1 /* $Id: main.c,v 1.270 2010/08/24 10:11:51 htrb Exp $ */
2 #define MAINPROGRAM
3 #include "fm.h"
4 #include <stdio.h>
5 #include <signal.h>
6 #include <setjmp.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #if defined(HAVE_WAITPID) || defined(HAVE_WAIT3)
12 #include <sys/wait.h>
13 #endif
14 #include <time.h>
15 #if defined(__CYGWIN__) && defined(USE_BINMODE_STREAM)
16 #include <io.h>
17 #endif
18 #include "terms.h"
19 #include "myctype.h"
20 #include "regex.h"
21 #ifdef USE_M17N
22 #include "wc.h"
23 #include "wtf.h"
24 #ifdef USE_UNICODE
25 #include "ucs.h"
26 #endif
27 #endif
28 #ifdef USE_MOUSE
29 #ifdef USE_GPM
30 #include <gpm.h>
31 #endif /* USE_GPM */
32 #if defined(USE_GPM) || defined(USE_SYSMOUSE)
33 extern int do_getch();
34 #define getch() do_getch()
35 #endif /* defined(USE_GPM) || defined(USE_SYSMOUSE) */
36 #endif
37
38 #ifdef __MINGW32_VERSION
39 #include <winsock.h>
40
41 WSADATA WSAData;
42 #endif
43
44 #define DSTR_LEN 256
45
46 Hist *LoadHist;
47 Hist *SaveHist;
48 Hist *URLHist;
49 Hist *ShellHist;
50 Hist *TextHist;
51
52 typedef struct _Event {
53 int cmd;
54 void *data;
55 struct _Event *next;
56 } Event;
57 static Event *CurrentEvent = NULL;
58 static Event *LastEvent = NULL;
59
60 #ifdef USE_ALARM
61 static AlarmEvent DefaultAlarm = {
62 0, AL_UNSET, FUNCNAME_nulcmd, NULL
63 };
64 static AlarmEvent *CurrentAlarm = &DefaultAlarm;
65 static MySignalHandler SigAlarm(SIGNAL_ARG);
66 #endif
67
68 #ifdef SIGWINCH
69 static int need_resize_screen = FALSE;
70 static MySignalHandler resize_hook(SIGNAL_ARG);
71 static void resize_screen(void);
72 #endif
73
74 #ifdef SIGPIPE
75 static MySignalHandler SigPipe(SIGNAL_ARG);
76 #endif
77
78 #ifdef USE_MARK
79 static char *MarkString = NULL;
80 #endif
81 static char *SearchString = NULL;
82 int (*searchRoutine) (Buffer *, char *);
83
84 #ifndef __MINGW32_VERSION
85 JMP_BUF IntReturn;
86 #else
87 _JBTYPE IntReturn[_JBLEN];
88 #endif /* __MINGW32_VERSION */
89
90 static void delBuffer(Buffer *buf);
91 static void cmd_loadfile(char *path);
92 static void cmd_loadURL(char *url, ParsedURL *current, char *referer,
93 FormList *request);
94 static void cmd_loadBuffer(Buffer *buf, int prop, int linkid);
95 static void keyPressEventProc(int c);
96 int show_params_p = 0;
97 void show_params(FILE * fp);
98
99 static char *getCurWord(Buffer *buf, int *spos, int *epos);
100
101 static int display_ok = FALSE;
102 static void do_dump(Buffer *);
103 int prec_num = 0;
104 int prev_key = -1;
105 int on_target = 1;
106 static int add_download_list = FALSE;
107
108 void set_buffer_environ(Buffer *);
109 static void save_buffer_position(Buffer *buf);
110
111 static void _followForm(int);
112 static void _goLine(char *);
113 static void _newT(void);
114 static void followTab(TabBuffer * tab);
115 static void moveTab(TabBuffer * t, TabBuffer * t2, int right);
116 static void _nextA(int);
117 static void _prevA(int);
118 static int check_target = TRUE;
119 #define PREC_NUM (prec_num ? prec_num : 1)
120 #define PREC_LIMIT 10000
121 static int searchKeyNum(void);
122
123 #define help() fusage(stdout, 0)
124 #define usage() fusage(stderr, 1)
125
126 int enable_inline_image;
127
128 static void
fversion(FILE * f)129 fversion(FILE * f)
130 {
131 fprintf(f, "w3m version %s, options %s\n", w3m_version,
132 #if LANG == JA
133 "lang=ja"
134 #else
135 "lang=en"
136 #endif
137 #ifdef USE_M17N
138 ",m17n"
139 #endif
140 #ifdef USE_IMAGE
141 ",image"
142 #endif
143 #ifdef USE_COLOR
144 ",color"
145 #ifdef USE_ANSI_COLOR
146 ",ansi-color"
147 #endif
148 #endif
149 #ifdef USE_MOUSE
150 ",mouse"
151 #ifdef USE_GPM
152 ",gpm"
153 #endif
154 #ifdef USE_SYSMOUSE
155 ",sysmouse"
156 #endif
157 #endif
158 #ifdef USE_MENU
159 ",menu"
160 #endif
161 #ifdef USE_COOKIE
162 ",cookie"
163 #endif
164 #ifdef USE_SSL
165 ",ssl"
166 #ifdef USE_SSL_VERIFY
167 ",ssl-verify"
168 #endif
169 #endif
170 #ifdef USE_EXTERNAL_URI_LOADER
171 ",external-uri-loader"
172 #endif
173 #ifdef USE_W3MMAILER
174 ",w3mmailer"
175 #endif
176 #ifdef USE_NNTP
177 ",nntp"
178 #endif
179 #ifdef USE_GOPHER
180 ",gopher"
181 #endif
182 #ifdef INET6
183 ",ipv6"
184 #endif
185 #ifdef USE_ALARM
186 ",alarm"
187 #endif
188 #ifdef USE_MARK
189 ",mark"
190 #endif
191 #ifdef USE_MIGEMO
192 ",migemo"
193 #endif
194 );
195 }
196
197 static void
fusage(FILE * f,int err)198 fusage(FILE * f, int err)
199 {
200 fversion(f);
201 /* FIXME: gettextize? */
202 fprintf(f, "usage: w3m [options] [URL or filename]\noptions:\n");
203 fprintf(f, " -t tab set tab width\n");
204 fprintf(f, " -r ignore backspace effect\n");
205 fprintf(f, " -l line # of preserved line (default 10000)\n");
206 #ifdef USE_M17N
207 fprintf(f, " -I charset document charset\n");
208 fprintf(f, " -O charset display/output charset\n");
209 #if 0 /* use -O{s|j|e} instead */
210 fprintf(f, " -e EUC-JP\n");
211 fprintf(f, " -s Shift_JIS\n");
212 fprintf(f, " -j JIS\n");
213 #endif
214 #endif
215 fprintf(f, " -B load bookmark\n");
216 fprintf(f, " -bookmark file specify bookmark file\n");
217 fprintf(f, " -T type specify content-type\n");
218 fprintf(f, " -m internet message mode\n");
219 fprintf(f, " -v visual startup mode\n");
220 #ifdef USE_COLOR
221 fprintf(f, " -M monochrome display\n");
222 #endif /* USE_COLOR */
223 fprintf(f,
224 " -N open URL of command line on each new tab\n");
225 fprintf(f, " -F automatically render frames\n");
226 fprintf(f,
227 " -cols width specify column width (used with -dump)\n");
228 fprintf(f,
229 " -ppc count specify the number of pixels per character (4.0...32.0)\n");
230 #ifdef USE_IMAGE
231 fprintf(f,
232 " -ppl count specify the number of pixels per line (4.0...64.0)\n");
233 #endif
234 fprintf(f, " -dump dump formatted page into stdout\n");
235 fprintf(f,
236 " -dump_head dump response of HEAD request into stdout\n");
237 fprintf(f, " -dump_source dump page source into stdout\n");
238 fprintf(f, " -dump_both dump HEAD and source into stdout\n");
239 fprintf(f,
240 " -dump_extra dump HEAD, source, and extra information into stdout\n");
241 fprintf(f, " -post file use POST method with file content\n");
242 fprintf(f, " -header string insert string as a header\n");
243 fprintf(f, " +<num> goto <num> line\n");
244 fprintf(f, " -num show line number\n");
245 fprintf(f, " -no-proxy don't use proxy\n");
246 #ifdef INET6
247 fprintf(f, " -4 IPv4 only (-o dns_order=4)\n");
248 fprintf(f, " -6 IPv6 only (-o dns_order=6)\n");
249 #endif
250 #ifdef USE_SSL
251 fprintf(f, " -insecure use insecure SSL config options\n");
252 #endif
253 #ifdef USE_MOUSE
254 fprintf(f, " -no-mouse don't use mouse\n");
255 #endif /* USE_MOUSE */
256 #ifdef USE_COOKIE
257 fprintf(f,
258 " -cookie use cookie (-no-cookie: don't use cookie)\n");
259 #endif /* USE_COOKIE */
260 fprintf(f, " -graph use DEC special graphics for border of table and menu\n");
261 fprintf(f, " -no-graph use ASCII character for border of table and menu\n");
262 #if 1 /* pager requires -s */
263 fprintf(f, " -s squeeze multiple blank lines\n");
264 #else
265 fprintf(f, " -S squeeze multiple blank lines\n");
266 #endif
267 fprintf(f, " -W toggle search wrap mode\n");
268 fprintf(f, " -X don't use termcap init/deinit\n");
269 fprintf(f,
270 " -title[=TERM] set buffer name to terminal title string\n");
271 fprintf(f, " -o opt=value assign value to config option\n");
272 fprintf(f, " -show-option print all config options\n");
273 fprintf(f, " -config file specify config file\n");
274 fprintf(f, " -debug use debug mode (only for debugging)\n");
275 fprintf(f, " -reqlog write request logfile\n");
276 fprintf(f, " -help print this usage message\n");
277 fprintf(f, " -version print w3m version\n");
278 if (show_params_p)
279 show_params(f);
280 exit(err);
281 }
282
283 #ifdef USE_M17N
284 #ifdef __EMX__
285 static char *getCodePage(void);
286 #endif
287 #endif
288
289 static GC_warn_proc orig_GC_warn_proc = NULL;
290 #define GC_WARN_KEEP_MAX (20)
291
292 static void
wrap_GC_warn_proc(char * msg,GC_word arg)293 wrap_GC_warn_proc(char *msg, GC_word arg)
294 {
295 if (fmInitialized) {
296 /* *INDENT-OFF* */
297 static struct {
298 char *msg;
299 GC_word arg;
300 } msg_ring[GC_WARN_KEEP_MAX];
301 /* *INDENT-ON* */
302 static int i = 0;
303 static int n = 0;
304 static int lock = 0;
305 int j;
306
307 j = (i + n) % (sizeof(msg_ring) / sizeof(msg_ring[0]));
308 msg_ring[j].msg = msg;
309 msg_ring[j].arg = arg;
310
311 if (n < sizeof(msg_ring) / sizeof(msg_ring[0]))
312 ++n;
313 else
314 ++i;
315
316 if (!lock) {
317 lock = 1;
318
319 for (; n > 0; --n, ++i) {
320 i %= sizeof(msg_ring) / sizeof(msg_ring[0]);
321
322 printf(msg_ring[i].msg, (unsigned long)msg_ring[i].arg);
323 sleep_till_anykey(1, 1);
324 }
325
326 lock = 0;
327 }
328 }
329 else if (orig_GC_warn_proc)
330 orig_GC_warn_proc(msg, arg);
331 else
332 fprintf(stderr, msg, (unsigned long)arg);
333 }
334
335 #ifdef SIGCHLD
336 static void
sig_chld(int signo)337 sig_chld(int signo)
338 {
339 int p_stat;
340 pid_t pid;
341
342 #ifdef HAVE_WAITPID
343 while ((pid = waitpid(-1, &p_stat, WNOHANG)) > 0)
344 #elif HAVE_WAIT3
345 while ((pid = wait3(&p_stat, WNOHANG, NULL)) > 0)
346 #else
347 if ((pid = wait(&p_stat)) > 0)
348 #endif
349 {
350 DownloadList *d;
351
352 if (WIFEXITED(p_stat)) {
353 for (d = FirstDL; d != NULL; d = d->next) {
354 if (d->pid == pid) {
355 d->err = WEXITSTATUS(p_stat);
356 break;
357 }
358 }
359 }
360 }
361 mySignal(SIGCHLD, sig_chld);
362 return;
363 }
364 #endif
365
366 Str
make_optional_header_string(char * s)367 make_optional_header_string(char *s)
368 {
369 char *p;
370 Str hs;
371
372 if (strchr(s, '\n') || strchr(s, '\r'))
373 return NULL;
374 for (p = s; *p && *p != ':'; p++) ;
375 if (*p != ':' || p == s)
376 return NULL;
377 hs = Strnew_size(strlen(s) + 3);
378 Strcopy_charp_n(hs, s, p - s);
379 if (!Strcasecmp_charp(hs, "content-type"))
380 override_content_type = TRUE;
381 if (!Strcasecmp_charp(hs, "user-agent"))
382 override_user_agent = TRUE;
383 Strcat_charp(hs, ": ");
384 if (*(++p)) { /* not null header */
385 SKIP_BLANKS(p); /* skip white spaces */
386 Strcat_charp(hs, p);
387 }
388 Strcat_charp(hs, "\r\n");
389 return hs;
390 }
391
392 static void *
die_oom(size_t bytes)393 die_oom(size_t bytes)
394 {
395 fprintf(stderr, "Out of memory: %lu bytes unavailable!\n", (unsigned long)bytes);
396 exit(1);
397 }
398
399 int
main(int argc,char ** argv,char ** envp)400 main(int argc, char **argv, char **envp)
401 {
402 Buffer *newbuf = NULL;
403 char *p;
404 int c, i;
405 InputStream redin;
406 char *line_str = NULL;
407 char **load_argv;
408 FormList *request;
409 int load_argc = 0;
410 int load_bookmark = FALSE;
411 int visual_start = FALSE;
412 int open_new_tab = FALSE;
413 char search_header = FALSE;
414 char *default_type = NULL;
415 char *post_file = NULL;
416 Str err_msg;
417 #ifdef USE_M17N
418 char *Locale = NULL;
419 wc_uint8 auto_detect;
420 #ifdef __EMX__
421 wc_ces CodePage;
422 #endif
423 #endif
424 #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE)
425 char **getimage_args = NULL;
426 #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */
427 if (!getenv("GC_LARGE_ALLOC_WARN_INTERVAL"))
428 set_environ("GC_LARGE_ALLOC_WARN_INTERVAL", "30000");
429 GC_INIT();
430 #if (GC_VERSION_MAJOR>7) || ((GC_VERSION_MAJOR==7) && (GC_VERSION_MINOR>=2))
431 GC_set_oom_fn(die_oom);
432 #else
433 GC_oom_fn = die_oom;
434 #endif
435 #if defined(ENABLE_NLS) || (defined(USE_M17N) && defined(HAVE_LANGINFO_CODESET))
436 setlocale(LC_ALL, "");
437 #endif
438 #ifdef ENABLE_NLS
439 bindtextdomain(PACKAGE, LOCALEDIR);
440 textdomain(PACKAGE);
441 #endif
442
443 NO_proxy_domains = newTextList();
444 fileToDelete = newTextList();
445
446 load_argv = New_N(char *, argc - 1);
447 load_argc = 0;
448
449 CurrentDir = currentdir();
450 CurrentPid = (int)getpid();
451 #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE)
452 if (argv[0] && *argv[0])
453 MyProgramName = argv[0];
454 #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */
455 BookmarkFile = NULL;
456 config_file = NULL;
457
458 {
459 char hostname[HOST_NAME_MAX + 2];
460 if (gethostname(hostname, HOST_NAME_MAX + 2) == 0) {
461 size_t hostname_len;
462 /* Don't use hostname if it is truncated. */
463 hostname[HOST_NAME_MAX + 1] = '\0';
464 hostname_len = strlen(hostname);
465 if (hostname_len <= HOST_NAME_MAX && hostname_len < STR_SIZE_MAX)
466 HostName = allocStr(hostname, (int)hostname_len);
467 }
468 }
469
470 /* argument search 1 */
471 for (i = 1; i < argc; i++) {
472 if (*argv[i] == '-') {
473 if (!strcmp("-config", argv[i])) {
474 argv[i] = "-dummy";
475 if (++i >= argc)
476 usage();
477 config_file = argv[i];
478 argv[i] = "-dummy";
479 }
480 else if (!strcmp("-h", argv[i]) || !strcmp("-help", argv[i]))
481 help();
482 else if (!strcmp("-V", argv[i]) || !strcmp("-version", argv[i])) {
483 fversion(stdout);
484 exit(0);
485 }
486 }
487 }
488
489 #ifdef USE_M17N
490 if (non_null(Locale = getenv("LC_ALL")) ||
491 non_null(Locale = getenv("LC_CTYPE")) ||
492 non_null(Locale = getenv("LANG"))) {
493 DisplayCharset = wc_guess_locale_charset(Locale, DisplayCharset);
494 DocumentCharset = wc_guess_locale_charset(Locale, DocumentCharset);
495 SystemCharset = wc_guess_locale_charset(Locale, SystemCharset);
496 }
497 #ifdef __EMX__
498 CodePage = wc_guess_charset(getCodePage(), 0);
499 if (CodePage)
500 DisplayCharset = DocumentCharset = SystemCharset = CodePage;
501 #endif
502 #endif
503
504 /* initializations */
505 init_rc();
506
507 LoadHist = newHist();
508 SaveHist = newHist();
509 ShellHist = newHist();
510 TextHist = newHist();
511 URLHist = newHist();
512
513 #ifdef USE_M17N
514 if (FollowLocale && Locale) {
515 DisplayCharset = wc_guess_locale_charset(Locale, DisplayCharset);
516 SystemCharset = wc_guess_locale_charset(Locale, SystemCharset);
517 }
518 auto_detect = WcOption.auto_detect;
519 BookmarkCharset = DocumentCharset;
520 #endif
521
522 if (!non_null(HTTP_proxy) &&
523 ((p = getenv("HTTP_PROXY")) ||
524 (p = getenv("http_proxy")) || (p = getenv("HTTP_proxy"))))
525 HTTP_proxy = p;
526 #ifdef USE_SSL
527 if (!non_null(HTTPS_proxy) &&
528 ((p = getenv("HTTPS_PROXY")) ||
529 (p = getenv("https_proxy")) || (p = getenv("HTTPS_proxy"))))
530 HTTPS_proxy = p;
531 if (HTTPS_proxy == NULL && non_null(HTTP_proxy))
532 HTTPS_proxy = HTTP_proxy;
533 #endif /* USE_SSL */
534 #ifdef USE_GOPHER
535 if (!non_null(GOPHER_proxy) &&
536 ((p = getenv("GOPHER_PROXY")) ||
537 (p = getenv("gopher_proxy")) || (p = getenv("GOPHER_proxy"))))
538 GOPHER_proxy = p;
539 #endif /* USE_GOPHER */
540 if (!non_null(FTP_proxy) &&
541 ((p = getenv("FTP_PROXY")) ||
542 (p = getenv("ftp_proxy")) || (p = getenv("FTP_proxy"))))
543 FTP_proxy = p;
544 if (!non_null(NO_proxy) &&
545 ((p = getenv("NO_PROXY")) ||
546 (p = getenv("no_proxy")) || (p = getenv("NO_proxy"))))
547 NO_proxy = p;
548 #ifdef USE_NNTP
549 if (!non_null(NNTP_server) && (p = getenv("NNTPSERVER")) != NULL)
550 NNTP_server = p;
551 if (!non_null(NNTP_mode) && (p = getenv("NNTPMODE")) != NULL)
552 NNTP_mode = p;
553 #endif
554
555 if (!non_null(Editor) && (p = getenv("EDITOR")) != NULL)
556 Editor = p;
557 if (!non_null(Mailer) && (p = getenv("MAILER")) != NULL)
558 Mailer = p;
559
560 /* argument search 2 */
561 i = 1;
562 while (i < argc) {
563 if (*argv[i] == '-') {
564 if (!strcmp("-t", argv[i])) {
565 if (++i >= argc)
566 usage();
567 if (atoi(argv[i]) > 0)
568 Tabstop = atoi(argv[i]);
569 }
570 else if (!strcmp("-r", argv[i]))
571 ShowEffect = FALSE;
572 else if (!strcmp("-l", argv[i])) {
573 if (++i >= argc)
574 usage();
575 if (atoi(argv[i]) > 0)
576 PagerMax = atoi(argv[i]);
577 }
578 #ifdef USE_M17N
579 #if 0 /* use -O{s|j|e} instead */
580 else if (!strcmp("-s", argv[i]))
581 DisplayCharset = WC_CES_SHIFT_JIS;
582 else if (!strcmp("-j", argv[i]))
583 DisplayCharset = WC_CES_ISO_2022_JP;
584 else if (!strcmp("-e", argv[i]))
585 DisplayCharset = WC_CES_EUC_JP;
586 #endif
587 else if (!strncmp("-I", argv[i], 2)) {
588 if (argv[i][2] != '\0')
589 p = argv[i] + 2;
590 else {
591 if (++i >= argc)
592 usage();
593 p = argv[i];
594 }
595 DocumentCharset = wc_guess_charset_short(p, DocumentCharset);
596 WcOption.auto_detect = WC_OPT_DETECT_OFF;
597 UseContentCharset = FALSE;
598 }
599 else if (!strncmp("-O", argv[i], 2)) {
600 if (argv[i][2] != '\0')
601 p = argv[i] + 2;
602 else {
603 if (++i >= argc)
604 usage();
605 p = argv[i];
606 }
607 DisplayCharset = wc_guess_charset_short(p, DisplayCharset);
608 }
609 #endif
610 else if (!strcmp("-graph", argv[i]))
611 UseGraphicChar = GRAPHIC_CHAR_DEC;
612 else if (!strcmp("-no-graph", argv[i]))
613 UseGraphicChar = GRAPHIC_CHAR_ASCII;
614 else if (!strcmp("-T", argv[i])) {
615 if (++i >= argc)
616 usage();
617 DefaultType = default_type = argv[i];
618 }
619 else if (!strcmp("-m", argv[i]))
620 SearchHeader = search_header = TRUE;
621 else if (!strcmp("-v", argv[i]))
622 visual_start = TRUE;
623 else if (!strcmp("-N", argv[i]))
624 open_new_tab = TRUE;
625 #ifdef USE_COLOR
626 else if (!strcmp("-M", argv[i]))
627 useColor = FALSE;
628 #endif /* USE_COLOR */
629 else if (!strcmp("-B", argv[i]))
630 load_bookmark = TRUE;
631 else if (!strcmp("-bookmark", argv[i])) {
632 if (++i >= argc)
633 usage();
634 BookmarkFile = argv[i];
635 if (BookmarkFile[0] != '~' && BookmarkFile[0] != '/') {
636 Str tmp = Strnew_charp(CurrentDir);
637 if (Strlastchar(tmp) != '/')
638 Strcat_char(tmp, '/');
639 Strcat_charp(tmp, BookmarkFile);
640 BookmarkFile = cleanupName(tmp->ptr);
641 }
642 }
643 else if (!strcmp("-F", argv[i]))
644 RenderFrame = TRUE;
645 else if (!strcmp("-W", argv[i])) {
646 if (WrapDefault)
647 WrapDefault = FALSE;
648 else
649 WrapDefault = TRUE;
650 }
651 else if (!strcmp("-dump", argv[i]))
652 w3m_dump = DUMP_BUFFER;
653 else if (!strcmp("-dump_source", argv[i]))
654 w3m_dump = DUMP_SOURCE;
655 else if (!strcmp("-dump_head", argv[i]))
656 w3m_dump = DUMP_HEAD;
657 else if (!strcmp("-dump_both", argv[i]))
658 w3m_dump = (DUMP_HEAD | DUMP_SOURCE);
659 else if (!strcmp("-dump_extra", argv[i]))
660 w3m_dump = (DUMP_HEAD | DUMP_SOURCE | DUMP_EXTRA);
661 else if (!strcmp("-halfdump", argv[i]))
662 w3m_dump = DUMP_HALFDUMP;
663 else if (!strcmp("-halfload", argv[i])) {
664 w3m_dump = 0;
665 w3m_halfload = TRUE;
666 DefaultType = default_type = "text/html";
667 }
668 else if (!strcmp("-backend", argv[i])) {
669 w3m_backend = TRUE;
670 }
671 else if (!strcmp("-backend_batch", argv[i])) {
672 w3m_backend = TRUE;
673 if (++i >= argc)
674 usage();
675 if (!backend_batch_commands)
676 backend_batch_commands = newTextList();
677 pushText(backend_batch_commands, argv[i]);
678 }
679 else if (!strcmp("-cols", argv[i])) {
680 if (++i >= argc)
681 usage();
682 COLS = atoi(argv[i]);
683 if (COLS > MAXIMUM_COLS) {
684 COLS = MAXIMUM_COLS;
685 }
686 }
687 else if (!strcmp("-ppc", argv[i])) {
688 double ppc;
689 if (++i >= argc)
690 usage();
691 ppc = atof(argv[i]);
692 if (ppc >= MINIMUM_PIXEL_PER_CHAR &&
693 ppc <= MAXIMUM_PIXEL_PER_CHAR) {
694 pixel_per_char = ppc;
695 set_pixel_per_char = TRUE;
696 }
697 }
698 #ifdef USE_IMAGE
699 else if (!strcmp("-ppl", argv[i])) {
700 double ppc;
701 if (++i >= argc)
702 usage();
703 ppc = atof(argv[i]);
704 if (ppc >= MINIMUM_PIXEL_PER_CHAR &&
705 ppc <= MAXIMUM_PIXEL_PER_CHAR * 2) {
706 pixel_per_line = ppc;
707 set_pixel_per_line = TRUE;
708 }
709 }
710 #endif
711 else if (!strcmp("-ri", argv[i])) {
712 enable_inline_image = INLINE_IMG_OSC5379;
713 }
714 else if (!strcmp("-sixel", argv[i])) {
715 enable_inline_image = INLINE_IMG_SIXEL;
716 }
717 else if (!strcmp("-num", argv[i]))
718 showLineNum = TRUE;
719 else if (!strcmp("-no-proxy", argv[i]))
720 use_proxy = FALSE;
721 #ifdef INET6
722 else if (!strcmp("-4", argv[i]) || !strcmp("-6", argv[i]))
723 set_param_option(Sprintf("dns_order=%c", argv[i][1])->ptr);
724 #endif
725 else if (!strcmp("-post", argv[i])) {
726 if (++i >= argc)
727 usage();
728 post_file = argv[i];
729 }
730 else if (!strcmp("-header", argv[i])) {
731 Str hs;
732 if (++i >= argc)
733 usage();
734 if ((hs = make_optional_header_string(argv[i])) != NULL) {
735 if (header_string == NULL)
736 header_string = hs;
737 else
738 Strcat(header_string, hs);
739 }
740 while (argv[i][0]) {
741 argv[i][0] = '\0';
742 argv[i]++;
743 }
744 }
745 #ifdef USE_MOUSE
746 else if (!strcmp("-no-mouse", argv[i])) {
747 use_mouse = FALSE;
748 }
749 #endif /* USE_MOUSE */
750 #ifdef USE_COOKIE
751 else if (!strcmp("-no-cookie", argv[i])) {
752 use_cookie = FALSE;
753 accept_cookie = FALSE;
754 }
755 else if (!strcmp("-cookie", argv[i])) {
756 use_cookie = TRUE;
757 accept_cookie = TRUE;
758 }
759 #endif /* USE_COOKIE */
760 #if 1 /* pager requires -s */
761 else if (!strcmp("-s", argv[i]))
762 #else
763 else if (!strcmp("-S", argv[i]))
764 #endif
765 squeezeBlankLine = TRUE;
766 else if (!strcmp("-X", argv[i]))
767 Do_not_use_ti_te = TRUE;
768 else if (!strcmp("-title", argv[i]))
769 displayTitleTerm = getenv("TERM");
770 else if (!strncmp("-title=", argv[i], 7))
771 displayTitleTerm = argv[i] + 7;
772 #ifdef USE_SSL
773 else if (!strcmp("-insecure", argv[i])) {
774 #ifdef OPENSSL_TLS_SECURITY_LEVEL
775 set_param_option("ssl_cipher=ALL:eNULL:@SECLEVEL=0");
776 #else
777 set_param_option("ssl_cipher=ALL:eNULL");
778 #endif
779 #ifdef SSL_CTX_set_min_proto_version
780 set_param_option("ssl_min_version=all");
781 #endif
782 set_param_option("ssl_forbid_method=");
783 #ifdef USE_SSL_VERIFY
784 set_param_option("ssl_verify_server=0");
785 #endif
786 }
787 #endif /* USE_SSL */
788 else if (!strcmp("-o", argv[i]) ||
789 !strcmp("-show-option", argv[i])) {
790 if (!strcmp("-show-option", argv[i]) || ++i >= argc ||
791 !strcmp(argv[i], "?")) {
792 show_params(stdout);
793 exit(0);
794 }
795 if (!set_param_option(argv[i])) {
796 /* option set failed */
797 /* FIXME: gettextize? */
798 fprintf(stderr, "%s: bad option\n", argv[i]);
799 show_params_p = 1;
800 usage();
801 }
802 }
803 else if (!strcmp("-", argv[i]) || !strcmp("-dummy", argv[i])) {
804 /* do nothing */
805 }
806 else if (!strcmp("-debug", argv[i])) {
807 w3m_debug = TRUE;
808 }
809 else if (!strcmp("-reqlog",argv[i])) {
810 w3m_reqlog=rcFile("request.log");
811 }
812 #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE)
813 else if (!strcmp("-$$getimage", argv[i])) {
814 ++i;
815 getimage_args = argv + i;
816 i += 4;
817 if (i > argc)
818 usage();
819 }
820 #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */
821 else {
822 usage();
823 }
824 }
825 else if (*argv[i] == '+') {
826 line_str = argv[i] + 1;
827 }
828 else {
829 load_argv[load_argc++] = argv[i];
830 }
831 i++;
832 }
833
834 #ifdef __WATT32__
835 if (w3m_debug)
836 dbug_init();
837 sock_init();
838 #endif
839
840 #ifdef __MINGW32_VERSION
841 {
842 int err;
843 WORD wVerReq;
844
845 wVerReq = MAKEWORD(1, 1);
846
847 err = WSAStartup(wVerReq, &WSAData);
848 if (err != 0)
849 {
850 fprintf(stderr, "Can't find winsock\n");
851 return 1;
852 }
853 _fmode = _O_BINARY;
854 }
855 #endif
856
857 FirstTab = NULL;
858 LastTab = NULL;
859 nTab = 0;
860 CurrentTab = NULL;
861 CurrentKey = -1;
862 if (BookmarkFile == NULL)
863 BookmarkFile = rcFile(BOOKMARK);
864
865 if (!isatty(1) && !w3m_dump) {
866 /* redirected output */
867 w3m_dump = DUMP_BUFFER;
868 }
869 if (w3m_dump) {
870 if (COLS == 0)
871 COLS = DEFAULT_COLS;
872 }
873
874 #ifdef USE_BINMODE_STREAM
875 setmode(fileno(stdout), O_BINARY);
876 #endif
877 if (!w3m_dump && !w3m_backend) {
878 fmInit();
879 #ifdef SIGWINCH
880 mySignal(SIGWINCH, resize_hook);
881 #else /* not SIGWINCH */
882 setlinescols();
883 setupscreen();
884 #endif /* not SIGWINCH */
885 }
886 #ifdef USE_IMAGE
887 else if (w3m_halfdump && displayImage)
888 activeImage = TRUE;
889 #endif
890
891 sync_with_option();
892 #ifdef USE_COOKIE
893 initCookie();
894 #endif /* USE_COOKIE */
895 #ifdef USE_HISTORY
896 if (UseHistory)
897 loadHistory(URLHist);
898 #endif /* not USE_HISTORY */
899
900 #ifdef USE_M17N
901 wtf_init(DocumentCharset, DisplayCharset);
902 /* if (w3m_dump)
903 * WcOption.pre_conv = WC_TRUE;
904 */
905 #endif
906
907 if (w3m_backend)
908 backend();
909 #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE)
910 if (getimage_args) {
911 char *image_url = conv_from_system(getimage_args[0]);
912 char *base_url = conv_from_system(getimage_args[1]);
913 ParsedURL base_pu;
914
915 parseURL2(base_url, &base_pu, NULL);
916 image_source = getimage_args[2];
917 newbuf = loadGeneralFile(image_url, &base_pu, NULL, 0, NULL);
918 if (!newbuf || !newbuf->real_type ||
919 strncasecmp(newbuf->real_type, "image/", 6))
920 unlink(getimage_args[2]);
921 #if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT)
922 symlink(getimage_args[2], getimage_args[3]);
923 #else
924 {
925 FILE *f = fopen(getimage_args[3], "w");
926 if (f)
927 fclose(f);
928 }
929 #endif
930 w3m_exit(0);
931 }
932 #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */
933
934 if (w3m_dump)
935 mySignal(SIGINT, SIG_IGN);
936 #ifdef SIGCHLD
937 mySignal(SIGCHLD, sig_chld);
938 #endif
939 #ifdef SIGPIPE
940 mySignal(SIGPIPE, SigPipe);
941 #endif
942
943 #if (GC_VERSION_MAJOR>7) || ((GC_VERSION_MAJOR==7) && (GC_VERSION_MINOR>=2))
944 orig_GC_warn_proc = GC_get_warn_proc();
945 GC_set_warn_proc(wrap_GC_warn_proc);
946 #else
947 orig_GC_warn_proc = GC_set_warn_proc(wrap_GC_warn_proc);
948 #endif
949 err_msg = Strnew();
950 if (load_argc == 0) {
951 /* no URL specified */
952 if (!isatty(0)) {
953 redin = newFileStream(fdopen(dup(0), "rb"), (void (*)())pclose);
954 newbuf = openGeneralPagerBuffer(redin);
955 dup2(1, 0);
956 }
957 else if (load_bookmark) {
958 newbuf = loadGeneralFile(BookmarkFile, NULL, NO_REFERER, 0, NULL);
959 if (newbuf == NULL)
960 Strcat_charp(err_msg, "w3m: Can't load bookmark.\n");
961 }
962 else if (visual_start) {
963 /* FIXME: gettextize? */
964 Str s_page;
965 s_page =
966 Strnew_charp
967 ("<title>W3M startup page</title><center><b>Welcome to ");
968 Strcat_charp(s_page, "<a href='http://w3m.sourceforge.net/'>");
969 Strcat_m_charp(s_page,
970 "w3m</a>!<p><p>This is w3m version ",
971 w3m_version,
972 "<br>Written by <a href='mailto:aito@fw.ipsj.or.jp'>Akinori Ito</a>",
973 NULL);
974 newbuf = loadHTMLString(s_page);
975 if (newbuf == NULL)
976 Strcat_charp(err_msg, "w3m: Can't load string.\n");
977 else if (newbuf != NO_BUFFER)
978 newbuf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
979 }
980 else if ((p = getenv("HTTP_HOME")) != NULL ||
981 (p = getenv("WWW_HOME")) != NULL) {
982 newbuf = loadGeneralFile(p, NULL, NO_REFERER, 0, NULL);
983 if (newbuf == NULL)
984 Strcat(err_msg, Sprintf("w3m: Can't load %s.\n", p));
985 else if (newbuf != NO_BUFFER)
986 pushHashHist(URLHist, parsedURL2Str(&newbuf->currentURL)->ptr);
987 }
988 else {
989 if (fmInitialized)
990 fmTerm();
991 usage();
992 }
993 if (newbuf == NULL) {
994 if (fmInitialized)
995 fmTerm();
996 if (err_msg->length)
997 fprintf(stderr, "%s", err_msg->ptr);
998 w3m_exit(2);
999 }
1000 i = -1;
1001 }
1002 else {
1003 i = 0;
1004 }
1005 for (; i < load_argc; i++) {
1006 if (i >= 0) {
1007 SearchHeader = search_header;
1008 DefaultType = default_type;
1009 char *url;
1010
1011 url = load_argv[i];
1012 if (getURLScheme(&url) == SCM_MISSING && !ArgvIsURL)
1013 url = file_to_url(load_argv[i]);
1014 else
1015 url = url_encode(conv_from_system(load_argv[i]), NULL, 0);
1016 if (w3m_dump == DUMP_HEAD) {
1017 request = New(FormList);
1018 request->method = FORM_METHOD_HEAD;
1019 newbuf = loadGeneralFile(url, NULL, NO_REFERER, 0, request);
1020 }
1021 else {
1022 if (post_file && i == 0) {
1023 FILE *fp;
1024 Str body;
1025 if (!strcmp(post_file, "-"))
1026 fp = stdin;
1027 else
1028 fp = fopen(post_file, "r");
1029 if (fp == NULL) {
1030 /* FIXME: gettextize? */
1031 Strcat(err_msg,
1032 Sprintf("w3m: Can't open %s.\n", post_file));
1033 continue;
1034 }
1035 body = Strfgetall(fp);
1036 if (fp != stdin)
1037 fclose(fp);
1038 request =
1039 newFormList(NULL, "post", NULL, NULL, NULL, NULL,
1040 NULL);
1041 request->body = body->ptr;
1042 request->boundary = NULL;
1043 request->length = body->length;
1044 }
1045 else {
1046 request = NULL;
1047 }
1048 newbuf = loadGeneralFile(url, NULL, NO_REFERER, 0, request);
1049 }
1050 if (newbuf == NULL) {
1051 /* FIXME: gettextize? */
1052 Strcat(err_msg,
1053 Sprintf("w3m: Can't load %s.\n", load_argv[i]));
1054 continue;
1055 }
1056 else if (newbuf == NO_BUFFER)
1057 continue;
1058 switch (newbuf->real_scheme) {
1059 case SCM_MAILTO:
1060 break;
1061 case SCM_LOCAL:
1062 case SCM_LOCAL_CGI:
1063 unshiftHist(LoadHist, url);
1064 default:
1065 pushHashHist(URLHist, parsedURL2Str(&newbuf->currentURL)->ptr);
1066 break;
1067 }
1068 }
1069 else if (newbuf == NO_BUFFER)
1070 continue;
1071 if (newbuf->pagerSource ||
1072 (newbuf->real_scheme == SCM_LOCAL && newbuf->header_source &&
1073 newbuf->currentURL.file && strcmp(newbuf->currentURL.file, "-")))
1074 newbuf->search_header = search_header;
1075 if (CurrentTab == NULL) {
1076 FirstTab = LastTab = CurrentTab = newTab();
1077 nTab = 1;
1078 Firstbuf = Currentbuf = newbuf;
1079 }
1080 else if (open_new_tab) {
1081 _newT();
1082 Currentbuf->nextBuffer = newbuf;
1083 delBuffer(Currentbuf);
1084 }
1085 else {
1086 Currentbuf->nextBuffer = newbuf;
1087 Currentbuf = newbuf;
1088 }
1089 if (!w3m_dump || w3m_dump == DUMP_BUFFER) {
1090 if (Currentbuf->frameset != NULL && RenderFrame)
1091 rFrame();
1092 }
1093 if (w3m_dump)
1094 do_dump(Currentbuf);
1095 else {
1096 Currentbuf = newbuf;
1097 #ifdef USE_BUFINFO
1098 saveBufferInfo();
1099 #endif
1100 }
1101 }
1102 if (w3m_dump) {
1103 if (err_msg->length)
1104 fprintf(stderr, "%s", err_msg->ptr);
1105 #ifdef USE_COOKIE
1106 save_cookies();
1107 #endif /* USE_COOKIE */
1108 w3m_exit(0);
1109 }
1110
1111 if (add_download_list) {
1112 add_download_list = FALSE;
1113 CurrentTab = LastTab;
1114 if (!FirstTab) {
1115 FirstTab = LastTab = CurrentTab = newTab();
1116 nTab = 1;
1117 }
1118 if (!Firstbuf || Firstbuf == NO_BUFFER) {
1119 Firstbuf = Currentbuf = newBuffer(INIT_BUFFER_WIDTH);
1120 Currentbuf->bufferprop = BP_INTERNAL | BP_NO_URL;
1121 Currentbuf->buffername = DOWNLOAD_LIST_TITLE;
1122 }
1123 else
1124 Currentbuf = Firstbuf;
1125 ldDL();
1126 }
1127 else
1128 CurrentTab = FirstTab;
1129 if (!FirstTab || !Firstbuf || Firstbuf == NO_BUFFER) {
1130 if (newbuf == NO_BUFFER) {
1131 if (fmInitialized)
1132 /* FIXME: gettextize? */
1133 inputChar("Hit any key to quit w3m:");
1134 }
1135 if (fmInitialized)
1136 fmTerm();
1137 if (err_msg->length)
1138 fprintf(stderr, "%s", err_msg->ptr);
1139 if (newbuf == NO_BUFFER) {
1140 #ifdef USE_COOKIE
1141 save_cookies();
1142 #endif /* USE_COOKIE */
1143 if (!err_msg->length)
1144 w3m_exit(0);
1145 }
1146 w3m_exit(2);
1147 }
1148 if (err_msg->length)
1149 disp_message_nsec(err_msg->ptr, FALSE, 1, TRUE, FALSE);
1150
1151 SearchHeader = FALSE;
1152 DefaultType = NULL;
1153 #ifdef USE_M17N
1154 UseContentCharset = TRUE;
1155 WcOption.auto_detect = auto_detect;
1156 #endif
1157
1158 Currentbuf = Firstbuf;
1159 displayBuffer(Currentbuf, B_FORCE_REDRAW);
1160 if (line_str) {
1161 _goLine(line_str);
1162 }
1163 for (;;) {
1164 if (add_download_list) {
1165 add_download_list = FALSE;
1166 ldDL();
1167 }
1168 if (Currentbuf->submit) {
1169 Anchor *a = Currentbuf->submit;
1170 Currentbuf->submit = NULL;
1171 gotoLine(Currentbuf, a->start.line);
1172 Currentbuf->pos = a->start.pos;
1173 _followForm(TRUE);
1174 continue;
1175 }
1176 /* event processing */
1177 if (CurrentEvent) {
1178 CurrentKey = -1;
1179 CurrentKeyData = NULL;
1180 CurrentCmdData = (char *)CurrentEvent->data;
1181 w3mFuncList[CurrentEvent->cmd].func();
1182 CurrentCmdData = NULL;
1183 CurrentEvent = CurrentEvent->next;
1184 continue;
1185 }
1186 /* get keypress event */
1187 #ifdef USE_ALARM
1188 if (Currentbuf->event) {
1189 if (Currentbuf->event->status != AL_UNSET) {
1190 CurrentAlarm = Currentbuf->event;
1191 if (CurrentAlarm->sec == 0) { /* refresh (0sec) */
1192 Currentbuf->event = NULL;
1193 CurrentKey = -1;
1194 CurrentKeyData = NULL;
1195 CurrentCmdData = (char *)CurrentAlarm->data;
1196 w3mFuncList[CurrentAlarm->cmd].func();
1197 CurrentCmdData = NULL;
1198 continue;
1199 }
1200 }
1201 else
1202 Currentbuf->event = NULL;
1203 }
1204 if (!Currentbuf->event)
1205 CurrentAlarm = &DefaultAlarm;
1206 #endif
1207 #ifdef USE_MOUSE
1208 mouse_action.in_action = FALSE;
1209 if (use_mouse)
1210 mouse_active();
1211 #endif /* USE_MOUSE */
1212 #ifdef USE_ALARM
1213 if (CurrentAlarm->sec > 0) {
1214 mySignal(SIGALRM, SigAlarm);
1215 alarm(CurrentAlarm->sec);
1216 }
1217 #endif
1218 #ifdef SIGWINCH
1219 mySignal(SIGWINCH, resize_hook);
1220 #endif
1221 #ifdef USE_IMAGE
1222 if (activeImage && displayImage && Currentbuf->img &&
1223 !Currentbuf->image_loaded) {
1224 do {
1225 #ifdef SIGWINCH
1226 if (need_resize_screen)
1227 resize_screen();
1228 #endif
1229 loadImage(Currentbuf, IMG_FLAG_NEXT);
1230 } while (sleep_till_anykey(1, 0) <= 0);
1231 }
1232 #ifdef SIGWINCH
1233 else
1234 #endif
1235 #endif
1236 #ifdef SIGWINCH
1237 {
1238 do {
1239 if (need_resize_screen)
1240 resize_screen();
1241 } while (sleep_till_anykey(1, 0) <= 0);
1242 }
1243 #endif
1244 c = getch();
1245 #ifdef USE_ALARM
1246 if (CurrentAlarm->sec > 0) {
1247 alarm(0);
1248 }
1249 #endif
1250 #ifdef USE_MOUSE
1251 if (use_mouse)
1252 mouse_inactive();
1253 #endif /* USE_MOUSE */
1254 if (IS_ASCII(c)) { /* Ascii */
1255 if (('0' <= c) && (c <= '9') &&
1256 (prec_num || (GlobalKeymap[c] == FUNCNAME_nulcmd))) {
1257 prec_num = prec_num * 10 + (int)(c - '0');
1258 if (prec_num > PREC_LIMIT)
1259 prec_num = PREC_LIMIT;
1260 }
1261 else {
1262 set_buffer_environ(Currentbuf);
1263 save_buffer_position(Currentbuf);
1264 keyPressEventProc((int)c);
1265 prec_num = 0;
1266 }
1267 }
1268 prev_key = CurrentKey;
1269 CurrentKey = -1;
1270 CurrentKeyData = NULL;
1271 }
1272 }
1273
1274 static void
keyPressEventProc(int c)1275 keyPressEventProc(int c)
1276 {
1277 CurrentKey = c;
1278 w3mFuncList[(int)GlobalKeymap[c]].func();
1279 }
1280
1281 void
pushEvent(int cmd,void * data)1282 pushEvent(int cmd, void *data)
1283 {
1284 Event *event;
1285
1286 event = New(Event);
1287 event->cmd = cmd;
1288 event->data = data;
1289 event->next = NULL;
1290 if (CurrentEvent)
1291 LastEvent->next = event;
1292 else
1293 CurrentEvent = event;
1294 LastEvent = event;
1295 }
1296
1297 static void
dump_source(Buffer * buf)1298 dump_source(Buffer *buf)
1299 {
1300 FILE *f;
1301 int c;
1302 if (buf->sourcefile == NULL)
1303 return;
1304 f = fopen(buf->sourcefile, "r");
1305 if (f == NULL)
1306 return;
1307 while ((c = fgetc(f)) != EOF) {
1308 putchar(c);
1309 }
1310 fclose(f);
1311 }
1312
1313 static void
dump_head(Buffer * buf)1314 dump_head(Buffer *buf)
1315 {
1316 TextListItem *ti;
1317
1318 if (buf->document_header == NULL) {
1319 if (w3m_dump & DUMP_EXTRA)
1320 printf("\n");
1321 return;
1322 }
1323 for (ti = buf->document_header->first; ti; ti = ti->next) {
1324 #ifdef USE_M17N
1325 printf("%s",
1326 wc_conv_strict(ti->ptr, InnerCharset,
1327 buf->document_charset)->ptr);
1328 #else
1329 printf("%s", ti->ptr);
1330 #endif
1331 }
1332 puts("");
1333 }
1334
1335 static void
dump_extra(Buffer * buf)1336 dump_extra(Buffer *buf)
1337 {
1338 printf("W3m-current-url: %s\n", parsedURL2Str(&buf->currentURL)->ptr);
1339 if (buf->baseURL)
1340 printf("W3m-base-url: %s\n", parsedURL2Str(buf->baseURL)->ptr);
1341 #ifdef USE_M17N
1342 printf("W3m-document-charset: %s\n",
1343 wc_ces_to_charset(buf->document_charset));
1344 #endif
1345 #ifdef USE_SSL
1346 if (buf->ssl_certificate) {
1347 Str tmp = Strnew();
1348 char *p;
1349 for (p = buf->ssl_certificate; *p; p++) {
1350 Strcat_char(tmp, *p);
1351 if (*p == '\n') {
1352 for (; *(p + 1) == '\n'; p++) ;
1353 if (*(p + 1))
1354 Strcat_char(tmp, '\t');
1355 }
1356 }
1357 if (Strlastchar(tmp) != '\n')
1358 Strcat_char(tmp, '\n');
1359 printf("W3m-ssl-certificate: %s", tmp->ptr);
1360 }
1361 #endif
1362 }
1363
1364 static int
cmp_anchor_hseq(const void * a,const void * b)1365 cmp_anchor_hseq(const void *a, const void *b)
1366 {
1367 return (*((const Anchor **) a))->hseq - (*((const Anchor **) b))->hseq;
1368 }
1369
1370 static void
do_dump(Buffer * buf)1371 do_dump(Buffer *buf)
1372 {
1373 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
1374
1375 prevtrap = mySignal(SIGINT, intTrap);
1376 if (SETJMP(IntReturn) != 0) {
1377 mySignal(SIGINT, prevtrap);
1378 return;
1379 }
1380 if (w3m_dump & DUMP_EXTRA)
1381 dump_extra(buf);
1382 if (w3m_dump & DUMP_HEAD)
1383 dump_head(buf);
1384 if (w3m_dump & DUMP_SOURCE)
1385 dump_source(buf);
1386 if (w3m_dump == DUMP_BUFFER) {
1387 int i;
1388 saveBuffer(buf, stdout, FALSE);
1389 if (displayLinkNumber && buf->href) {
1390 int nanchor = buf->href->nanchor;
1391 printf("\nReferences:\n\n");
1392 Anchor **in_order = New_N(Anchor *, buf->href->nanchor);
1393 for (i = 0; i < nanchor; i++)
1394 in_order[i] = buf->href->anchors + i;
1395 qsort(in_order, nanchor, sizeof(Anchor *), cmp_anchor_hseq);
1396 for (i = 0; i < nanchor; i++) {
1397 ParsedURL pu;
1398 char *url;
1399 if (in_order[i]->slave)
1400 continue;
1401 parseURL2(in_order[i]->url, &pu, baseURL(buf));
1402 url = url_decode2(parsedURL2Str(&pu)->ptr, Currentbuf);
1403 printf("[%d] %s\n", in_order[i]->hseq + 1, url);
1404 }
1405 }
1406 }
1407 mySignal(SIGINT, prevtrap);
1408 }
1409
1410 DEFUN(nulcmd, NOTHING NULL @@@, "Do nothing")
1411 { /* do nothing */
1412 }
1413
1414 #ifdef __EMX__
1415 DEFUN(pcmap, PCMAP, "pcmap")
1416 {
1417 w3mFuncList[(int)PcKeymap[(int)getch()]].func();
1418 }
1419 #else /* not __EMX__ */
1420 void
pcmap(void)1421 pcmap(void)
1422 {
1423 }
1424 #endif
1425
1426 static void
escKeyProc(int c,int esc,unsigned char * map)1427 escKeyProc(int c, int esc, unsigned char *map)
1428 {
1429 if (CurrentKey >= 0 && CurrentKey & K_MULTI) {
1430 unsigned char **mmap;
1431 mmap = (unsigned char **)getKeyData(MULTI_KEY(CurrentKey));
1432 if (!mmap)
1433 return;
1434 switch (esc) {
1435 case K_ESCD:
1436 map = mmap[3];
1437 break;
1438 case K_ESCB:
1439 map = mmap[2];
1440 break;
1441 case K_ESC:
1442 map = mmap[1];
1443 break;
1444 default:
1445 map = mmap[0];
1446 break;
1447 }
1448 esc |= (CurrentKey & ~0xFFFF);
1449 }
1450 CurrentKey = esc | c;
1451 w3mFuncList[(int)map[c]].func();
1452 }
1453
1454 DEFUN(escmap, ESCMAP, "ESC map")
1455 {
1456 char c;
1457 c = getch();
1458 if (IS_ASCII(c))
1459 escKeyProc((int)c, K_ESC, EscKeymap);
1460 }
1461
1462 DEFUN(escbmap, ESCBMAP, "ESC [ map")
1463 {
1464 char c;
1465 c = getch();
1466 if (IS_DIGIT(c)) {
1467 escdmap(c);
1468 return;
1469 }
1470 if (IS_ASCII(c))
1471 escKeyProc((int)c, K_ESCB, EscBKeymap);
1472 }
1473
1474 void
escdmap(char c)1475 escdmap(char c)
1476 {
1477 int d;
1478 d = (int)c - (int)'0';
1479 c = getch();
1480 if (IS_DIGIT(c)) {
1481 d = d * 10 + (int)c - (int)'0';
1482 c = getch();
1483 }
1484 if (c == '~')
1485 escKeyProc((int)d, K_ESCD, EscDKeymap);
1486 }
1487
1488 DEFUN(multimap, MULTIMAP, "multimap")
1489 {
1490 char c;
1491 c = getch();
1492 if (IS_ASCII(c)) {
1493 CurrentKey = K_MULTI | (CurrentKey << 16) | c;
1494 escKeyProc((int)c, 0, NULL);
1495 }
1496 }
1497
1498 void
tmpClearBuffer(Buffer * buf)1499 tmpClearBuffer(Buffer *buf)
1500 {
1501 if (buf->pagerSource == NULL && writeBufferCache(buf) == 0) {
1502 buf->firstLine = NULL;
1503 buf->topLine = NULL;
1504 buf->currentLine = NULL;
1505 buf->lastLine = NULL;
1506 }
1507 }
1508
1509 static Str currentURL(void);
1510
1511 #ifdef USE_BUFINFO
1512 void
saveBufferInfo()1513 saveBufferInfo()
1514 {
1515 FILE *fp;
1516
1517 if (w3m_dump)
1518 return;
1519 if ((fp = fopen(rcFile("bufinfo"), "w")) == NULL) {
1520 return;
1521 }
1522 fprintf(fp, "%s\n", currentURL()->ptr);
1523 fclose(fp);
1524 }
1525 #endif
1526
1527 static void
pushBuffer(Buffer * buf)1528 pushBuffer(Buffer *buf)
1529 {
1530 Buffer *b;
1531
1532 #ifdef USE_IMAGE
1533 deleteImage(Currentbuf);
1534 #endif
1535 if (clear_buffer)
1536 tmpClearBuffer(Currentbuf);
1537 if (Firstbuf == Currentbuf) {
1538 buf->nextBuffer = Firstbuf;
1539 Firstbuf = Currentbuf = buf;
1540 }
1541 else if ((b = prevBuffer(Firstbuf, Currentbuf)) != NULL) {
1542 b->nextBuffer = buf;
1543 buf->nextBuffer = Currentbuf;
1544 Currentbuf = buf;
1545 }
1546 #ifdef USE_BUFINFO
1547 saveBufferInfo();
1548 #endif
1549
1550 }
1551
1552 static void
delBuffer(Buffer * buf)1553 delBuffer(Buffer *buf)
1554 {
1555 if (buf == NULL)
1556 return;
1557 if (Currentbuf == buf)
1558 Currentbuf = buf->nextBuffer;
1559 Firstbuf = deleteBuffer(Firstbuf, buf);
1560 if (!Currentbuf)
1561 Currentbuf = Firstbuf;
1562 }
1563
1564 static void
repBuffer(Buffer * oldbuf,Buffer * buf)1565 repBuffer(Buffer *oldbuf, Buffer *buf)
1566 {
1567 Firstbuf = replaceBuffer(Firstbuf, oldbuf, buf);
1568 Currentbuf = buf;
1569 }
1570
1571
1572 MySignalHandler
intTrap(SIGNAL_ARG)1573 intTrap(SIGNAL_ARG)
1574 { /* Interrupt catcher */
1575 LONGJMP(IntReturn, 0);
1576 SIGNAL_RETURN;
1577 }
1578
1579 #ifdef SIGWINCH
1580 static MySignalHandler
resize_hook(SIGNAL_ARG)1581 resize_hook(SIGNAL_ARG)
1582 {
1583 need_resize_screen = TRUE;
1584 mySignal(SIGWINCH, resize_hook);
1585 SIGNAL_RETURN;
1586 }
1587
1588 static void
resize_screen(void)1589 resize_screen(void)
1590 {
1591 need_resize_screen = FALSE;
1592 setlinescols();
1593 setupscreen();
1594 if (CurrentTab)
1595 displayBuffer(Currentbuf, B_FORCE_REDRAW);
1596 }
1597 #endif /* SIGWINCH */
1598
1599 #ifdef SIGPIPE
1600 static MySignalHandler
SigPipe(SIGNAL_ARG)1601 SigPipe(SIGNAL_ARG)
1602 {
1603 #ifdef USE_MIGEMO
1604 init_migemo();
1605 #endif
1606 mySignal(SIGPIPE, SigPipe);
1607 SIGNAL_RETURN;
1608 }
1609 #endif
1610
1611 /*
1612 * Command functions: These functions are called with a keystroke.
1613 */
1614
1615 static void
nscroll(int n,int mode)1616 nscroll(int n, int mode)
1617 {
1618 Buffer *buf = Currentbuf;
1619 Line *top = buf->topLine, *cur = buf->currentLine;
1620 int lnum, tlnum, llnum, diff_n;
1621
1622 if (buf->firstLine == NULL)
1623 return;
1624 lnum = cur->linenumber;
1625 buf->topLine = lineSkip(buf, top, n, FALSE);
1626 if (buf->topLine == top) {
1627 lnum += n;
1628 if (lnum < buf->topLine->linenumber)
1629 lnum = buf->topLine->linenumber;
1630 else if (lnum > buf->lastLine->linenumber)
1631 lnum = buf->lastLine->linenumber;
1632 }
1633 else {
1634 tlnum = buf->topLine->linenumber;
1635 llnum = buf->topLine->linenumber + buf->LINES - 1;
1636 if (nextpage_topline)
1637 diff_n = 0;
1638 else
1639 diff_n = n - (tlnum - top->linenumber);
1640 if (lnum < tlnum)
1641 lnum = tlnum + diff_n;
1642 if (lnum > llnum)
1643 lnum = llnum + diff_n;
1644 }
1645 gotoLine(buf, lnum);
1646 arrangeLine(buf);
1647 if (n > 0) {
1648 if (buf->currentLine->bpos &&
1649 buf->currentLine->bwidth >= buf->currentColumn + buf->visualpos)
1650 cursorDown(buf, 1);
1651 else {
1652 while (buf->currentLine->next && buf->currentLine->next->bpos &&
1653 buf->currentLine->bwidth + buf->currentLine->width <
1654 buf->currentColumn + buf->visualpos)
1655 cursorDown0(buf, 1);
1656 }
1657 }
1658 else {
1659 if (buf->currentLine->bwidth + buf->currentLine->width <
1660 buf->currentColumn + buf->visualpos)
1661 cursorUp(buf, 1);
1662 else {
1663 while (buf->currentLine->prev && buf->currentLine->bpos &&
1664 buf->currentLine->bwidth >=
1665 buf->currentColumn + buf->visualpos)
1666 cursorUp0(buf, 1);
1667 }
1668 }
1669 displayBuffer(buf, mode);
1670 }
1671
1672 /* Move page forward */
1673 DEFUN(pgFore, NEXT_PAGE, "Scroll down one page")
1674 {
1675 if (vi_prec_num)
1676 nscroll(searchKeyNum() * (Currentbuf->LINES - 1), B_NORMAL);
1677 else
1678 nscroll(prec_num ? searchKeyNum() : searchKeyNum()
1679 * (Currentbuf->LINES - 1), prec_num ? B_SCROLL : B_NORMAL);
1680 }
1681
1682 /* Move page backward */
1683 DEFUN(pgBack, PREV_PAGE, "Scroll up one page")
1684 {
1685 if (vi_prec_num)
1686 nscroll(-searchKeyNum() * (Currentbuf->LINES - 1), B_NORMAL);
1687 else
1688 nscroll(-(prec_num ? searchKeyNum() : searchKeyNum()
1689 * (Currentbuf->LINES - 1)), prec_num ? B_SCROLL : B_NORMAL);
1690 }
1691
1692 /* Move half page forward */
1693 DEFUN(hpgFore, NEXT_HALF_PAGE, "Scroll down half a page")
1694 {
1695 nscroll(searchKeyNum() * (Currentbuf->LINES / 2 - 1), B_NORMAL);
1696 }
1697
1698 /* Move half page backward */
1699 DEFUN(hpgBack, PREV_HALF_PAGE, "Scroll up half a page")
1700 {
1701 nscroll(-searchKeyNum() * (Currentbuf->LINES / 2 - 1), B_NORMAL);
1702 }
1703
1704 /* 1 line up */
1705 DEFUN(lup1, UP, "Scroll the screen up one line")
1706 {
1707 nscroll(searchKeyNum(), B_SCROLL);
1708 }
1709
1710 /* 1 line down */
1711 DEFUN(ldown1, DOWN, "Scroll the screen down one line")
1712 {
1713 nscroll(-searchKeyNum(), B_SCROLL);
1714 }
1715
1716 /* move cursor position to the center of screen */
1717 DEFUN(ctrCsrV, CENTER_V, "Center on cursor line")
1718 {
1719 int offsety;
1720 if (Currentbuf->firstLine == NULL)
1721 return;
1722 offsety = Currentbuf->LINES / 2 - Currentbuf->cursorY;
1723 if (offsety != 0) {
1724 #if 0
1725 Currentbuf->currentLine = lineSkip(Currentbuf,
1726 Currentbuf->currentLine, offsety,
1727 FALSE);
1728 #endif
1729 Currentbuf->topLine =
1730 lineSkip(Currentbuf, Currentbuf->topLine, -offsety, FALSE);
1731 arrangeLine(Currentbuf);
1732 displayBuffer(Currentbuf, B_NORMAL);
1733 }
1734 }
1735
1736 DEFUN(ctrCsrH, CENTER_H, "Center on cursor column")
1737 {
1738 int offsetx;
1739 if (Currentbuf->firstLine == NULL)
1740 return;
1741 offsetx = Currentbuf->cursorX - Currentbuf->COLS / 2;
1742 if (offsetx != 0) {
1743 columnSkip(Currentbuf, offsetx);
1744 arrangeCursor(Currentbuf);
1745 displayBuffer(Currentbuf, B_NORMAL);
1746 }
1747 }
1748
1749 /* Redraw screen */
1750 DEFUN(rdrwSc, REDRAW, "Draw the screen anew")
1751 {
1752 clear();
1753 arrangeCursor(Currentbuf);
1754 displayBuffer(Currentbuf, B_FORCE_REDRAW);
1755 }
1756
1757 static void
clear_mark(Line * l)1758 clear_mark(Line *l)
1759 {
1760 int pos;
1761 if (!l)
1762 return;
1763 for (pos = 0; pos < l->size; pos++)
1764 l->propBuf[pos] &= ~PE_MARK;
1765 }
1766
1767 /* search by regular expression */
1768 static int
srchcore(char * volatile str,int (* func)(Buffer *,char *))1769 srchcore(char *volatile str, int (*func) (Buffer *, char *))
1770 {
1771 MySignalHandler(*prevtrap) ();
1772 volatile int i, result = SR_NOTFOUND;
1773
1774 if (str != NULL && str != SearchString)
1775 SearchString = str;
1776 if (SearchString == NULL || *SearchString == '\0')
1777 return SR_NOTFOUND;
1778
1779 str = conv_search_string(SearchString, DisplayCharset);
1780 prevtrap = mySignal(SIGINT, intTrap);
1781 crmode();
1782 if (SETJMP(IntReturn) == 0) {
1783 for (i = 0; i < PREC_NUM; i++) {
1784 result = func(Currentbuf, str);
1785 if (i < PREC_NUM - 1 && result & SR_FOUND)
1786 clear_mark(Currentbuf->currentLine);
1787 }
1788 }
1789 mySignal(SIGINT, prevtrap);
1790 term_raw();
1791 return result;
1792 }
1793
1794 static void
disp_srchresult(int result,char * prompt,char * str)1795 disp_srchresult(int result, char *prompt, char *str)
1796 {
1797 if (str == NULL)
1798 str = "";
1799 if (result & SR_NOTFOUND)
1800 disp_message(Sprintf("Not found: %s", str)->ptr, TRUE);
1801 else if (result & SR_WRAPPED)
1802 disp_message(Sprintf("Search wrapped: %s", str)->ptr, TRUE);
1803 else if (show_srch_str)
1804 disp_message(Sprintf("%s%s", prompt, str)->ptr, TRUE);
1805 }
1806
1807 static int
dispincsrch(int ch,Str buf,Lineprop * prop)1808 dispincsrch(int ch, Str buf, Lineprop *prop)
1809 {
1810 static Buffer sbuf;
1811 static Line *currentLine;
1812 static int pos;
1813 char *str;
1814 int do_next_search = FALSE;
1815
1816 if (ch == 0 && buf == NULL) {
1817 SAVE_BUFPOSITION(&sbuf); /* search starting point */
1818 currentLine = sbuf.currentLine;
1819 pos = sbuf.pos;
1820 return -1;
1821 }
1822
1823 str = buf->ptr;
1824 switch (ch) {
1825 case 022: /* C-r */
1826 searchRoutine = backwardSearch;
1827 do_next_search = TRUE;
1828 break;
1829 case 023: /* C-s */
1830 searchRoutine = forwardSearch;
1831 do_next_search = TRUE;
1832 break;
1833
1834 #ifdef USE_MIGEMO
1835 case 034:
1836 migemo_active = -migemo_active;
1837 goto done;
1838 #endif
1839
1840 default:
1841 if (ch >= 0)
1842 return ch; /* use InputKeymap */
1843 }
1844
1845 if (do_next_search) {
1846 if (*str) {
1847 if (searchRoutine == forwardSearch)
1848 Currentbuf->pos += 1;
1849 SAVE_BUFPOSITION(&sbuf);
1850 if (srchcore(str, searchRoutine) == SR_NOTFOUND
1851 && searchRoutine == forwardSearch) {
1852 Currentbuf->pos -= 1;
1853 SAVE_BUFPOSITION(&sbuf);
1854 }
1855 arrangeCursor(Currentbuf);
1856 displayBuffer(Currentbuf, B_FORCE_REDRAW);
1857 clear_mark(Currentbuf->currentLine);
1858 return -1;
1859 }
1860 else
1861 return 020; /* _prev completion for C-s C-s */
1862 }
1863 else if (*str) {
1864 RESTORE_BUFPOSITION(&sbuf);
1865 arrangeCursor(Currentbuf);
1866 srchcore(str, searchRoutine);
1867 arrangeCursor(Currentbuf);
1868 currentLine = Currentbuf->currentLine;
1869 pos = Currentbuf->pos;
1870 }
1871 displayBuffer(Currentbuf, B_FORCE_REDRAW);
1872 clear_mark(Currentbuf->currentLine);
1873 #ifdef USE_MIGEMO
1874 done:
1875 while (*str++ != '\0') {
1876 if (migemo_active > 0)
1877 *prop++ |= PE_UNDER;
1878 else
1879 *prop++ &= ~PE_UNDER;
1880 }
1881 #endif
1882 return -1;
1883 }
1884
1885 void
isrch(int (* func)(Buffer *,char *),char * prompt)1886 isrch(int (*func) (Buffer *, char *), char *prompt)
1887 {
1888 char *str;
1889 Buffer sbuf;
1890 SAVE_BUFPOSITION(&sbuf);
1891 dispincsrch(0, NULL, NULL); /* initialize incremental search state */
1892
1893 searchRoutine = func;
1894 str = inputLineHistSearch(prompt, NULL, IN_STRING, TextHist, dispincsrch);
1895 if (str == NULL) {
1896 RESTORE_BUFPOSITION(&sbuf);
1897 }
1898 displayBuffer(Currentbuf, B_FORCE_REDRAW);
1899 }
1900
1901 void
srch(int (* func)(Buffer *,char *),char * prompt)1902 srch(int (*func) (Buffer *, char *), char *prompt)
1903 {
1904 char *str;
1905 int result;
1906 int disp = FALSE;
1907 int pos;
1908
1909 str = searchKeyData();
1910 if (str == NULL || *str == '\0') {
1911 str = inputStrHist(prompt, NULL, TextHist);
1912 if (str != NULL && *str == '\0')
1913 str = SearchString;
1914 if (str == NULL) {
1915 displayBuffer(Currentbuf, B_NORMAL);
1916 return;
1917 }
1918 disp = TRUE;
1919 }
1920 pos = Currentbuf->pos;
1921 if (func == forwardSearch)
1922 Currentbuf->pos += 1;
1923 result = srchcore(str, func);
1924 if (result & SR_FOUND)
1925 clear_mark(Currentbuf->currentLine);
1926 else
1927 Currentbuf->pos = pos;
1928 displayBuffer(Currentbuf, B_NORMAL);
1929 if (disp)
1930 disp_srchresult(result, prompt, str);
1931 searchRoutine = func;
1932 }
1933
1934 /* Search regular expression forward */
1935
1936 DEFUN(srchfor, SEARCH SEARCH_FORE WHEREIS, "Search forward")
1937 {
1938 srch(forwardSearch, "Forward: ");
1939 }
1940
1941 DEFUN(isrchfor, ISEARCH, "Incremental search forward")
1942 {
1943 isrch(forwardSearch, "I-search: ");
1944 }
1945
1946 /* Search regular expression backward */
1947
1948 DEFUN(srchbak, SEARCH_BACK, "Search backward")
1949 {
1950 srch(backwardSearch, "Backward: ");
1951 }
1952
1953 DEFUN(isrchbak, ISEARCH_BACK, "Incremental search backward")
1954 {
1955 isrch(backwardSearch, "I-search backward: ");
1956 }
1957
1958 static void
srch_nxtprv(int reverse)1959 srch_nxtprv(int reverse)
1960 {
1961 int result;
1962 /* *INDENT-OFF* */
1963 static int (*routine[2]) (Buffer *, char *) = {
1964 forwardSearch, backwardSearch
1965 };
1966 /* *INDENT-ON* */
1967
1968 if (searchRoutine == NULL) {
1969 /* FIXME: gettextize? */
1970 disp_message("No previous regular expression", TRUE);
1971 return;
1972 }
1973 if (reverse != 0)
1974 reverse = 1;
1975 if (searchRoutine == backwardSearch)
1976 reverse ^= 1;
1977 if (reverse == 0)
1978 Currentbuf->pos += 1;
1979 result = srchcore(SearchString, routine[reverse]);
1980 if (result & SR_FOUND)
1981 clear_mark(Currentbuf->currentLine);
1982 else {
1983 if (reverse == 0)
1984 Currentbuf->pos -= 1;
1985 }
1986 displayBuffer(Currentbuf, B_NORMAL);
1987 disp_srchresult(result, (reverse ? "Backward: " : "Forward: "),
1988 SearchString);
1989 }
1990
1991 /* Search next matching */
1992 DEFUN(srchnxt, SEARCH_NEXT, "Continue search forward")
1993 {
1994 srch_nxtprv(0);
1995 }
1996
1997 /* Search previous matching */
1998 DEFUN(srchprv, SEARCH_PREV, "Continue search backward")
1999 {
2000 srch_nxtprv(1);
2001 }
2002
2003 static void
shiftvisualpos(Buffer * buf,int shift)2004 shiftvisualpos(Buffer *buf, int shift)
2005 {
2006 Line *l = buf->currentLine;
2007 buf->visualpos -= shift;
2008 if (buf->visualpos - l->bwidth >= buf->COLS)
2009 buf->visualpos = l->bwidth + buf->COLS - 1;
2010 else if (buf->visualpos - l->bwidth < 0)
2011 buf->visualpos = l->bwidth;
2012 arrangeLine(buf);
2013 if (buf->visualpos - l->bwidth == -shift && buf->cursorX == 0)
2014 buf->visualpos = l->bwidth;
2015 }
2016
2017 /* Shift screen left */
2018 DEFUN(shiftl, SHIFT_LEFT, "Shift screen left")
2019 {
2020 int column;
2021
2022 if (Currentbuf->firstLine == NULL)
2023 return;
2024 column = Currentbuf->currentColumn;
2025 columnSkip(Currentbuf, searchKeyNum() * (-Currentbuf->COLS + 1) + 1);
2026 shiftvisualpos(Currentbuf, Currentbuf->currentColumn - column);
2027 displayBuffer(Currentbuf, B_NORMAL);
2028 }
2029
2030 /* Shift screen right */
2031 DEFUN(shiftr, SHIFT_RIGHT, "Shift screen right")
2032 {
2033 int column;
2034
2035 if (Currentbuf->firstLine == NULL)
2036 return;
2037 column = Currentbuf->currentColumn;
2038 columnSkip(Currentbuf, searchKeyNum() * (Currentbuf->COLS - 1) - 1);
2039 shiftvisualpos(Currentbuf, Currentbuf->currentColumn - column);
2040 displayBuffer(Currentbuf, B_NORMAL);
2041 }
2042
2043 DEFUN(col1R, RIGHT, "Shift screen one column right")
2044 {
2045 Buffer *buf = Currentbuf;
2046 Line *l = buf->currentLine;
2047 int j, column, n = searchKeyNum();
2048
2049 if (l == NULL)
2050 return;
2051 for (j = 0; j < n; j++) {
2052 column = buf->currentColumn;
2053 columnSkip(Currentbuf, 1);
2054 if (column == buf->currentColumn)
2055 break;
2056 shiftvisualpos(Currentbuf, 1);
2057 }
2058 displayBuffer(Currentbuf, B_NORMAL);
2059 }
2060
2061 DEFUN(col1L, LEFT, "Shift screen one column left")
2062 {
2063 Buffer *buf = Currentbuf;
2064 Line *l = buf->currentLine;
2065 int j, n = searchKeyNum();
2066
2067 if (l == NULL)
2068 return;
2069 for (j = 0; j < n; j++) {
2070 if (buf->currentColumn == 0)
2071 break;
2072 columnSkip(Currentbuf, -1);
2073 shiftvisualpos(Currentbuf, -1);
2074 }
2075 displayBuffer(Currentbuf, B_NORMAL);
2076 }
2077
2078 DEFUN(setEnv, SETENV, "Set environment variable")
2079 {
2080 char *env;
2081 char *var, *value;
2082
2083 CurrentKeyData = NULL; /* not allowed in w3m-control: */
2084 env = searchKeyData();
2085 if (env == NULL || *env == '\0' || strchr(env, '=') == NULL) {
2086 if (env != NULL && *env != '\0')
2087 env = Sprintf("%s=", env)->ptr;
2088 env = inputStrHist("Set environ: ", env, TextHist);
2089 if (env == NULL || *env == '\0') {
2090 displayBuffer(Currentbuf, B_NORMAL);
2091 return;
2092 }
2093 }
2094 if ((value = strchr(env, '=')) != NULL && value > env) {
2095 var = allocStr(env, value - env);
2096 value++;
2097 set_environ(var, value);
2098 }
2099 displayBuffer(Currentbuf, B_NORMAL);
2100 }
2101
2102 DEFUN(pipeBuf, PIPE_BUF, "Pipe current buffer through a shell command and display output")
2103 {
2104 Buffer *buf;
2105 char *cmd, *tmpf;
2106 FILE *f;
2107
2108 CurrentKeyData = NULL; /* not allowed in w3m-control: */
2109 cmd = searchKeyData();
2110 if (cmd == NULL || *cmd == '\0') {
2111 /* FIXME: gettextize? */
2112 cmd = inputLineHist("Pipe buffer to: ", "", IN_COMMAND, ShellHist);
2113 }
2114 if (cmd != NULL)
2115 cmd = conv_to_system(cmd);
2116 if (cmd == NULL || *cmd == '\0') {
2117 displayBuffer(Currentbuf, B_NORMAL);
2118 return;
2119 }
2120 tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
2121 f = fopen(tmpf, "w");
2122 if (f == NULL) {
2123 /* FIXME: gettextize? */
2124 disp_message(Sprintf("Can't save buffer to %s", cmd)->ptr, TRUE);
2125 return;
2126 }
2127 saveBuffer(Currentbuf, f, TRUE);
2128 fclose(f);
2129 buf = getpipe(myExtCommand(cmd, shell_quote(tmpf), TRUE)->ptr);
2130 if (buf == NULL) {
2131 disp_message("Execution failed", TRUE);
2132 return;
2133 }
2134 else {
2135 buf->filename = cmd;
2136 buf->buffername = Sprintf("%s %s", PIPEBUFFERNAME,
2137 conv_from_system(cmd))->ptr;
2138 buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
2139 if (buf->type == NULL)
2140 buf->type = "text/plain";
2141 buf->currentURL.file = "-";
2142 pushBuffer(buf);
2143 }
2144 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2145 }
2146
2147 /* Execute shell command and read output ac pipe. */
2148 DEFUN(pipesh, PIPE_SHELL, "Execute shell command and display output")
2149 {
2150 Buffer *buf;
2151 char *cmd;
2152
2153 CurrentKeyData = NULL; /* not allowed in w3m-control: */
2154 cmd = searchKeyData();
2155 if (cmd == NULL || *cmd == '\0') {
2156 cmd = inputLineHist("(read shell[pipe])!", "", IN_COMMAND, ShellHist);
2157 }
2158 if (cmd != NULL)
2159 cmd = conv_to_system(cmd);
2160 if (cmd == NULL || *cmd == '\0') {
2161 displayBuffer(Currentbuf, B_NORMAL);
2162 return;
2163 }
2164 buf = getpipe(cmd);
2165 if (buf == NULL) {
2166 disp_message("Execution failed", TRUE);
2167 return;
2168 }
2169 else {
2170 buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
2171 if (buf->type == NULL)
2172 buf->type = "text/plain";
2173 pushBuffer(buf);
2174 }
2175 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2176 }
2177
2178 /* Execute shell command and load entire output to buffer */
2179 DEFUN(readsh, READ_SHELL, "Execute shell command and display output")
2180 {
2181 Buffer *buf;
2182 MySignalHandler(*prevtrap) ();
2183 char *cmd;
2184
2185 CurrentKeyData = NULL; /* not allowed in w3m-control: */
2186 cmd = searchKeyData();
2187 if (cmd == NULL || *cmd == '\0') {
2188 cmd = inputLineHist("(read shell)!", "", IN_COMMAND, ShellHist);
2189 }
2190 if (cmd != NULL)
2191 cmd = conv_to_system(cmd);
2192 if (cmd == NULL || *cmd == '\0') {
2193 displayBuffer(Currentbuf, B_NORMAL);
2194 return;
2195 }
2196 prevtrap = mySignal(SIGINT, intTrap);
2197 crmode();
2198 buf = getshell(cmd);
2199 mySignal(SIGINT, prevtrap);
2200 term_raw();
2201 if (buf == NULL) {
2202 /* FIXME: gettextize? */
2203 disp_message("Execution failed", TRUE);
2204 return;
2205 }
2206 else {
2207 buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
2208 if (buf->type == NULL)
2209 buf->type = "text/plain";
2210 pushBuffer(buf);
2211 }
2212 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2213 }
2214
2215 /* Execute shell command */
2216 DEFUN(execsh, EXEC_SHELL SHELL, "Execute shell command and display output")
2217 {
2218 char *cmd;
2219
2220 CurrentKeyData = NULL; /* not allowed in w3m-control: */
2221 cmd = searchKeyData();
2222 if (cmd == NULL || *cmd == '\0') {
2223 cmd = inputLineHist("(exec shell)!", "", IN_COMMAND, ShellHist);
2224 }
2225 if (cmd != NULL)
2226 cmd = conv_to_system(cmd);
2227 if (cmd != NULL && *cmd != '\0') {
2228 fmTerm();
2229 printf("\n");
2230 system(cmd);
2231 /* FIXME: gettextize? */
2232 printf("\n[Hit any key]");
2233 fflush(stdout);
2234 fmInit();
2235 getch();
2236 }
2237 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2238 }
2239
2240 /* Load file */
2241 DEFUN(ldfile, LOAD, "Open local file in a new buffer")
2242 {
2243 char *fn;
2244
2245 fn = searchKeyData();
2246 if (fn == NULL || *fn == '\0') {
2247 /* FIXME: gettextize? */
2248 fn = inputFilenameHist("(Load)Filename? ", NULL, LoadHist);
2249 }
2250 if (fn != NULL)
2251 fn = conv_to_system(fn);
2252 if (fn == NULL || *fn == '\0') {
2253 displayBuffer(Currentbuf, B_NORMAL);
2254 return;
2255 }
2256 cmd_loadfile(fn);
2257 }
2258
2259 /* Load help file */
2260 DEFUN(ldhelp, HELP, "Show help panel")
2261 {
2262 #ifdef USE_HELP_CGI
2263 char *lang;
2264 int n;
2265 Str tmp;
2266
2267 lang = AcceptLang;
2268 n = strcspn(lang, ";, \t");
2269 tmp = Sprintf("file:///$LIB/" HELP_CGI CGI_EXTENSION "?version=%s&lang=%s",
2270 Str_form_quote(Strnew_charp(w3m_version))->ptr,
2271 Str_form_quote(Strnew_charp_n(lang, n))->ptr);
2272 cmd_loadURL(tmp->ptr, NULL, NO_REFERER, NULL);
2273 #else
2274 cmd_loadURL(helpFile(HELP_FILE), NULL, NO_REFERER, NULL);
2275 #endif
2276 }
2277
2278 static void
cmd_loadfile(char * fn)2279 cmd_loadfile(char *fn)
2280 {
2281 Buffer *buf;
2282
2283 buf = loadGeneralFile(file_to_url(fn), NULL, NO_REFERER, 0, NULL);
2284 if (buf == NULL) {
2285 /* FIXME: gettextize? */
2286 char *emsg = Sprintf("%s not found", conv_from_system(fn))->ptr;
2287 disp_err_message(emsg, FALSE);
2288 }
2289 else if (buf != NO_BUFFER) {
2290 pushBuffer(buf);
2291 if (RenderFrame && Currentbuf->frameset != NULL)
2292 rFrame();
2293 }
2294 displayBuffer(Currentbuf, B_NORMAL);
2295 }
2296
2297 /* Move cursor left */
2298 static void
_movL(int n)2299 _movL(int n)
2300 {
2301 int i, m = searchKeyNum();
2302 if (Currentbuf->firstLine == NULL)
2303 return;
2304 for (i = 0; i < m; i++)
2305 cursorLeft(Currentbuf, n);
2306 displayBuffer(Currentbuf, B_NORMAL);
2307 }
2308
2309 DEFUN(movL, MOVE_LEFT, "Cursor left")
2310 {
2311 _movL(Currentbuf->COLS / 2);
2312 }
2313
2314 DEFUN(movL1, MOVE_LEFT1, "Cursor left. With edge touched, slide")
2315 {
2316 _movL(1);
2317 }
2318
2319 /* Move cursor downward */
2320 static void
_movD(int n)2321 _movD(int n)
2322 {
2323 int i, m = searchKeyNum();
2324 if (Currentbuf->firstLine == NULL)
2325 return;
2326 for (i = 0; i < m; i++)
2327 cursorDown(Currentbuf, n);
2328 displayBuffer(Currentbuf, B_NORMAL);
2329 }
2330
2331 DEFUN(movD, MOVE_DOWN, "Cursor down")
2332 {
2333 _movD((Currentbuf->LINES + 1) / 2);
2334 }
2335
2336 DEFUN(movD1, MOVE_DOWN1, "Cursor down. With edge touched, slide")
2337 {
2338 _movD(1);
2339 }
2340
2341 /* move cursor upward */
2342 static void
_movU(int n)2343 _movU(int n)
2344 {
2345 int i, m = searchKeyNum();
2346 if (Currentbuf->firstLine == NULL)
2347 return;
2348 for (i = 0; i < m; i++)
2349 cursorUp(Currentbuf, n);
2350 displayBuffer(Currentbuf, B_NORMAL);
2351 }
2352
2353 DEFUN(movU, MOVE_UP, "Cursor up")
2354 {
2355 _movU((Currentbuf->LINES + 1) / 2);
2356 }
2357
2358 DEFUN(movU1, MOVE_UP1, "Cursor up. With edge touched, slide")
2359 {
2360 _movU(1);
2361 }
2362
2363 /* Move cursor right */
2364 static void
_movR(int n)2365 _movR(int n)
2366 {
2367 int i, m = searchKeyNum();
2368 if (Currentbuf->firstLine == NULL)
2369 return;
2370 for (i = 0; i < m; i++)
2371 cursorRight(Currentbuf, n);
2372 displayBuffer(Currentbuf, B_NORMAL);
2373 }
2374
2375 DEFUN(movR, MOVE_RIGHT, "Cursor right")
2376 {
2377 _movR(Currentbuf->COLS / 2);
2378 }
2379
2380 DEFUN(movR1, MOVE_RIGHT1, "Cursor right. With edge touched, slide")
2381 {
2382 _movR(1);
2383 }
2384
2385 /* movLW, movRW */
2386 /*
2387 * From: Takashi Nishimoto <g96p0935@mse.waseda.ac.jp> Date: Mon, 14 Jun
2388 * 1999 09:29:56 +0900
2389 */
2390 #if defined(USE_M17N) && defined(USE_UNICODE)
2391 #define nextChar(s, l) do { (s)++; } while ((s) < (l)->len && (l)->propBuf[s] & PC_WCHAR2)
2392 #define prevChar(s, l) do { (s)--; } while ((s) > 0 && (l)->propBuf[s] & PC_WCHAR2)
2393
2394 static wc_uint32
getChar(char * p)2395 getChar(char *p)
2396 {
2397 return wc_any_to_ucs(wtf_parse1((wc_uchar **)&p));
2398 }
2399
2400 static int
is_wordchar(wc_uint32 c)2401 is_wordchar(wc_uint32 c)
2402 {
2403 return wc_is_ucs_alnum(c);
2404 }
2405 #else
2406 #define nextChar(s, l) (s)++
2407 #define prevChar(s, l) (s)--
2408 #define getChar(p) ((int)*(p))
2409
2410 static int
is_wordchar(int c)2411 is_wordchar(int c)
2412 {
2413 return IS_ALNUM(c);
2414 }
2415 #endif
2416
2417 static int
prev_nonnull_line(Line * line)2418 prev_nonnull_line(Line *line)
2419 {
2420 Line *l;
2421
2422 for (l = line; l != NULL && l->len == 0; l = l->prev) ;
2423 if (l == NULL || l->len == 0)
2424 return -1;
2425
2426 Currentbuf->currentLine = l;
2427 if (l != line)
2428 Currentbuf->pos = Currentbuf->currentLine->len;
2429 return 0;
2430 }
2431
2432 DEFUN(movLW, PREV_WORD, "Move to the previous word")
2433 {
2434 char *lb;
2435 Line *pline, *l;
2436 int ppos;
2437 int i, n = searchKeyNum();
2438
2439 if (Currentbuf->firstLine == NULL)
2440 return;
2441
2442 for (i = 0; i < n; i++) {
2443 pline = Currentbuf->currentLine;
2444 ppos = Currentbuf->pos;
2445
2446 if (prev_nonnull_line(Currentbuf->currentLine) < 0)
2447 goto end;
2448
2449 while (1) {
2450 l = Currentbuf->currentLine;
2451 lb = l->lineBuf;
2452 while (Currentbuf->pos > 0) {
2453 int tmp = Currentbuf->pos;
2454 prevChar(tmp, l);
2455 if (is_wordchar(getChar(&lb[tmp])))
2456 break;
2457 Currentbuf->pos = tmp;
2458 }
2459 if (Currentbuf->pos > 0)
2460 break;
2461 if (prev_nonnull_line(Currentbuf->currentLine->prev) < 0) {
2462 Currentbuf->currentLine = pline;
2463 Currentbuf->pos = ppos;
2464 goto end;
2465 }
2466 Currentbuf->pos = Currentbuf->currentLine->len;
2467 }
2468
2469 l = Currentbuf->currentLine;
2470 lb = l->lineBuf;
2471 while (Currentbuf->pos > 0) {
2472 int tmp = Currentbuf->pos;
2473 prevChar(tmp, l);
2474 if (!is_wordchar(getChar(&lb[tmp])))
2475 break;
2476 Currentbuf->pos = tmp;
2477 }
2478 }
2479 end:
2480 arrangeCursor(Currentbuf);
2481 displayBuffer(Currentbuf, B_NORMAL);
2482 }
2483
2484 static int
next_nonnull_line(Line * line)2485 next_nonnull_line(Line *line)
2486 {
2487 Line *l;
2488
2489 for (l = line; l != NULL && l->len == 0; l = l->next) ;
2490
2491 if (l == NULL || l->len == 0)
2492 return -1;
2493
2494 Currentbuf->currentLine = l;
2495 if (l != line)
2496 Currentbuf->pos = 0;
2497 return 0;
2498 }
2499
2500 DEFUN(movRW, NEXT_WORD, "Move to the next word")
2501 {
2502 char *lb;
2503 Line *pline, *l;
2504 int ppos;
2505 int i, n = searchKeyNum();
2506
2507 if (Currentbuf->firstLine == NULL)
2508 return;
2509
2510 for (i = 0; i < n; i++) {
2511 pline = Currentbuf->currentLine;
2512 ppos = Currentbuf->pos;
2513
2514 if (next_nonnull_line(Currentbuf->currentLine) < 0)
2515 goto end;
2516
2517 l = Currentbuf->currentLine;
2518 lb = l->lineBuf;
2519 while (Currentbuf->pos < l->len &&
2520 is_wordchar(getChar(&lb[Currentbuf->pos])))
2521 nextChar(Currentbuf->pos, l);
2522
2523 while (1) {
2524 while (Currentbuf->pos < l->len &&
2525 !is_wordchar(getChar(&lb[Currentbuf->pos])))
2526 nextChar(Currentbuf->pos, l);
2527 if (Currentbuf->pos < l->len)
2528 break;
2529 if (next_nonnull_line(Currentbuf->currentLine->next) < 0) {
2530 Currentbuf->currentLine = pline;
2531 Currentbuf->pos = ppos;
2532 goto end;
2533 }
2534 Currentbuf->pos = 0;
2535 l = Currentbuf->currentLine;
2536 lb = l->lineBuf;
2537 }
2538 }
2539 end:
2540 arrangeCursor(Currentbuf);
2541 displayBuffer(Currentbuf, B_NORMAL);
2542 }
2543
2544 static void
_quitfm(int confirm)2545 _quitfm(int confirm)
2546 {
2547 char *ans = "y";
2548
2549 if (checkDownloadList())
2550 /* FIXME: gettextize? */
2551 ans = inputChar("Download process retains. "
2552 "Do you want to exit w3m? (y/n)");
2553 else if (confirm)
2554 /* FIXME: gettextize? */
2555 ans = inputChar("Do you want to exit w3m? (y/n)");
2556 if (!(ans && TOLOWER(*ans) == 'y')) {
2557 displayBuffer(Currentbuf, B_NORMAL);
2558 return;
2559 }
2560
2561 term_title(""); /* XXX */
2562 #ifdef USE_IMAGE
2563 if (activeImage)
2564 termImage();
2565 #endif
2566 fmTerm();
2567 #ifdef USE_COOKIE
2568 save_cookies();
2569 #endif /* USE_COOKIE */
2570 #ifdef USE_HISTORY
2571 if (UseHistory && SaveURLHist)
2572 saveHistory(URLHist, URLHistSize);
2573 #endif /* USE_HISTORY */
2574 w3m_exit(0);
2575 }
2576
2577 /* Quit */
2578 DEFUN(quitfm, ABORT EXIT, "Quit at once")
2579 {
2580 _quitfm(FALSE);
2581 }
2582
2583 /* Question and Quit */
2584 DEFUN(qquitfm, QUIT, "Quit with confirmation request")
2585 {
2586 _quitfm(confirm_on_quit);
2587 }
2588
2589 /* Select buffer */
2590 DEFUN(selBuf, SELECT, "Display buffer-stack panel")
2591 {
2592 Buffer *buf;
2593 int ok;
2594 char cmd;
2595
2596 ok = FALSE;
2597 do {
2598 buf = selectBuffer(Firstbuf, Currentbuf, &cmd);
2599 switch (cmd) {
2600 case 'B':
2601 ok = TRUE;
2602 break;
2603 case '\n':
2604 case ' ':
2605 Currentbuf = buf;
2606 ok = TRUE;
2607 break;
2608 case 'D':
2609 delBuffer(buf);
2610 if (Firstbuf == NULL) {
2611 /* No more buffer */
2612 Firstbuf = nullBuffer();
2613 Currentbuf = Firstbuf;
2614 }
2615 break;
2616 case 'q':
2617 qquitfm();
2618 break;
2619 case 'Q':
2620 quitfm();
2621 break;
2622 }
2623 } while (!ok);
2624
2625 for (buf = Firstbuf; buf != NULL; buf = buf->nextBuffer) {
2626 if (buf == Currentbuf)
2627 continue;
2628 #ifdef USE_IMAGE
2629 deleteImage(buf);
2630 #endif
2631 if (clear_buffer)
2632 tmpClearBuffer(buf);
2633 }
2634 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2635 }
2636
2637 /* Suspend (on BSD), or run interactive shell (on SysV) */
2638 DEFUN(susp, INTERRUPT SUSPEND, "Suspend w3m to background")
2639 {
2640 #ifndef SIGSTOP
2641 char *shell;
2642 #endif /* not SIGSTOP */
2643 move(LASTLINE, 0);
2644 clrtoeolx();
2645 refresh();
2646 fmTerm();
2647 #ifndef SIGSTOP
2648 shell = getenv("SHELL");
2649 if (shell == NULL)
2650 shell = "/bin/sh";
2651 system(shell);
2652 #else /* SIGSTOP */
2653 #ifdef SIGTSTP
2654 signal(SIGTSTP, SIG_DFL); /* just in case */
2655 /*
2656 * Note: If susp() was called from SIGTSTP handler,
2657 * unblocking SIGTSTP would be required here.
2658 * Currently not.
2659 */
2660 kill(0, SIGTSTP); /* stop whole job, not a single process */
2661 #else
2662 kill((pid_t) 0, SIGSTOP);
2663 #endif
2664 #endif /* SIGSTOP */
2665 fmInit();
2666 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2667 }
2668
2669 /* Go to specified line */
2670 static void
_goLine(char * l)2671 _goLine(char *l)
2672 {
2673 if (l == NULL || *l == '\0' || Currentbuf->currentLine == NULL) {
2674 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2675 return;
2676 }
2677 Currentbuf->pos = 0;
2678 if (((*l == '^') || (*l == '$')) && prec_num) {
2679 gotoRealLine(Currentbuf, prec_num);
2680 }
2681 else if (*l == '^') {
2682 Currentbuf->topLine = Currentbuf->currentLine = Currentbuf->firstLine;
2683 }
2684 else if (*l == '$') {
2685 Currentbuf->topLine =
2686 lineSkip(Currentbuf, Currentbuf->lastLine,
2687 -(Currentbuf->LINES + 1) / 2, TRUE);
2688 Currentbuf->currentLine = Currentbuf->lastLine;
2689 }
2690 else
2691 gotoRealLine(Currentbuf, atoi(l));
2692 arrangeCursor(Currentbuf);
2693 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2694 }
2695
2696 DEFUN(goLine, GOTO_LINE, "Go to the specified line")
2697 {
2698
2699 char *str = searchKeyData();
2700 if (prec_num)
2701 _goLine("^");
2702 else if (str)
2703 _goLine(str);
2704 else
2705 /* FIXME: gettextize? */
2706 _goLine(inputStr("Goto line: ", ""));
2707 }
2708
2709
2710 DEFUN(goLineF, BEGIN, "Go to the first line")
2711 {
2712 _goLine("^");
2713 }
2714
2715 DEFUN(goLineL, END, "Go to the last line")
2716 {
2717 _goLine("$");
2718 }
2719
2720 /* Go to the beginning of the line */
2721 DEFUN(linbeg, LINE_BEGIN, "Go to the beginning of the line")
2722 {
2723 if (Currentbuf->firstLine == NULL)
2724 return;
2725 while (Currentbuf->currentLine->prev && Currentbuf->currentLine->bpos)
2726 cursorUp0(Currentbuf, 1);
2727 Currentbuf->pos = 0;
2728 arrangeCursor(Currentbuf);
2729 displayBuffer(Currentbuf, B_NORMAL);
2730 }
2731
2732 /* Go to the bottom of the line */
2733 DEFUN(linend, LINE_END, "Go to the end of the line")
2734 {
2735 if (Currentbuf->firstLine == NULL)
2736 return;
2737 while (Currentbuf->currentLine->next
2738 && Currentbuf->currentLine->next->bpos)
2739 cursorDown0(Currentbuf, 1);
2740 Currentbuf->pos = Currentbuf->currentLine->len - 1;
2741 arrangeCursor(Currentbuf);
2742 displayBuffer(Currentbuf, B_NORMAL);
2743 }
2744
2745 static int
cur_real_linenumber(Buffer * buf)2746 cur_real_linenumber(Buffer *buf)
2747 {
2748 Line *l, *cur = buf->currentLine;
2749 int n;
2750
2751 if (!cur)
2752 return 1;
2753 n = cur->real_linenumber ? cur->real_linenumber : 1;
2754 for (l = buf->firstLine; l && l != cur && l->real_linenumber == 0; l = l->next) { /* header */
2755 if (l->bpos == 0)
2756 n++;
2757 }
2758 return n;
2759 }
2760
2761 /* Run editor on the current buffer */
2762 DEFUN(editBf, EDIT, "Edit local source")
2763 {
2764 char *fn = Currentbuf->filename;
2765 Str cmd;
2766
2767 if (fn == NULL || Currentbuf->pagerSource != NULL || /* Behaving as a pager */
2768 (Currentbuf->type == NULL && Currentbuf->edit == NULL) || /* Reading shell */
2769 Currentbuf->real_scheme != SCM_LOCAL || !strcmp(Currentbuf->currentURL.file, "-") || /* file is std input */
2770 Currentbuf->bufferprop & BP_FRAME) { /* Frame */
2771 disp_err_message("Can't edit other than local file", TRUE);
2772 return;
2773 }
2774 if (Currentbuf->edit)
2775 cmd = unquote_mailcap(Currentbuf->edit, Currentbuf->real_type, fn,
2776 checkHeader(Currentbuf, "Content-Type:"), NULL);
2777 else
2778 cmd = myEditor(Editor, shell_quote(fn),
2779 cur_real_linenumber(Currentbuf));
2780 fmTerm();
2781 system(cmd->ptr);
2782 fmInit();
2783
2784 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2785 reload();
2786 }
2787
2788 /* Run editor on the current screen */
2789 DEFUN(editScr, EDIT_SCREEN, "Edit rendered copy of document")
2790 {
2791 char *tmpf;
2792 FILE *f;
2793
2794 tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
2795 f = fopen(tmpf, "w");
2796 if (f == NULL) {
2797 /* FIXME: gettextize? */
2798 disp_err_message(Sprintf("Can't open %s", tmpf)->ptr, TRUE);
2799 return;
2800 }
2801 saveBuffer(Currentbuf, f, TRUE);
2802 fclose(f);
2803 fmTerm();
2804 system(myEditor(Editor, shell_quote(tmpf),
2805 cur_real_linenumber(Currentbuf))->ptr);
2806 fmInit();
2807 unlink(tmpf);
2808 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2809 }
2810
2811 #ifdef USE_MARK
2812
2813 /* Set / unset mark */
2814 DEFUN(_mark, MARK, "Set/unset mark")
2815 {
2816 Line *l;
2817 if (!use_mark)
2818 return;
2819 if (Currentbuf->firstLine == NULL)
2820 return;
2821 l = Currentbuf->currentLine;
2822 l->propBuf[Currentbuf->pos] ^= PE_MARK;
2823 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2824 }
2825
2826 /* Go to next mark */
2827 DEFUN(nextMk, NEXT_MARK, "Go to the next mark")
2828 {
2829 Line *l;
2830 int i;
2831
2832 if (!use_mark)
2833 return;
2834 if (Currentbuf->firstLine == NULL)
2835 return;
2836 i = Currentbuf->pos + 1;
2837 l = Currentbuf->currentLine;
2838 if (i >= l->len) {
2839 i = 0;
2840 l = l->next;
2841 }
2842 while (l != NULL) {
2843 for (; i < l->len; i++) {
2844 if (l->propBuf[i] & PE_MARK) {
2845 Currentbuf->currentLine = l;
2846 Currentbuf->pos = i;
2847 arrangeCursor(Currentbuf);
2848 displayBuffer(Currentbuf, B_NORMAL);
2849 return;
2850 }
2851 }
2852 l = l->next;
2853 i = 0;
2854 }
2855 /* FIXME: gettextize? */
2856 disp_message("No mark exist after here", TRUE);
2857 }
2858
2859 /* Go to previous mark */
2860 DEFUN(prevMk, PREV_MARK, "Go to the previous mark")
2861 {
2862 Line *l;
2863 int i;
2864
2865 if (!use_mark)
2866 return;
2867 if (Currentbuf->firstLine == NULL)
2868 return;
2869 i = Currentbuf->pos - 1;
2870 l = Currentbuf->currentLine;
2871 if (i < 0) {
2872 l = l->prev;
2873 if (l != NULL)
2874 i = l->len - 1;
2875 }
2876 while (l != NULL) {
2877 for (; i >= 0; i--) {
2878 if (l->propBuf[i] & PE_MARK) {
2879 Currentbuf->currentLine = l;
2880 Currentbuf->pos = i;
2881 arrangeCursor(Currentbuf);
2882 displayBuffer(Currentbuf, B_NORMAL);
2883 return;
2884 }
2885 }
2886 l = l->prev;
2887 if (l != NULL)
2888 i = l->len - 1;
2889 }
2890 /* FIXME: gettextize? */
2891 disp_message("No mark exist before here", TRUE);
2892 }
2893
2894 /* Mark place to which the regular expression matches */
2895 DEFUN(reMark, REG_MARK, "Mark all occurences of a pattern")
2896 {
2897 Line *l;
2898 char *str;
2899 char *p, *p1, *p2;
2900
2901 if (!use_mark)
2902 return;
2903 str = searchKeyData();
2904 if (str == NULL || *str == '\0') {
2905 str = inputStrHist("(Mark)Regexp: ", MarkString, TextHist);
2906 if (str == NULL || *str == '\0') {
2907 displayBuffer(Currentbuf, B_NORMAL);
2908 return;
2909 }
2910 }
2911 str = conv_search_string(str, DisplayCharset);
2912 if ((str = regexCompile(str, 1)) != NULL) {
2913 disp_message(str, TRUE);
2914 return;
2915 }
2916 MarkString = str;
2917 for (l = Currentbuf->firstLine; l != NULL; l = l->next) {
2918 p = l->lineBuf;
2919 for (;;) {
2920 if (regexMatch(p, &l->lineBuf[l->len] - p, p == l->lineBuf) == 1) {
2921 matchedPosition(&p1, &p2);
2922 l->propBuf[p1 - l->lineBuf] |= PE_MARK;
2923 p = p2;
2924 }
2925 else
2926 break;
2927 }
2928 }
2929
2930 displayBuffer(Currentbuf, B_FORCE_REDRAW);
2931 }
2932 #endif /* USE_MARK */
2933
2934 static Buffer *
loadNormalBuf(Buffer * buf,int renderframe)2935 loadNormalBuf(Buffer *buf, int renderframe)
2936 {
2937 pushBuffer(buf);
2938 if (renderframe && RenderFrame && Currentbuf->frameset != NULL)
2939 rFrame();
2940 return buf;
2941 }
2942
2943 static Buffer *
loadLink(char * url,char * target,char * referer,FormList * request)2944 loadLink(char *url, char *target, char *referer, FormList *request)
2945 {
2946 Buffer *buf, *nfbuf;
2947 union frameset_element *f_element = NULL;
2948 int flag = 0;
2949 ParsedURL *base, pu;
2950 const int *no_referer_ptr;
2951
2952 message(Sprintf("loading %s", url)->ptr, 0, 0);
2953 refresh();
2954
2955 no_referer_ptr = query_SCONF_NO_REFERER_FROM(&Currentbuf->currentURL);
2956 base = baseURL(Currentbuf);
2957 if ((no_referer_ptr && *no_referer_ptr) ||
2958 base == NULL ||
2959 base->scheme == SCM_LOCAL || base->scheme == SCM_LOCAL_CGI ||
2960 base->scheme == SCM_DATA)
2961 referer = NO_REFERER;
2962 if (referer == NULL)
2963 referer = parsedURL2RefererStr(&Currentbuf->currentURL)->ptr;
2964 buf = loadGeneralFile(url, baseURL(Currentbuf), referer, flag, request);
2965 if (buf == NULL) {
2966 char *emsg = Sprintf("Can't load %s", url)->ptr;
2967 disp_err_message(emsg, FALSE);
2968 return NULL;
2969 }
2970
2971 parseURL2(url, &pu, base);
2972 pushHashHist(URLHist, parsedURL2Str(&pu)->ptr);
2973
2974 if (buf == NO_BUFFER) {
2975 return NULL;
2976 }
2977 if (!on_target) /* open link as an indivisual page */
2978 return loadNormalBuf(buf, TRUE);
2979
2980 if (do_download) /* download (thus no need to render frames) */
2981 return loadNormalBuf(buf, FALSE);
2982
2983 if (target == NULL || /* no target specified (that means this page is not a frame page) */
2984 !strcmp(target, "_top") || /* this link is specified to be opened as an indivisual * page */
2985 !(Currentbuf->bufferprop & BP_FRAME) /* This page is not a frame page */
2986 ) {
2987 return loadNormalBuf(buf, TRUE);
2988 }
2989 nfbuf = Currentbuf->linkBuffer[LB_N_FRAME];
2990 if (nfbuf == NULL) {
2991 /* original page (that contains <frameset> tag) doesn't exist */
2992 return loadNormalBuf(buf, TRUE);
2993 }
2994
2995 f_element = search_frame(nfbuf->frameset, target);
2996 if (f_element == NULL) {
2997 /* specified target doesn't exist in this frameset */
2998 return loadNormalBuf(buf, TRUE);
2999 }
3000
3001 /* frame page */
3002
3003 /* stack current frameset */
3004 pushFrameTree(&(nfbuf->frameQ), copyFrameSet(nfbuf->frameset), Currentbuf);
3005 /* delete frame view buffer */
3006 delBuffer(Currentbuf);
3007 Currentbuf = nfbuf;
3008 /* nfbuf->frameset = copyFrameSet(nfbuf->frameset); */
3009 resetFrameElement(f_element, buf, referer, request);
3010 discardBuffer(buf);
3011 rFrame();
3012 {
3013 Anchor *al = NULL;
3014 char *label = pu.label;
3015
3016 if (label && f_element->element->attr == F_BODY) {
3017 al = searchAnchor(f_element->body->nameList, label);
3018 }
3019 if (!al) {
3020 label = Strnew_m_charp("_", target, NULL)->ptr;
3021 al = searchURLLabel(Currentbuf, label);
3022 }
3023 if (al) {
3024 gotoLine(Currentbuf, al->start.line);
3025 if (label_topline)
3026 Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine,
3027 Currentbuf->currentLine->
3028 linenumber -
3029 Currentbuf->topLine->linenumber,
3030 FALSE);
3031 Currentbuf->pos = al->start.pos;
3032 arrangeCursor(Currentbuf);
3033 }
3034 }
3035 displayBuffer(Currentbuf, B_NORMAL);
3036 return buf;
3037 }
3038
3039 static void
gotoLabel(char * label)3040 gotoLabel(char *label)
3041 {
3042 Buffer *buf;
3043 Anchor *al;
3044 int i;
3045
3046 al = searchURLLabel(Currentbuf, label);
3047 if (al == NULL) {
3048 /* FIXME: gettextize? */
3049 disp_message(Sprintf("%s is not found", label)->ptr, TRUE);
3050 return;
3051 }
3052 buf = newBuffer(Currentbuf->width);
3053 copyBuffer(buf, Currentbuf);
3054 for (i = 0; i < MAX_LB; i++)
3055 buf->linkBuffer[i] = NULL;
3056 buf->currentURL.label = allocStr(label, -1);
3057 pushHashHist(URLHist, parsedURL2Str(&buf->currentURL)->ptr);
3058 (*buf->clone)++;
3059 pushBuffer(buf);
3060 gotoLine(Currentbuf, al->start.line);
3061 if (label_topline)
3062 Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine,
3063 Currentbuf->currentLine->linenumber
3064 - Currentbuf->topLine->linenumber,
3065 FALSE);
3066 Currentbuf->pos = al->start.pos;
3067 arrangeCursor(Currentbuf);
3068 displayBuffer(Currentbuf, B_FORCE_REDRAW);
3069 return;
3070 }
3071
3072 static int
handleMailto(char * url)3073 handleMailto(char *url)
3074 {
3075 Str to;
3076 char *pos;
3077
3078 if (strncasecmp(url, "mailto:", 7))
3079 return 0;
3080 #ifdef USE_W3MMAILER
3081 if (! non_null(Mailer) || MailtoOptions == MAILTO_OPTIONS_USE_W3MMAILER)
3082 return 0;
3083 #else
3084 if (!non_null(Mailer)) {
3085 /* FIXME: gettextize? */
3086 disp_err_message("no mailer is specified", TRUE);
3087 return 1;
3088 }
3089 #endif
3090
3091 /* invoke external mailer */
3092 if (MailtoOptions == MAILTO_OPTIONS_USE_MAILTO_URL) {
3093 to = Strnew_charp(html_unquote(url));
3094 } else {
3095 to = Strnew_charp(url + 7);
3096 if ((pos = strchr(to->ptr, '?')) != NULL)
3097 Strtruncate(to, pos - to->ptr);
3098 }
3099 fmTerm();
3100 system(myExtCommand(Mailer, shell_quote(file_unquote(to->ptr)),
3101 FALSE)->ptr);
3102 fmInit();
3103 displayBuffer(Currentbuf, B_FORCE_REDRAW);
3104 pushHashHist(URLHist, url);
3105 return 1;
3106 }
3107
3108 /* follow HREF link */
3109 DEFUN(followA, GOTO_LINK, "Follow current hyperlink in a new buffer")
3110 {
3111 Anchor *a;
3112 ParsedURL u;
3113 #ifdef USE_IMAGE
3114 int x = 0, y = 0, map = 0;
3115 #endif
3116 char *url;
3117
3118 if (Currentbuf->firstLine == NULL)
3119 return;
3120
3121 #ifdef USE_IMAGE
3122 a = retrieveCurrentImg(Currentbuf);
3123 if (a && a->image && a->image->map) {
3124 _followForm(FALSE);
3125 return;
3126 }
3127 if (a && a->image && a->image->ismap) {
3128 getMapXY(Currentbuf, a, &x, &y);
3129 map = 1;
3130 }
3131 #else
3132 a = retrieveCurrentMap(Currentbuf);
3133 if (a) {
3134 _followForm(FALSE);
3135 return;
3136 }
3137 #endif
3138 a = retrieveCurrentAnchor(Currentbuf);
3139 if (a == NULL) {
3140 _followForm(FALSE);
3141 return;
3142 }
3143 if (*a->url == '#') { /* index within this buffer */
3144 gotoLabel(a->url + 1);
3145 return;
3146 }
3147 parseURL2(a->url, &u, baseURL(Currentbuf));
3148 if (Strcmp(parsedURL2Str(&u), parsedURL2Str(&Currentbuf->currentURL)) == 0) {
3149 /* index within this buffer */
3150 if (u.label) {
3151 gotoLabel(u.label);
3152 return;
3153 }
3154 }
3155 if (handleMailto(a->url))
3156 return;
3157 #if 0
3158 else if (!strncasecmp(a->url, "news:", 5) && strchr(a->url, '@') == NULL) {
3159 /* news:newsgroup is not supported */
3160 /* FIXME: gettextize? */
3161 disp_err_message("news:newsgroup_name is not supported", TRUE);
3162 return;
3163 }
3164 #endif /* USE_NNTP */
3165 url = a->url;
3166 #ifdef USE_IMAGE
3167 if (map)
3168 url = Sprintf("%s?%d,%d", a->url, x, y)->ptr;
3169 #endif
3170
3171 if (check_target && open_tab_blank && a->target &&
3172 (!strcasecmp(a->target, "_new") || !strcasecmp(a->target, "_blank"))) {
3173 Buffer *buf;
3174
3175 _newT();
3176 buf = Currentbuf;
3177 loadLink(url, a->target, a->referer, NULL);
3178 if (buf != Currentbuf)
3179 delBuffer(buf);
3180 else
3181 deleteTab(CurrentTab);
3182 displayBuffer(Currentbuf, B_FORCE_REDRAW);
3183 return;
3184 }
3185 loadLink(url, a->target, a->referer, NULL);
3186 displayBuffer(Currentbuf, B_NORMAL);
3187 }
3188
3189 /* follow HREF link in the buffer */
3190 void
bufferA(void)3191 bufferA(void)
3192 {
3193 on_target = FALSE;
3194 followA();
3195 on_target = TRUE;
3196 }
3197
3198 /* view inline image */
3199 DEFUN(followI, VIEW_IMAGE, "Display image in viewer")
3200 {
3201 Anchor *a;
3202 Buffer *buf;
3203
3204 if (Currentbuf->firstLine == NULL)
3205 return;
3206
3207 a = retrieveCurrentImg(Currentbuf);
3208 if (a == NULL)
3209 return;
3210 /* FIXME: gettextize? */
3211 message(Sprintf("loading %s", a->url)->ptr, 0, 0);
3212 refresh();
3213 buf = loadGeneralFile(a->url, baseURL(Currentbuf), NULL, 0, NULL);
3214 if (buf == NULL) {
3215 /* FIXME: gettextize? */
3216 char *emsg = Sprintf("Can't load %s", a->url)->ptr;
3217 disp_err_message(emsg, FALSE);
3218 }
3219 else if (buf != NO_BUFFER) {
3220 pushBuffer(buf);
3221 }
3222 displayBuffer(Currentbuf, B_NORMAL);
3223 }
3224
3225 static FormItemList *
save_submit_formlist(FormItemList * src)3226 save_submit_formlist(FormItemList *src)
3227 {
3228 FormList *list;
3229 FormList *srclist;
3230 FormItemList *srcitem;
3231 FormItemList *item;
3232 FormItemList *ret = NULL;
3233 #ifdef MENU_SELECT
3234 FormSelectOptionItem *opt;
3235 FormSelectOptionItem *curopt;
3236 FormSelectOptionItem *srcopt;
3237 #endif /* MENU_SELECT */
3238
3239 if (src == NULL)
3240 return NULL;
3241 srclist = src->parent;
3242 list = New(FormList);
3243 list->method = srclist->method;
3244 list->action = Strdup(srclist->action);
3245 #ifdef USE_M17N
3246 list->charset = srclist->charset;
3247 #endif
3248 list->enctype = srclist->enctype;
3249 list->nitems = srclist->nitems;
3250 list->body = srclist->body;
3251 list->boundary = srclist->boundary;
3252 list->length = srclist->length;
3253
3254 for (srcitem = srclist->item; srcitem; srcitem = srcitem->next) {
3255 item = New(FormItemList);
3256 item->type = srcitem->type;
3257 item->name = Strdup(srcitem->name);
3258 item->value = Strdup(srcitem->value);
3259 item->checked = srcitem->checked;
3260 item->accept = srcitem->accept;
3261 item->size = srcitem->size;
3262 item->rows = srcitem->rows;
3263 item->maxlength = srcitem->maxlength;
3264 item->readonly = srcitem->readonly;
3265 #ifdef MENU_SELECT
3266 opt = curopt = NULL;
3267 for (srcopt = srcitem->select_option; srcopt; srcopt = srcopt->next) {
3268 if (!srcopt->checked)
3269 continue;
3270 opt = New(FormSelectOptionItem);
3271 opt->value = Strdup(srcopt->value);
3272 opt->label = Strdup(srcopt->label);
3273 opt->checked = srcopt->checked;
3274 if (item->select_option == NULL) {
3275 item->select_option = curopt = opt;
3276 }
3277 else {
3278 curopt->next = opt;
3279 curopt = curopt->next;
3280 }
3281 }
3282 item->select_option = opt;
3283 if (srcitem->label)
3284 item->label = Strdup(srcitem->label);
3285 #endif /* MENU_SELECT */
3286 item->parent = list;
3287 item->next = NULL;
3288
3289 if (list->lastitem == NULL) {
3290 list->item = list->lastitem = item;
3291 }
3292 else {
3293 list->lastitem->next = item;
3294 list->lastitem = item;
3295 }
3296
3297 if (srcitem == src)
3298 ret = item;
3299 }
3300
3301 return ret;
3302 }
3303
3304 #ifdef USE_M17N
3305 static Str
conv_form_encoding(Str val,FormItemList * fi,Buffer * buf)3306 conv_form_encoding(Str val, FormItemList *fi, Buffer *buf)
3307 {
3308 wc_ces charset = SystemCharset;
3309
3310 if (fi->parent->charset)
3311 charset = fi->parent->charset;
3312 else if (buf->document_charset && buf->document_charset != WC_CES_US_ASCII)
3313 charset = buf->document_charset;
3314 return wc_Str_conv_strict(val, InnerCharset, charset);
3315 }
3316 #else
3317 #define conv_form_encoding(val, fi, buf) (val)
3318 #endif
3319
3320 static void
query_from_followform(Str * query,FormItemList * fi,int multipart)3321 query_from_followform(Str *query, FormItemList *fi, int multipart)
3322 {
3323 FormItemList *f2;
3324 FILE *body = NULL;
3325
3326 if (multipart) {
3327 *query = tmpfname(TMPF_DFL, NULL);
3328 body = fopen((*query)->ptr, "w");
3329 if (body == NULL) {
3330 return;
3331 }
3332 fi->parent->body = (*query)->ptr;
3333 fi->parent->boundary =
3334 Sprintf("------------------------------%d%ld%ld%ld", CurrentPid,
3335 fi->parent, fi->parent->body, fi->parent->boundary)->ptr;
3336 }
3337 *query = Strnew();
3338 for (f2 = fi->parent->item; f2; f2 = f2->next) {
3339 if (f2->name == NULL)
3340 continue;
3341 /* <ISINDEX> is translated into single text form */
3342 if (f2->name->length == 0 &&
3343 (multipart || f2->type != FORM_INPUT_TEXT))
3344 continue;
3345 switch (f2->type) {
3346 case FORM_INPUT_RESET:
3347 /* do nothing */
3348 continue;
3349 case FORM_INPUT_SUBMIT:
3350 case FORM_INPUT_IMAGE:
3351 if (f2 != fi || f2->value == NULL)
3352 continue;
3353 break;
3354 case FORM_INPUT_RADIO:
3355 case FORM_INPUT_CHECKBOX:
3356 if (!f2->checked)
3357 continue;
3358 }
3359 if (multipart) {
3360 if (f2->type == FORM_INPUT_IMAGE) {
3361 int x = 0, y = 0;
3362 #ifdef USE_IMAGE
3363 getMapXY(Currentbuf, retrieveCurrentImg(Currentbuf), &x, &y);
3364 #endif
3365 *query = Strdup(conv_form_encoding(f2->name, fi, Currentbuf));
3366 Strcat_charp(*query, ".x");
3367 form_write_data(body, fi->parent->boundary, (*query)->ptr,
3368 Sprintf("%d", x)->ptr);
3369 *query = Strdup(conv_form_encoding(f2->name, fi, Currentbuf));
3370 Strcat_charp(*query, ".y");
3371 form_write_data(body, fi->parent->boundary, (*query)->ptr,
3372 Sprintf("%d", y)->ptr);
3373 }
3374 else if (f2->name && f2->name->length > 0 && f2->value != NULL) {
3375 /* not IMAGE */
3376 *query = conv_form_encoding(f2->value, fi, Currentbuf);
3377 if (f2->type == FORM_INPUT_FILE)
3378 form_write_from_file(body, fi->parent->boundary,
3379 conv_form_encoding(f2->name, fi,
3380 Currentbuf)->ptr,
3381 (*query)->ptr,
3382 Str_conv_to_system(f2->value)->ptr);
3383 else
3384 form_write_data(body, fi->parent->boundary,
3385 conv_form_encoding(f2->name, fi,
3386 Currentbuf)->ptr,
3387 (*query)->ptr);
3388 }
3389 }
3390 else {
3391 /* not multipart */
3392 if (f2->type == FORM_INPUT_IMAGE) {
3393 int x = 0, y = 0;
3394 #ifdef USE_IMAGE
3395 getMapXY(Currentbuf, retrieveCurrentImg(Currentbuf), &x, &y);
3396 #endif
3397 Strcat(*query,
3398 Str_form_quote(conv_form_encoding
3399 (f2->name, fi, Currentbuf)));
3400 Strcat(*query, Sprintf(".x=%d&", x));
3401 Strcat(*query,
3402 Str_form_quote(conv_form_encoding
3403 (f2->name, fi, Currentbuf)));
3404 Strcat(*query, Sprintf(".y=%d", y));
3405 }
3406 else {
3407 /* not IMAGE */
3408 if (f2->name && f2->name->length > 0) {
3409 Strcat(*query,
3410 Str_form_quote(conv_form_encoding
3411 (f2->name, fi, Currentbuf)));
3412 Strcat_char(*query, '=');
3413 }
3414 if (f2->value != NULL) {
3415 if (fi->parent->method == FORM_METHOD_INTERNAL)
3416 Strcat(*query, Str_form_quote(f2->value));
3417 else {
3418 Strcat(*query,
3419 Str_form_quote(conv_form_encoding
3420 (f2->value, fi, Currentbuf)));
3421 }
3422 }
3423 }
3424 if (f2->next)
3425 Strcat_char(*query, '&');
3426 }
3427 }
3428 if (multipart) {
3429 fprintf(body, "--%s--\r\n", fi->parent->boundary);
3430 fclose(body);
3431 }
3432 else {
3433 /* remove trailing & */
3434 while (Strlastchar(*query) == '&')
3435 Strshrink(*query, 1);
3436 }
3437 }
3438
3439 /* submit form */
3440 DEFUN(submitForm, SUBMIT, "Submit form")
3441 {
3442 _followForm(TRUE);
3443 }
3444
3445 /* process form */
3446 void
followForm(void)3447 followForm(void)
3448 {
3449 _followForm(FALSE);
3450 }
3451
3452 static void
_followForm(int submit)3453 _followForm(int submit)
3454 {
3455 Anchor *a, *a2;
3456 char *p;
3457 FormItemList *fi, *f2;
3458 Str tmp, tmp2;
3459 int multipart = 0, i;
3460
3461 if (Currentbuf->firstLine == NULL)
3462 return;
3463
3464 a = retrieveCurrentForm(Currentbuf);
3465 if (a == NULL)
3466 return;
3467 fi = (FormItemList *)a->url;
3468 switch (fi->type) {
3469 case FORM_INPUT_TEXT:
3470 if (submit)
3471 goto do_submit;
3472 if (fi->readonly)
3473 /* FIXME: gettextize? */
3474 disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
3475 /* FIXME: gettextize? */
3476 p = inputStrHist("TEXT:", fi->value ? fi->value->ptr : NULL, TextHist);
3477 if (p == NULL || fi->readonly)
3478 break;
3479 fi->value = Strnew_charp(p);
3480 formUpdateBuffer(a, Currentbuf, fi);
3481 if (fi->accept || fi->parent->nitems == 1)
3482 goto do_submit;
3483 break;
3484 case FORM_INPUT_FILE:
3485 if (submit)
3486 goto do_submit;
3487 if (fi->readonly)
3488 /* FIXME: gettextize? */
3489 disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
3490 /* FIXME: gettextize? */
3491 p = inputFilenameHist("Filename:", fi->value ? fi->value->ptr : NULL,
3492 NULL);
3493 if (p == NULL || fi->readonly)
3494 break;
3495 fi->value = Strnew_charp(p);
3496 formUpdateBuffer(a, Currentbuf, fi);
3497 if (fi->accept || fi->parent->nitems == 1)
3498 goto do_submit;
3499 break;
3500 case FORM_INPUT_PASSWORD:
3501 if (submit)
3502 goto do_submit;
3503 if (fi->readonly) {
3504 /* FIXME: gettextize? */
3505 disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
3506 break;
3507 }
3508 /* FIXME: gettextize? */
3509 p = inputLine("Password:", fi->value ? fi->value->ptr : NULL,
3510 IN_PASSWORD);
3511 if (p == NULL)
3512 break;
3513 fi->value = Strnew_charp(p);
3514 formUpdateBuffer(a, Currentbuf, fi);
3515 if (fi->accept)
3516 goto do_submit;
3517 break;
3518 case FORM_TEXTAREA:
3519 if (submit)
3520 goto do_submit;
3521 if (fi->readonly)
3522 /* FIXME: gettextize? */
3523 disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
3524 input_textarea(fi);
3525 formUpdateBuffer(a, Currentbuf, fi);
3526 break;
3527 case FORM_INPUT_RADIO:
3528 if (submit)
3529 goto do_submit;
3530 if (fi->readonly) {
3531 /* FIXME: gettextize? */
3532 disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
3533 break;
3534 }
3535 formRecheckRadio(a, Currentbuf, fi);
3536 break;
3537 case FORM_INPUT_CHECKBOX:
3538 if (submit)
3539 goto do_submit;
3540 if (fi->readonly) {
3541 /* FIXME: gettextize? */
3542 disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
3543 break;
3544 }
3545 fi->checked = !fi->checked;
3546 formUpdateBuffer(a, Currentbuf, fi);
3547 break;
3548 #ifdef MENU_SELECT
3549 case FORM_SELECT:
3550 if (submit)
3551 goto do_submit;
3552 if (!formChooseOptionByMenu(fi,
3553 Currentbuf->cursorX - Currentbuf->pos +
3554 a->start.pos + Currentbuf->rootX,
3555 Currentbuf->cursorY + Currentbuf->rootY))
3556 break;
3557 formUpdateBuffer(a, Currentbuf, fi);
3558 if (fi->parent->nitems == 1)
3559 goto do_submit;
3560 break;
3561 #endif /* MENU_SELECT */
3562 case FORM_INPUT_IMAGE:
3563 case FORM_INPUT_SUBMIT:
3564 case FORM_INPUT_BUTTON:
3565 do_submit:
3566 tmp = Strnew();
3567 multipart = (fi->parent->method == FORM_METHOD_POST &&
3568 fi->parent->enctype == FORM_ENCTYPE_MULTIPART);
3569 query_from_followform(&tmp, fi, multipart);
3570
3571 tmp2 = Strdup(fi->parent->action);
3572 if (!Strcmp_charp(tmp2, "!CURRENT_URL!")) {
3573 /* It means "current URL" */
3574 tmp2 = parsedURL2Str(&Currentbuf->currentURL);
3575 if ((p = strchr(tmp2->ptr, '?')) != NULL)
3576 Strshrink(tmp2, (tmp2->ptr + tmp2->length) - p);
3577 }
3578
3579 if (fi->parent->method == FORM_METHOD_GET) {
3580 if ((p = strchr(tmp2->ptr, '?')) != NULL)
3581 Strshrink(tmp2, (tmp2->ptr + tmp2->length) - p);
3582 Strcat_charp(tmp2, "?");
3583 Strcat(tmp2, tmp);
3584 loadLink(tmp2->ptr, a->target, NULL, NULL);
3585 }
3586 else if (fi->parent->method == FORM_METHOD_POST) {
3587 Buffer *buf;
3588 if (multipart) {
3589 struct stat st;
3590 stat(fi->parent->body, &st);
3591 fi->parent->length = st.st_size;
3592 }
3593 else {
3594 fi->parent->body = tmp->ptr;
3595 fi->parent->length = tmp->length;
3596 }
3597 buf = loadLink(tmp2->ptr, a->target, NULL, fi->parent);
3598 if (multipart) {
3599 unlink(fi->parent->body);
3600 }
3601 if (buf && !(buf->bufferprop & BP_REDIRECTED)) { /* buf must be Currentbuf */
3602 /* BP_REDIRECTED means that the buffer is obtained through
3603 * Location: header. In this case, buf->form_submit must not be set
3604 * because the page is not loaded by POST method but GET method.
3605 */
3606 buf->form_submit = save_submit_formlist(fi);
3607 }
3608 }
3609 else if ((fi->parent->method == FORM_METHOD_INTERNAL && (!Strcmp_charp(fi->parent->action, "map") || !Strcmp_charp(fi->parent->action, "none"))) || Currentbuf->bufferprop & BP_INTERNAL) { /* internal */
3610 do_internal(tmp2->ptr, tmp->ptr);
3611 }
3612 else {
3613 disp_err_message("Can't send form because of illegal method.",
3614 FALSE);
3615 }
3616 break;
3617 case FORM_INPUT_RESET:
3618 for (i = 0; i < Currentbuf->formitem->nanchor; i++) {
3619 a2 = &Currentbuf->formitem->anchors[i];
3620 f2 = (FormItemList *)a2->url;
3621 if (f2->parent == fi->parent &&
3622 f2->name && f2->value &&
3623 f2->type != FORM_INPUT_SUBMIT &&
3624 f2->type != FORM_INPUT_HIDDEN &&
3625 f2->type != FORM_INPUT_RESET) {
3626 f2->value = f2->init_value;
3627 f2->checked = f2->init_checked;
3628 #ifdef MENU_SELECT
3629 f2->label = f2->init_label;
3630 f2->selected = f2->init_selected;
3631 #endif /* MENU_SELECT */
3632 formUpdateBuffer(a2, Currentbuf, f2);
3633 }
3634 }
3635 break;
3636 case FORM_INPUT_HIDDEN:
3637 default:
3638 break;
3639 }
3640 displayBuffer(Currentbuf, B_FORCE_REDRAW);
3641 }
3642
3643 /* go to the top anchor */
3644 DEFUN(topA, LINK_BEGIN, "Move to the first hyperlink")
3645 {
3646 HmarkerList *hl = Currentbuf->hmarklist;
3647 BufferPoint *po;
3648 Anchor *an;
3649 int hseq = 0;
3650
3651 if (Currentbuf->firstLine == NULL)
3652 return;
3653 if (!hl || hl->nmark == 0)
3654 return;
3655
3656 if (prec_num > hl->nmark)
3657 hseq = hl->nmark - 1;
3658 else if (prec_num > 0)
3659 hseq = prec_num - 1;
3660 do {
3661 if (hseq >= hl->nmark)
3662 return;
3663 po = hl->marks + hseq;
3664 an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
3665 if (an == NULL)
3666 an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos);
3667 hseq++;
3668 } while (an == NULL);
3669
3670 gotoLine(Currentbuf, po->line);
3671 Currentbuf->pos = po->pos;
3672 arrangeCursor(Currentbuf);
3673 displayBuffer(Currentbuf, B_NORMAL);
3674 }
3675
3676 /* go to the last anchor */
3677 DEFUN(lastA, LINK_END, "Move to the last hyperlink")
3678 {
3679 HmarkerList *hl = Currentbuf->hmarklist;
3680 BufferPoint *po;
3681 Anchor *an;
3682 int hseq;
3683
3684 if (Currentbuf->firstLine == NULL)
3685 return;
3686 if (!hl || hl->nmark == 0)
3687 return;
3688
3689 if (prec_num >= hl->nmark)
3690 hseq = 0;
3691 else if (prec_num > 0)
3692 hseq = hl->nmark - prec_num;
3693 else
3694 hseq = hl->nmark - 1;
3695 do {
3696 if (hseq < 0)
3697 return;
3698 po = hl->marks + hseq;
3699 an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
3700 if (an == NULL)
3701 an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos);
3702 hseq--;
3703 } while (an == NULL);
3704
3705 gotoLine(Currentbuf, po->line);
3706 Currentbuf->pos = po->pos;
3707 arrangeCursor(Currentbuf);
3708 displayBuffer(Currentbuf, B_NORMAL);
3709 }
3710
3711 /* go to the nth anchor */
3712 DEFUN(nthA, LINK_N, "Go to the nth link")
3713 {
3714 HmarkerList *hl = Currentbuf->hmarklist;
3715 BufferPoint *po;
3716 Anchor *an;
3717
3718 int n = searchKeyNum();
3719 if (n < 0 || n > hl->nmark) return;
3720
3721 if (Currentbuf->firstLine == NULL)
3722 return;
3723 if (!hl || hl->nmark == 0)
3724 return;
3725
3726 po = hl->marks + n-1;
3727 an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
3728 if (an == NULL)
3729 an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos);
3730 if (an == NULL) return;
3731
3732 gotoLine(Currentbuf, po->line);
3733 Currentbuf->pos = po->pos;
3734 arrangeCursor(Currentbuf);
3735 displayBuffer(Currentbuf, B_NORMAL);
3736 }
3737
3738 /* go to the next anchor */
3739 DEFUN(nextA, NEXT_LINK, "Move to the next hyperlink")
3740 {
3741 _nextA(FALSE);
3742 }
3743
3744 /* go to the previous anchor */
3745 DEFUN(prevA, PREV_LINK, "Move to the previous hyperlink")
3746 {
3747 _prevA(FALSE);
3748 }
3749
3750 /* go to the next visited anchor */
3751 DEFUN(nextVA, NEXT_VISITED, "Move to the next visited hyperlink")
3752 {
3753 _nextA(TRUE);
3754 }
3755
3756 /* go to the previous visited anchor */
3757 DEFUN(prevVA, PREV_VISITED, "Move to the previous visited hyperlink")
3758 {
3759 _prevA(TRUE);
3760 }
3761
3762 /* go to the next [visited] anchor */
3763 static void
_nextA(int visited)3764 _nextA(int visited)
3765 {
3766 HmarkerList *hl = Currentbuf->hmarklist;
3767 BufferPoint *po;
3768 Anchor *an, *pan;
3769 int i, x, y, n = searchKeyNum();
3770 ParsedURL url;
3771
3772 if (Currentbuf->firstLine == NULL)
3773 return;
3774 if (!hl || hl->nmark == 0)
3775 return;
3776
3777 an = retrieveCurrentAnchor(Currentbuf);
3778 if (visited != TRUE && an == NULL)
3779 an = retrieveCurrentForm(Currentbuf);
3780
3781 y = Currentbuf->currentLine->linenumber;
3782 x = Currentbuf->pos;
3783
3784 if (visited == TRUE) {
3785 n = hl->nmark;
3786 }
3787
3788 for (i = 0; i < n; i++) {
3789 pan = an;
3790 if (an && an->hseq >= 0) {
3791 int hseq = an->hseq + 1;
3792 do {
3793 if (hseq >= hl->nmark) {
3794 if (visited == TRUE)
3795 return;
3796 an = pan;
3797 goto _end;
3798 }
3799 po = &hl->marks[hseq];
3800 an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
3801 if (visited != TRUE && an == NULL)
3802 an = retrieveAnchor(Currentbuf->formitem, po->line,
3803 po->pos);
3804 hseq++;
3805 if (visited == TRUE && an) {
3806 parseURL2(an->url, &url, baseURL(Currentbuf));
3807 if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
3808 goto _end;
3809 }
3810 }
3811 } while (an == NULL || an == pan);
3812 }
3813 else {
3814 an = closest_next_anchor(Currentbuf->href, NULL, x, y);
3815 if (visited != TRUE)
3816 an = closest_next_anchor(Currentbuf->formitem, an, x, y);
3817 if (an == NULL) {
3818 if (visited == TRUE)
3819 return;
3820 an = pan;
3821 break;
3822 }
3823 x = an->start.pos;
3824 y = an->start.line;
3825 if (visited == TRUE) {
3826 parseURL2(an->url, &url, baseURL(Currentbuf));
3827 if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
3828 goto _end;
3829 }
3830 }
3831 }
3832 }
3833 if (visited == TRUE)
3834 return;
3835
3836 _end:
3837 if (an == NULL || an->hseq < 0)
3838 return;
3839 po = &hl->marks[an->hseq];
3840 gotoLine(Currentbuf, po->line);
3841 Currentbuf->pos = po->pos;
3842 arrangeCursor(Currentbuf);
3843 displayBuffer(Currentbuf, B_NORMAL);
3844 }
3845
3846 /* go to the previous anchor */
3847 static void
_prevA(int visited)3848 _prevA(int visited)
3849 {
3850 HmarkerList *hl = Currentbuf->hmarklist;
3851 BufferPoint *po;
3852 Anchor *an, *pan;
3853 int i, x, y, n = searchKeyNum();
3854 ParsedURL url;
3855
3856 if (Currentbuf->firstLine == NULL)
3857 return;
3858 if (!hl || hl->nmark == 0)
3859 return;
3860
3861 an = retrieveCurrentAnchor(Currentbuf);
3862 if (visited != TRUE && an == NULL)
3863 an = retrieveCurrentForm(Currentbuf);
3864
3865 y = Currentbuf->currentLine->linenumber;
3866 x = Currentbuf->pos;
3867
3868 if (visited == TRUE) {
3869 n = hl->nmark;
3870 }
3871
3872 for (i = 0; i < n; i++) {
3873 pan = an;
3874 if (an && an->hseq >= 0) {
3875 int hseq = an->hseq - 1;
3876 do {
3877 if (hseq < 0) {
3878 if (visited == TRUE)
3879 return;
3880 an = pan;
3881 goto _end;
3882 }
3883 po = hl->marks + hseq;
3884 an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
3885 if (visited != TRUE && an == NULL)
3886 an = retrieveAnchor(Currentbuf->formitem, po->line,
3887 po->pos);
3888 hseq--;
3889 if (visited == TRUE && an) {
3890 parseURL2(an->url, &url, baseURL(Currentbuf));
3891 if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
3892 goto _end;
3893 }
3894 }
3895 } while (an == NULL || an == pan);
3896 }
3897 else {
3898 an = closest_prev_anchor(Currentbuf->href, NULL, x, y);
3899 if (visited != TRUE)
3900 an = closest_prev_anchor(Currentbuf->formitem, an, x, y);
3901 if (an == NULL) {
3902 if (visited == TRUE)
3903 return;
3904 an = pan;
3905 break;
3906 }
3907 x = an->start.pos;
3908 y = an->start.line;
3909 if (visited == TRUE && an) {
3910 parseURL2(an->url, &url, baseURL(Currentbuf));
3911 if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) {
3912 goto _end;
3913 }
3914 }
3915 }
3916 }
3917 if (visited == TRUE)
3918 return;
3919
3920 _end:
3921 if (an == NULL || an->hseq < 0)
3922 return;
3923 po = hl->marks + an->hseq;
3924 gotoLine(Currentbuf, po->line);
3925 Currentbuf->pos = po->pos;
3926 arrangeCursor(Currentbuf);
3927 displayBuffer(Currentbuf, B_NORMAL);
3928 }
3929
3930 /* go to the next left/right anchor */
3931 static void
nextX(int d,int dy)3932 nextX(int d, int dy)
3933 {
3934 HmarkerList *hl = Currentbuf->hmarklist;
3935 Anchor *an, *pan;
3936 Line *l;
3937 int i, x, y, n = searchKeyNum();
3938
3939 if (Currentbuf->firstLine == NULL)
3940 return;
3941 if (!hl || hl->nmark == 0)
3942 return;
3943
3944 an = retrieveCurrentAnchor(Currentbuf);
3945 if (an == NULL)
3946 an = retrieveCurrentForm(Currentbuf);
3947
3948 l = Currentbuf->currentLine;
3949 x = Currentbuf->pos;
3950 y = l->linenumber;
3951 pan = NULL;
3952 for (i = 0; i < n; i++) {
3953 if (an)
3954 x = (d > 0) ? an->end.pos : an->start.pos - 1;
3955 an = NULL;
3956 while (1) {
3957 for (; x >= 0 && x < l->len; x += d) {
3958 an = retrieveAnchor(Currentbuf->href, y, x);
3959 if (!an)
3960 an = retrieveAnchor(Currentbuf->formitem, y, x);
3961 if (an) {
3962 pan = an;
3963 break;
3964 }
3965 }
3966 if (!dy || an)
3967 break;
3968 l = (dy > 0) ? l->next : l->prev;
3969 if (!l)
3970 break;
3971 x = (d > 0) ? 0 : l->len - 1;
3972 y = l->linenumber;
3973 }
3974 if (!an)
3975 break;
3976 }
3977
3978 if (pan == NULL)
3979 return;
3980 gotoLine(Currentbuf, y);
3981 Currentbuf->pos = pan->start.pos;
3982 arrangeCursor(Currentbuf);
3983 displayBuffer(Currentbuf, B_NORMAL);
3984 }
3985
3986 /* go to the next downward/upward anchor */
3987 static void
nextY(int d)3988 nextY(int d)
3989 {
3990 HmarkerList *hl = Currentbuf->hmarklist;
3991 Anchor *an, *pan;
3992 int i, x, y, n = searchKeyNum();
3993 int hseq;
3994
3995 if (Currentbuf->firstLine == NULL)
3996 return;
3997 if (!hl || hl->nmark == 0)
3998 return;
3999
4000 an = retrieveCurrentAnchor(Currentbuf);
4001 if (an == NULL)
4002 an = retrieveCurrentForm(Currentbuf);
4003
4004 x = Currentbuf->pos;
4005 y = Currentbuf->currentLine->linenumber + d;
4006 pan = NULL;
4007 hseq = -1;
4008 for (i = 0; i < n; i++) {
4009 if (an)
4010 hseq = abs(an->hseq);
4011 an = NULL;
4012 for (; y >= 0 && y <= Currentbuf->lastLine->linenumber; y += d) {
4013 an = retrieveAnchor(Currentbuf->href, y, x);
4014 if (!an)
4015 an = retrieveAnchor(Currentbuf->formitem, y, x);
4016 if (an && hseq != abs(an->hseq)) {
4017 pan = an;
4018 break;
4019 }
4020 }
4021 if (!an)
4022 break;
4023 }
4024
4025 if (pan == NULL)
4026 return;
4027 gotoLine(Currentbuf, pan->start.line);
4028 arrangeLine(Currentbuf);
4029 displayBuffer(Currentbuf, B_NORMAL);
4030 }
4031
4032 /* go to the next left anchor */
4033 DEFUN(nextL, NEXT_LEFT, "Move left to the next hyperlink")
4034 {
4035 nextX(-1, 0);
4036 }
4037
4038 /* go to the next left-up anchor */
4039 DEFUN(nextLU, NEXT_LEFT_UP, "Move left or upward to the next hyperlink")
4040 {
4041 nextX(-1, -1);
4042 }
4043
4044 /* go to the next right anchor */
4045 DEFUN(nextR, NEXT_RIGHT, "Move right to the next hyperlink")
4046 {
4047 nextX(1, 0);
4048 }
4049
4050 /* go to the next right-down anchor */
4051 DEFUN(nextRD, NEXT_RIGHT_DOWN, "Move right or downward to the next hyperlink")
4052 {
4053 nextX(1, 1);
4054 }
4055
4056 /* go to the next downward anchor */
4057 DEFUN(nextD, NEXT_DOWN, "Move downward to the next hyperlink")
4058 {
4059 nextY(1);
4060 }
4061
4062 /* go to the next upward anchor */
4063 DEFUN(nextU, NEXT_UP, "Move upward to the next hyperlink")
4064 {
4065 nextY(-1);
4066 }
4067
4068 /* go to the next bufferr */
4069 DEFUN(nextBf, NEXT, "Switch to the next buffer")
4070 {
4071 Buffer *buf;
4072 int i;
4073
4074 for (i = 0; i < PREC_NUM; i++) {
4075 buf = prevBuffer(Firstbuf, Currentbuf);
4076 if (!buf) {
4077 if (i == 0)
4078 return;
4079 break;
4080 }
4081 Currentbuf = buf;
4082 }
4083 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4084 }
4085
4086 /* go to the previous bufferr */
4087 DEFUN(prevBf, PREV, "Switch to the previous buffer")
4088 {
4089 Buffer *buf;
4090 int i;
4091
4092 for (i = 0; i < PREC_NUM; i++) {
4093 buf = Currentbuf->nextBuffer;
4094 if (!buf) {
4095 if (i == 0)
4096 return;
4097 break;
4098 }
4099 Currentbuf = buf;
4100 }
4101 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4102 }
4103
4104 static int
checkBackBuffer(Buffer * buf)4105 checkBackBuffer(Buffer *buf)
4106 {
4107 Buffer *fbuf = buf->linkBuffer[LB_N_FRAME];
4108
4109 if (fbuf) {
4110 if (fbuf->frameQ)
4111 return TRUE; /* Currentbuf has stacked frames */
4112 /* when no frames stacked and next is frame source, try next's
4113 * nextBuffer */
4114 if (RenderFrame && fbuf == buf->nextBuffer) {
4115 if (fbuf->nextBuffer != NULL)
4116 return TRUE;
4117 else
4118 return FALSE;
4119 }
4120 }
4121
4122 if (buf->nextBuffer)
4123 return TRUE;
4124
4125 return FALSE;
4126 }
4127
4128 /* delete current buffer and back to the previous buffer */
4129 DEFUN(backBf, BACK, "Close current buffer and return to the one below in stack")
4130 {
4131 Buffer *buf = Currentbuf->linkBuffer[LB_N_FRAME];
4132
4133 if (!checkBackBuffer(Currentbuf)) {
4134 if (close_tab_back && nTab >= 1) {
4135 deleteTab(CurrentTab);
4136 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4137 }
4138 else
4139 /* FIXME: gettextize? */
4140 disp_message("Can't go back...", TRUE);
4141 return;
4142 }
4143
4144 delBuffer(Currentbuf);
4145
4146 if (buf) {
4147 if (buf->frameQ) {
4148 struct frameset *fs;
4149 long linenumber = buf->frameQ->linenumber;
4150 long top = buf->frameQ->top_linenumber;
4151 int pos = buf->frameQ->pos;
4152 int currentColumn = buf->frameQ->currentColumn;
4153 AnchorList *formitem = buf->frameQ->formitem;
4154
4155 fs = popFrameTree(&(buf->frameQ));
4156 deleteFrameSet(buf->frameset);
4157 buf->frameset = fs;
4158
4159 if (buf == Currentbuf) {
4160 rFrame();
4161 Currentbuf->topLine = lineSkip(Currentbuf,
4162 Currentbuf->firstLine, top - 1,
4163 FALSE);
4164 gotoLine(Currentbuf, linenumber);
4165 Currentbuf->pos = pos;
4166 Currentbuf->currentColumn = currentColumn;
4167 arrangeCursor(Currentbuf);
4168 formResetBuffer(Currentbuf, formitem);
4169 }
4170 }
4171 else if (RenderFrame && buf == Currentbuf) {
4172 delBuffer(Currentbuf);
4173 }
4174 }
4175 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4176 }
4177
4178 DEFUN(deletePrevBuf, DELETE_PREVBUF, "Delete previous buffer (mainly for local CGI-scripts)")
4179 {
4180 Buffer *buf = Currentbuf->nextBuffer;
4181 if (buf)
4182 delBuffer(buf);
4183 }
4184
4185 static void
cmd_loadURL(char * url,ParsedURL * current,char * referer,FormList * request)4186 cmd_loadURL(char *url, ParsedURL *current, char *referer, FormList *request)
4187 {
4188 Buffer *buf;
4189
4190 if (handleMailto(url))
4191 return;
4192 #if 0
4193 if (!strncasecmp(url, "news:", 5) && strchr(url, '@') == NULL) {
4194 /* news:newsgroup is not supported */
4195 /* FIXME: gettextize? */
4196 disp_err_message("news:newsgroup_name is not supported", TRUE);
4197 return;
4198 }
4199 #endif /* USE_NNTP */
4200
4201 refresh();
4202 buf = loadGeneralFile(url, current, referer, 0, request);
4203 if (buf == NULL) {
4204 /* FIXME: gettextize? */
4205 char *emsg = Sprintf("Can't load %s", conv_from_system(url))->ptr;
4206 disp_err_message(emsg, FALSE);
4207 }
4208 else if (buf != NO_BUFFER) {
4209 pushBuffer(buf);
4210 if (RenderFrame && Currentbuf->frameset != NULL)
4211 rFrame();
4212 }
4213 displayBuffer(Currentbuf, B_NORMAL);
4214 }
4215
4216
4217 /* go to specified URL */
4218 static void
goURL0(char * prompt,int relative)4219 goURL0(char *prompt, int relative)
4220 {
4221 char *url, *referer;
4222 ParsedURL p_url, *current;
4223 Buffer *cur_buf = Currentbuf;
4224 const int *no_referer_ptr;
4225
4226 url = searchKeyData();
4227 if (url == NULL) {
4228 Hist *hist = copyHist(URLHist);
4229 Anchor *a;
4230
4231 current = baseURL(Currentbuf);
4232 if (current) {
4233 char *c_url = parsedURL2Str(current)->ptr;
4234 if (DefaultURLString == DEFAULT_URL_CURRENT)
4235 url = url_decode2(c_url, NULL);
4236 else
4237 pushHist(hist, c_url);
4238 }
4239 a = retrieveCurrentAnchor(Currentbuf);
4240 if (a) {
4241 char *a_url;
4242 parseURL2(a->url, &p_url, current);
4243 a_url = parsedURL2Str(&p_url)->ptr;
4244 if (DefaultURLString == DEFAULT_URL_LINK)
4245 url = url_decode2(a_url, Currentbuf);
4246 else
4247 pushHist(hist, a_url);
4248 }
4249 url = inputLineHist(prompt, url, IN_URL, hist);
4250 if (url != NULL)
4251 SKIP_BLANKS(url);
4252 }
4253 if (relative) {
4254 no_referer_ptr = query_SCONF_NO_REFERER_FROM(&Currentbuf->currentURL);
4255 current = baseURL(Currentbuf);
4256 if ((no_referer_ptr && *no_referer_ptr) ||
4257 current == NULL ||
4258 current->scheme == SCM_LOCAL || current->scheme == SCM_LOCAL_CGI ||
4259 current->scheme == SCM_DATA)
4260 referer = NO_REFERER;
4261 else
4262 referer = parsedURL2RefererStr(&Currentbuf->currentURL)->ptr;
4263 url = url_encode(url, current, Currentbuf->document_charset);
4264 }
4265 else {
4266 current = NULL;
4267 referer = NULL;
4268 url = url_encode(url, NULL, 0);
4269 }
4270 if (url == NULL || *url == '\0') {
4271 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4272 return;
4273 }
4274 if (*url == '#') {
4275 gotoLabel(url + 1);
4276 return;
4277 }
4278 parseURL2(url, &p_url, current);
4279 pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr);
4280 cmd_loadURL(url, current, referer, NULL);
4281 if (Currentbuf != cur_buf) /* success */
4282 pushHashHist(URLHist, parsedURL2Str(&Currentbuf->currentURL)->ptr);
4283 }
4284
4285 DEFUN(goURL, GOTO, "Open specified document in a new buffer")
4286 {
4287 goURL0("Goto URL: ", FALSE);
4288 }
4289
4290 DEFUN(goHome, GOTO_HOME, "Open home page in a new buffer")
4291 {
4292 char *url;
4293 if ((url = getenv("HTTP_HOME")) != NULL ||
4294 (url = getenv("WWW_HOME")) != NULL) {
4295 ParsedURL p_url;
4296 Buffer *cur_buf = Currentbuf;
4297 SKIP_BLANKS(url);
4298 url = url_encode(url, NULL, 0);
4299 parseURL2(url, &p_url, NULL);
4300 pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr);
4301 cmd_loadURL(url, NULL, NULL, NULL);
4302 if (Currentbuf != cur_buf) /* success */
4303 pushHashHist(URLHist, parsedURL2Str(&Currentbuf->currentURL)->ptr);
4304 }
4305 }
4306
4307 DEFUN(gorURL, GOTO_RELATIVE, "Go to relative address")
4308 {
4309 goURL0("Goto relative URL: ", TRUE);
4310 }
4311
4312 static void
cmd_loadBuffer(Buffer * buf,int prop,int linkid)4313 cmd_loadBuffer(Buffer *buf, int prop, int linkid)
4314 {
4315 if (buf == NULL) {
4316 disp_err_message("Can't load string", FALSE);
4317 }
4318 else if (buf != NO_BUFFER) {
4319 buf->bufferprop |= (BP_INTERNAL | prop);
4320 if (!(buf->bufferprop & BP_NO_URL))
4321 copyParsedURL(&buf->currentURL, &Currentbuf->currentURL);
4322 if (linkid != LB_NOLINK) {
4323 buf->linkBuffer[REV_LB[linkid]] = Currentbuf;
4324 Currentbuf->linkBuffer[linkid] = buf;
4325 }
4326 pushBuffer(buf);
4327 }
4328 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4329 }
4330
4331 /* load bookmark */
4332 DEFUN(ldBmark, BOOKMARK VIEW_BOOKMARK, "View bookmarks")
4333 {
4334 cmd_loadURL(BookmarkFile, NULL, NO_REFERER, NULL);
4335 }
4336
4337
4338 /* Add current to bookmark */
4339 DEFUN(adBmark, ADD_BOOKMARK, "Add current page to bookmarks")
4340 {
4341 Str tmp;
4342 FormList *request;
4343
4344 tmp = Sprintf("mode=panel&cookie=%s&bmark=%s&url=%s&title=%s"
4345 #ifdef USE_M17N
4346 "&charset=%s"
4347 #endif
4348 ,
4349 (Str_form_quote(localCookie()))->ptr,
4350 (Str_form_quote(Strnew_charp(BookmarkFile)))->ptr,
4351 (Str_form_quote(parsedURL2Str(&Currentbuf->currentURL)))->
4352 ptr,
4353 #ifdef USE_M17N
4354 (Str_form_quote(wc_conv_strict(Currentbuf->buffername,
4355 InnerCharset,
4356 BookmarkCharset)))->ptr,
4357 wc_ces_to_charset(BookmarkCharset));
4358 #else
4359 (Str_form_quote(Strnew_charp(Currentbuf->buffername)))->ptr);
4360 #endif
4361 request = newFormList(NULL, "post", NULL, NULL, NULL, NULL, NULL);
4362 request->body = tmp->ptr;
4363 request->length = tmp->length;
4364 cmd_loadURL("file:///$LIB/" W3MBOOKMARK_CMDNAME, NULL, NO_REFERER,
4365 request);
4366 }
4367
4368 /* option setting */
4369 DEFUN(ldOpt, OPTIONS, "Display options setting panel")
4370 {
4371 cmd_loadBuffer(load_option_panel(), BP_NO_URL, LB_NOLINK);
4372 }
4373
4374 /* set an option */
4375 DEFUN(setOpt, SET_OPTION, "Set option")
4376 {
4377 char *opt;
4378
4379 CurrentKeyData = NULL; /* not allowed in w3m-control: */
4380 opt = searchKeyData();
4381 if (opt == NULL || *opt == '\0' || strchr(opt, '=') == NULL) {
4382 if (opt != NULL && *opt != '\0') {
4383 char *v = get_param_option(opt);
4384 opt = Sprintf("%s=%s", opt, v ? v : "")->ptr;
4385 }
4386 opt = inputStrHist("Set option: ", opt, TextHist);
4387 if (opt == NULL || *opt == '\0') {
4388 displayBuffer(Currentbuf, B_NORMAL);
4389 return;
4390 }
4391 }
4392 if (set_param_option(opt))
4393 sync_with_option();
4394 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
4395 }
4396
4397 /* error message list */
4398 DEFUN(msgs, MSGS, "Display error messages")
4399 {
4400 cmd_loadBuffer(message_list_panel(), BP_NO_URL, LB_NOLINK);
4401 }
4402
4403 /* page info */
4404 DEFUN(pginfo, INFO, "Display information about the current document")
4405 {
4406 Buffer *buf;
4407
4408 if ((buf = Currentbuf->linkBuffer[LB_N_INFO]) != NULL) {
4409 Currentbuf = buf;
4410 displayBuffer(Currentbuf, B_NORMAL);
4411 return;
4412 }
4413 if ((buf = Currentbuf->linkBuffer[LB_INFO]) != NULL)
4414 delBuffer(buf);
4415 buf = page_info_panel(Currentbuf);
4416 cmd_loadBuffer(buf, BP_NORMAL, LB_INFO);
4417 }
4418
4419 void
follow_map(struct parsed_tagarg * arg)4420 follow_map(struct parsed_tagarg *arg)
4421 {
4422 char *name = tag_get_value(arg, "link");
4423 #if defined(MENU_MAP) || defined(USE_IMAGE)
4424 Anchor *an;
4425 MapArea *a;
4426 int x, y;
4427 ParsedURL p_url;
4428
4429 an = retrieveCurrentImg(Currentbuf);
4430 x = Currentbuf->cursorX + Currentbuf->rootX;
4431 y = Currentbuf->cursorY + Currentbuf->rootY;
4432 a = follow_map_menu(Currentbuf, name, an, x, y);
4433 if (a == NULL || a->url == NULL || *(a->url) == '\0') {
4434 #endif
4435 #ifndef MENU_MAP
4436 Buffer *buf = follow_map_panel(Currentbuf, name);
4437
4438 if (buf != NULL)
4439 cmd_loadBuffer(buf, BP_NORMAL, LB_NOLINK);
4440 #endif
4441 #if defined(MENU_MAP) || defined(USE_IMAGE)
4442 return;
4443 }
4444 if (*(a->url) == '#') {
4445 gotoLabel(a->url + 1);
4446 return;
4447 }
4448 parseURL2(a->url, &p_url, baseURL(Currentbuf));
4449 pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr);
4450 if (check_target && open_tab_blank && a->target &&
4451 (!strcasecmp(a->target, "_new") || !strcasecmp(a->target, "_blank"))) {
4452 Buffer *buf;
4453
4454 _newT();
4455 buf = Currentbuf;
4456 cmd_loadURL(a->url, baseURL(Currentbuf),
4457 parsedURL2Str(&Currentbuf->currentURL)->ptr, NULL);
4458 if (buf != Currentbuf)
4459 delBuffer(buf);
4460 else
4461 deleteTab(CurrentTab);
4462 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4463 return;
4464 }
4465 cmd_loadURL(a->url, baseURL(Currentbuf),
4466 parsedURL2Str(&Currentbuf->currentURL)->ptr, NULL);
4467 #endif
4468 }
4469
4470 #ifdef USE_MENU
4471 /* link menu */
4472 DEFUN(linkMn, LINK_MENU, "Pop up link element menu")
4473 {
4474 LinkList *l = link_menu(Currentbuf);
4475 ParsedURL p_url;
4476
4477 if (!l || !l->url)
4478 return;
4479 if (*(l->url) == '#') {
4480 gotoLabel(l->url + 1);
4481 return;
4482 }
4483 parseURL2(l->url, &p_url, baseURL(Currentbuf));
4484 pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr);
4485 cmd_loadURL(l->url, baseURL(Currentbuf),
4486 parsedURL2Str(&Currentbuf->currentURL)->ptr, NULL);
4487 }
4488
4489 static void
anchorMn(Anchor * (* menu_func)(Buffer *),int go)4490 anchorMn(Anchor *(*menu_func) (Buffer *), int go)
4491 {
4492 Anchor *a;
4493 BufferPoint *po;
4494
4495 if (!Currentbuf->href || !Currentbuf->hmarklist)
4496 return;
4497 a = menu_func(Currentbuf);
4498 if (!a || a->hseq < 0)
4499 return;
4500 po = &Currentbuf->hmarklist->marks[a->hseq];
4501 gotoLine(Currentbuf, po->line);
4502 Currentbuf->pos = po->pos;
4503 arrangeCursor(Currentbuf);
4504 displayBuffer(Currentbuf, B_NORMAL);
4505 if (go)
4506 followA();
4507 }
4508
4509 /* accesskey */
4510 DEFUN(accessKey, ACCESSKEY, "Pop up accesskey menu")
4511 {
4512 anchorMn(accesskey_menu, TRUE);
4513 }
4514
4515 /* list menu */
4516 DEFUN(listMn, LIST_MENU, "Pop up menu for hyperlinks to browse to")
4517 {
4518 anchorMn(list_menu, TRUE);
4519 }
4520
4521 DEFUN(movlistMn, MOVE_LIST_MENU, "Pop up menu to navigate between hyperlinks")
4522 {
4523 anchorMn(list_menu, FALSE);
4524 }
4525 #endif
4526
4527 /* link,anchor,image list */
4528 DEFUN(linkLst, LIST, "Show all URLs referenced")
4529 {
4530 Buffer *buf;
4531
4532 buf = link_list_panel(Currentbuf);
4533 if (buf != NULL) {
4534 #ifdef USE_M17N
4535 buf->document_charset = Currentbuf->document_charset;
4536 #endif
4537 cmd_loadBuffer(buf, BP_NORMAL, LB_NOLINK);
4538 }
4539 }
4540
4541 #ifdef USE_COOKIE
4542 /* cookie list */
4543 DEFUN(cooLst, COOKIE, "View cookie list")
4544 {
4545 Buffer *buf;
4546
4547 buf = cookie_list_panel();
4548 if (buf != NULL)
4549 cmd_loadBuffer(buf, BP_NO_URL, LB_NOLINK);
4550 }
4551 #endif /* USE_COOKIE */
4552
4553 #ifdef USE_HISTORY
4554 /* History page */
4555 DEFUN(ldHist, HISTORY, "Show browsing history")
4556 {
4557 cmd_loadBuffer(historyBuffer(URLHist), BP_NO_URL, LB_NOLINK);
4558 }
4559 #endif /* USE_HISTORY */
4560
4561 /* download HREF link */
4562 DEFUN(svA, SAVE_LINK, "Save hyperlink target")
4563 {
4564 CurrentKeyData = NULL; /* not allowed in w3m-control: */
4565 do_download = TRUE;
4566 followA();
4567 do_download = FALSE;
4568 }
4569
4570 /* download IMG link */
4571 DEFUN(svI, SAVE_IMAGE, "Save inline image")
4572 {
4573 CurrentKeyData = NULL; /* not allowed in w3m-control: */
4574 do_download = TRUE;
4575 followI();
4576 do_download = FALSE;
4577 }
4578
4579 /* save buffer */
4580 DEFUN(svBuf, PRINT SAVE_SCREEN, "Save rendered document")
4581 {
4582 char *qfile = NULL, *file;
4583 FILE *f;
4584 int is_pipe;
4585
4586 CurrentKeyData = NULL; /* not allowed in w3m-control: */
4587 file = searchKeyData();
4588 if (file == NULL || *file == '\0') {
4589 /* FIXME: gettextize? */
4590 qfile = inputLineHist("Save buffer to: ", NULL, IN_COMMAND, SaveHist);
4591 if (qfile == NULL || *qfile == '\0') {
4592 displayBuffer(Currentbuf, B_NORMAL);
4593 return;
4594 }
4595 }
4596 file = conv_to_system(qfile ? qfile : file);
4597 if (*file == '|') {
4598 is_pipe = TRUE;
4599 f = popen(file + 1, "w");
4600 }
4601 else {
4602 if (qfile) {
4603 file = unescape_spaces(Strnew_charp(qfile))->ptr;
4604 file = conv_to_system(file);
4605 }
4606 file = expandPath(file);
4607 if (checkOverWrite(file) < 0) {
4608 displayBuffer(Currentbuf, B_NORMAL);
4609 return;
4610 }
4611 f = fopen(file, "w");
4612 is_pipe = FALSE;
4613 }
4614 if (f == NULL) {
4615 /* FIXME: gettextize? */
4616 char *emsg = Sprintf("Can't open %s", conv_from_system(file))->ptr;
4617 disp_err_message(emsg, TRUE);
4618 return;
4619 }
4620 saveBuffer(Currentbuf, f, TRUE);
4621 if (is_pipe)
4622 pclose(f);
4623 else
4624 fclose(f);
4625 displayBuffer(Currentbuf, B_NORMAL);
4626 }
4627
4628 /* save source */
4629 DEFUN(svSrc, DOWNLOAD SAVE, "Save document source")
4630 {
4631 char *file;
4632
4633 if (Currentbuf->sourcefile == NULL)
4634 return;
4635 CurrentKeyData = NULL; /* not allowed in w3m-control: */
4636 PermitSaveToPipe = TRUE;
4637 if (Currentbuf->real_scheme == SCM_LOCAL)
4638 file = conv_from_system(guess_save_name(NULL,
4639 Currentbuf->currentURL.
4640 real_file));
4641 else
4642 file = guess_save_name(Currentbuf, Currentbuf->currentURL.file);
4643 doFileCopy(Currentbuf->sourcefile, file);
4644 PermitSaveToPipe = FALSE;
4645 displayBuffer(Currentbuf, B_NORMAL);
4646 }
4647
4648 static void
_peekURL(int only_img)4649 _peekURL(int only_img)
4650 {
4651
4652 Anchor *a;
4653 ParsedURL pu;
4654 static Str s = NULL;
4655 #ifdef USE_M17N
4656 static Lineprop *p = NULL;
4657 Lineprop *pp;
4658 #endif
4659 static int offset = 0, n;
4660
4661 if (Currentbuf->firstLine == NULL)
4662 return;
4663 if (CurrentKey == prev_key && s != NULL) {
4664 if (s->length - offset >= COLS)
4665 offset++;
4666 else if (s->length <= offset) /* bug ? */
4667 offset = 0;
4668 goto disp;
4669 }
4670 else {
4671 offset = 0;
4672 }
4673 s = NULL;
4674 a = (only_img ? NULL : retrieveCurrentAnchor(Currentbuf));
4675 if (a == NULL) {
4676 a = (only_img ? NULL : retrieveCurrentForm(Currentbuf));
4677 if (a == NULL) {
4678 a = retrieveCurrentImg(Currentbuf);
4679 if (a == NULL)
4680 return;
4681 }
4682 else
4683 s = Strnew_charp(form2str((FormItemList *)a->url));
4684 }
4685 if (s == NULL) {
4686 parseURL2(a->url, &pu, baseURL(Currentbuf));
4687 s = parsedURL2Str(&pu);
4688 }
4689 if (DecodeURL)
4690 s = Strnew_charp(url_decode2(s->ptr, Currentbuf));
4691 #ifdef USE_M17N
4692 s = checkType(s, &pp, NULL);
4693 p = NewAtom_N(Lineprop, s->length);
4694 bcopy((void *)pp, (void *)p, s->length * sizeof(Lineprop));
4695 #endif
4696 disp:
4697 n = searchKeyNum();
4698 if (n > 1 && s->length > (n - 1) * (COLS - 1))
4699 offset = (n - 1) * (COLS - 1);
4700 #ifdef USE_M17N
4701 while (offset < s->length && p[offset] & PC_WCHAR2)
4702 offset++;
4703 #endif
4704 disp_message_nomouse(&s->ptr[offset], TRUE);
4705 }
4706
4707 /* peek URL */
4708 DEFUN(peekURL, PEEK_LINK, "Show target address")
4709 {
4710 _peekURL(0);
4711 }
4712
4713 /* peek URL of image */
4714 DEFUN(peekIMG, PEEK_IMG, "Show image address")
4715 {
4716 _peekURL(1);
4717 }
4718
4719 /* show current URL */
4720 static Str
currentURL(void)4721 currentURL(void)
4722 {
4723 if (Currentbuf->bufferprop & BP_INTERNAL)
4724 return Strnew_size(0);
4725 return parsedURL2Str(&Currentbuf->currentURL);
4726 }
4727
4728 DEFUN(curURL, PEEK, "Show current address")
4729 {
4730 static Str s = NULL;
4731 #ifdef USE_M17N
4732 static Lineprop *p = NULL;
4733 Lineprop *pp;
4734 #endif
4735 static int offset = 0, n;
4736
4737 if (Currentbuf->bufferprop & BP_INTERNAL)
4738 return;
4739 if (CurrentKey == prev_key && s != NULL) {
4740 if (s->length - offset >= COLS)
4741 offset++;
4742 else if (s->length <= offset) /* bug ? */
4743 offset = 0;
4744 }
4745 else {
4746 offset = 0;
4747 s = currentURL();
4748 if (DecodeURL)
4749 s = Strnew_charp(url_decode2(s->ptr, NULL));
4750 #ifdef USE_M17N
4751 s = checkType(s, &pp, NULL);
4752 p = NewAtom_N(Lineprop, s->length);
4753 bcopy((void *)pp, (void *)p, s->length * sizeof(Lineprop));
4754 #endif
4755 }
4756 n = searchKeyNum();
4757 if (n > 1 && s->length > (n - 1) * (COLS - 1))
4758 offset = (n - 1) * (COLS - 1);
4759 #ifdef USE_M17N
4760 while (offset < s->length && p[offset] & PC_WCHAR2)
4761 offset++;
4762 #endif
4763 disp_message_nomouse(&s->ptr[offset], TRUE);
4764 }
4765 /* view HTML source */
4766
4767 DEFUN(vwSrc, SOURCE VIEW, "Toggle between HTML shown or processed")
4768 {
4769 Buffer *buf;
4770
4771 if (Currentbuf->type == NULL || Currentbuf->bufferprop & BP_FRAME)
4772 return;
4773 if ((buf = Currentbuf->linkBuffer[LB_SOURCE]) != NULL ||
4774 (buf = Currentbuf->linkBuffer[LB_N_SOURCE]) != NULL) {
4775 Currentbuf = buf;
4776 displayBuffer(Currentbuf, B_NORMAL);
4777 return;
4778 }
4779 if (Currentbuf->sourcefile == NULL) {
4780 if (Currentbuf->pagerSource &&
4781 !strcasecmp(Currentbuf->type, "text/plain")) {
4782 #ifdef USE_M17N
4783 wc_ces old_charset;
4784 wc_bool old_fix_width_conv;
4785 #endif
4786 FILE *f;
4787 Str tmpf = tmpfname(TMPF_SRC, NULL);
4788 f = fopen(tmpf->ptr, "w");
4789 if (f == NULL)
4790 return;
4791 #ifdef USE_M17N
4792 old_charset = DisplayCharset;
4793 old_fix_width_conv = WcOption.fix_width_conv;
4794 DisplayCharset = (Currentbuf->document_charset != WC_CES_US_ASCII)
4795 ? Currentbuf->document_charset : 0;
4796 WcOption.fix_width_conv = WC_FALSE;
4797 #endif
4798 saveBufferBody(Currentbuf, f, TRUE);
4799 #ifdef USE_M17N
4800 DisplayCharset = old_charset;
4801 WcOption.fix_width_conv = old_fix_width_conv;
4802 #endif
4803 fclose(f);
4804 Currentbuf->sourcefile = tmpf->ptr;
4805 }
4806 else {
4807 return;
4808 }
4809 }
4810
4811 buf = newBuffer(INIT_BUFFER_WIDTH);
4812
4813 if (is_html_type(Currentbuf->type)) {
4814 buf->type = "text/plain";
4815 if (Currentbuf->real_type &&
4816 is_html_type(Currentbuf->real_type))
4817 buf->real_type = "text/plain";
4818 else
4819 buf->real_type = Currentbuf->real_type;
4820 buf->buffername = Sprintf("source of %s", Currentbuf->buffername)->ptr;
4821 buf->linkBuffer[LB_N_SOURCE] = Currentbuf;
4822 Currentbuf->linkBuffer[LB_SOURCE] = buf;
4823 }
4824 else if (!strcasecmp(Currentbuf->type, "text/plain")) {
4825 buf->type = "text/html";
4826 if (Currentbuf->real_type &&
4827 !strcasecmp(Currentbuf->real_type, "text/plain"))
4828 buf->real_type = "text/html";
4829 else
4830 buf->real_type = Currentbuf->real_type;
4831 buf->buffername = Sprintf("HTML view of %s",
4832 Currentbuf->buffername)->ptr;
4833 buf->linkBuffer[LB_SOURCE] = Currentbuf;
4834 Currentbuf->linkBuffer[LB_N_SOURCE] = buf;
4835 }
4836 else {
4837 return;
4838 }
4839 buf->currentURL = Currentbuf->currentURL;
4840 buf->real_scheme = Currentbuf->real_scheme;
4841 buf->filename = Currentbuf->filename;
4842 buf->sourcefile = Currentbuf->sourcefile;
4843 buf->header_source = Currentbuf->header_source;
4844 buf->search_header = Currentbuf->search_header;
4845 #ifdef USE_M17N
4846 buf->document_charset = Currentbuf->document_charset;
4847 #endif
4848 buf->clone = Currentbuf->clone;
4849 (*buf->clone)++;
4850
4851 buf->need_reshape = TRUE;
4852 reshapeBuffer(buf);
4853 pushBuffer(buf);
4854 displayBuffer(Currentbuf, B_NORMAL);
4855 }
4856
4857 /* reload */
4858 DEFUN(reload, RELOAD, "Load current document anew")
4859 {
4860 Buffer *buf, *fbuf = NULL, sbuf;
4861 #ifdef USE_M17N
4862 wc_ces old_charset;
4863 #endif
4864 Str url;
4865 FormList *request;
4866 int multipart;
4867
4868 if (Currentbuf->bufferprop & BP_INTERNAL) {
4869 if (!strcmp(Currentbuf->buffername, DOWNLOAD_LIST_TITLE)) {
4870 ldDL();
4871 return;
4872 }
4873 /* FIXME: gettextize? */
4874 disp_err_message("Can't reload...", TRUE);
4875 return;
4876 }
4877 if (Currentbuf->currentURL.scheme == SCM_LOCAL &&
4878 !strcmp(Currentbuf->currentURL.file, "-")) {
4879 /* file is std input */
4880 /* FIXME: gettextize? */
4881 disp_err_message("Can't reload stdin", TRUE);
4882 return;
4883 }
4884 copyBuffer(&sbuf, Currentbuf);
4885 if (Currentbuf->bufferprop & BP_FRAME &&
4886 (fbuf = Currentbuf->linkBuffer[LB_N_FRAME])) {
4887 if (fmInitialized) {
4888 message("Rendering frame", 0, 0);
4889 refresh();
4890 }
4891 if (!(buf = renderFrame(fbuf, 1))) {
4892 displayBuffer(Currentbuf, B_NORMAL);
4893 return;
4894 }
4895 if (fbuf->linkBuffer[LB_FRAME]) {
4896 if (buf->sourcefile &&
4897 fbuf->linkBuffer[LB_FRAME]->sourcefile &&
4898 !strcmp(buf->sourcefile,
4899 fbuf->linkBuffer[LB_FRAME]->sourcefile))
4900 fbuf->linkBuffer[LB_FRAME]->sourcefile = NULL;
4901 delBuffer(fbuf->linkBuffer[LB_FRAME]);
4902 }
4903 fbuf->linkBuffer[LB_FRAME] = buf;
4904 buf->linkBuffer[LB_N_FRAME] = fbuf;
4905 pushBuffer(buf);
4906 Currentbuf = buf;
4907 if (Currentbuf->firstLine) {
4908 COPY_BUFROOT(Currentbuf, &sbuf);
4909 restorePosition(Currentbuf, &sbuf);
4910 }
4911 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4912 return;
4913 }
4914 else if (Currentbuf->frameset != NULL)
4915 fbuf = Currentbuf->linkBuffer[LB_FRAME];
4916 multipart = 0;
4917 if (Currentbuf->form_submit) {
4918 request = Currentbuf->form_submit->parent;
4919 if (request->method == FORM_METHOD_POST
4920 && request->enctype == FORM_ENCTYPE_MULTIPART) {
4921 Str query;
4922 struct stat st;
4923 multipart = 1;
4924 query_from_followform(&query, Currentbuf->form_submit, multipart);
4925 stat(request->body, &st);
4926 request->length = st.st_size;
4927 }
4928 }
4929 else {
4930 request = NULL;
4931 }
4932 url = parsedURL2Str(&Currentbuf->currentURL);
4933 /* FIXME: gettextize? */
4934 message("Reloading...", 0, 0);
4935 refresh();
4936 #ifdef USE_M17N
4937 old_charset = DocumentCharset;
4938 if (Currentbuf->document_charset != WC_CES_US_ASCII)
4939 DocumentCharset = Currentbuf->document_charset;
4940 #endif
4941 SearchHeader = Currentbuf->search_header;
4942 DefaultType = Currentbuf->real_type;
4943 buf = loadGeneralFile(url->ptr, NULL, NO_REFERER, RG_NOCACHE, request);
4944 #ifdef USE_M17N
4945 DocumentCharset = old_charset;
4946 #endif
4947 SearchHeader = FALSE;
4948 DefaultType = NULL;
4949
4950 if (multipart)
4951 unlink(request->body);
4952 if (buf == NULL) {
4953 /* FIXME: gettextize? */
4954 disp_err_message("Can't reload...", TRUE);
4955 return;
4956 }
4957 else if (buf == NO_BUFFER) {
4958 displayBuffer(Currentbuf, B_NORMAL);
4959 return;
4960 }
4961 if (fbuf != NULL)
4962 Firstbuf = deleteBuffer(Firstbuf, fbuf);
4963 repBuffer(Currentbuf, buf);
4964 if ((buf->type != NULL) && (sbuf.type != NULL) &&
4965 ((!strcasecmp(buf->type, "text/plain") &&
4966 is_html_type(sbuf.type)) ||
4967 (is_html_type(buf->type) &&
4968 !strcasecmp(sbuf.type, "text/plain")))) {
4969 vwSrc();
4970 if (Currentbuf != buf)
4971 Firstbuf = deleteBuffer(Firstbuf, buf);
4972 }
4973 Currentbuf->search_header = sbuf.search_header;
4974 Currentbuf->form_submit = sbuf.form_submit;
4975 if (Currentbuf->firstLine) {
4976 COPY_BUFROOT(Currentbuf, &sbuf);
4977 restorePosition(Currentbuf, &sbuf);
4978 }
4979 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4980 }
4981
4982 /* reshape */
4983 DEFUN(reshape, RESHAPE, "Re-render document")
4984 {
4985 Currentbuf->need_reshape = TRUE;
4986 reshapeBuffer(Currentbuf);
4987 displayBuffer(Currentbuf, B_FORCE_REDRAW);
4988 }
4989
4990 #ifdef USE_M17N
4991 static void
_docCSet(wc_ces charset)4992 _docCSet(wc_ces charset)
4993 {
4994 if (Currentbuf->bufferprop & BP_INTERNAL)
4995 return;
4996 if (Currentbuf->sourcefile == NULL) {
4997 disp_message("Can't reload...", FALSE);
4998 return;
4999 }
5000 Currentbuf->document_charset = charset;
5001 Currentbuf->need_reshape = TRUE;
5002 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5003 }
5004
5005 void
change_charset(struct parsed_tagarg * arg)5006 change_charset(struct parsed_tagarg *arg)
5007 {
5008 Buffer *buf = Currentbuf->linkBuffer[LB_N_INFO];
5009 wc_ces charset;
5010
5011 if (buf == NULL)
5012 return;
5013 delBuffer(Currentbuf);
5014 Currentbuf = buf;
5015 if (Currentbuf->bufferprop & BP_INTERNAL)
5016 return;
5017 charset = Currentbuf->document_charset;
5018 for (; arg; arg = arg->next) {
5019 if (!strcmp(arg->arg, "charset"))
5020 charset = atoi(arg->value);
5021 }
5022 _docCSet(charset);
5023 }
5024
5025 DEFUN(docCSet, CHARSET, "Change the character encoding for the current document")
5026 {
5027 char *cs;
5028 wc_ces charset;
5029
5030 cs = searchKeyData();
5031 if (cs == NULL || *cs == '\0')
5032 /* FIXME: gettextize? */
5033 cs = inputStr("Document charset: ",
5034 wc_ces_to_charset(Currentbuf->document_charset));
5035 charset = wc_guess_charset_short(cs, 0);
5036 if (charset == 0) {
5037 displayBuffer(Currentbuf, B_NORMAL);
5038 return;
5039 }
5040 _docCSet(charset);
5041 }
5042
5043 DEFUN(defCSet, DEFAULT_CHARSET, "Change the default character encoding")
5044 {
5045 char *cs;
5046 wc_ces charset;
5047
5048 cs = searchKeyData();
5049 if (cs == NULL || *cs == '\0')
5050 /* FIXME: gettextize? */
5051 cs = inputStr("Default document charset: ",
5052 wc_ces_to_charset(DocumentCharset));
5053 charset = wc_guess_charset_short(cs, 0);
5054 if (charset != 0)
5055 DocumentCharset = charset;
5056 displayBuffer(Currentbuf, B_NORMAL);
5057 }
5058 #endif
5059
5060 /* mark URL-like patterns as anchors */
5061 void
chkURLBuffer(Buffer * buf)5062 chkURLBuffer(Buffer *buf)
5063 {
5064 static char *url_like_pat[] = {
5065 "https?://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./?=~_\\&+@#,\\$;]*[a-zA-Z0-9_/=\\-]",
5066 "file:/[a-zA-Z0-9:%\\-\\./=_\\+@#,\\$;]*",
5067 #ifdef USE_GOPHER
5068 "gopher://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./_]*",
5069 #endif /* USE_GOPHER */
5070 "ftp://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./=_+@#,\\$]*[a-zA-Z0-9_/]",
5071 #ifdef USE_NNTP
5072 "news:[^<> ][^<> ]*",
5073 "nntp://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./_]*",
5074 #endif /* USE_NNTP */
5075 #ifndef USE_W3MMAILER /* see also chkExternalURIBuffer() */
5076 "mailto:[^<> ][^<> ]*@[a-zA-Z0-9][a-zA-Z0-9\\-\\._]*[a-zA-Z0-9]",
5077 #endif
5078 #ifdef INET6
5079 "https?://[a-zA-Z0-9:%\\-\\./_@]*\\[[a-fA-F0-9:][a-fA-F0-9:\\.]*\\][a-zA-Z0-9:%\\-\\./?=~_\\&+@#,\\$;]*",
5080 "ftp://[a-zA-Z0-9:%\\-\\./_@]*\\[[a-fA-F0-9:][a-fA-F0-9:\\.]*\\][a-zA-Z0-9:%\\-\\./=_+@#,\\$]*",
5081 #endif /* INET6 */
5082 NULL
5083 };
5084 int i;
5085 for (i = 0; url_like_pat[i]; i++) {
5086 reAnchor(buf, url_like_pat[i]);
5087 }
5088 #ifdef USE_EXTERNAL_URI_LOADER
5089 chkExternalURIBuffer(buf);
5090 #endif
5091 buf->check_url |= CHK_URL;
5092 }
5093
5094 DEFUN(chkURL, MARK_URL, "Turn URL-like strings into hyperlinks")
5095 {
5096 chkURLBuffer(Currentbuf);
5097 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5098 }
5099
5100 DEFUN(chkWORD, MARK_WORD, "Turn current word into hyperlink")
5101 {
5102 char *p;
5103 int spos, epos;
5104 p = getCurWord(Currentbuf, &spos, &epos);
5105 if (p == NULL)
5106 return;
5107 reAnchorWord(Currentbuf, Currentbuf->currentLine, spos, epos);
5108 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5109 }
5110
5111 #ifdef USE_NNTP
5112 /* mark Message-ID-like patterns as NEWS anchors */
5113 void
chkNMIDBuffer(Buffer * buf)5114 chkNMIDBuffer(Buffer *buf)
5115 {
5116 static char *url_like_pat[] = {
5117 "<[!-;=?-~]+@[a-zA-Z0-9\\.\\-_]+>",
5118 NULL,
5119 };
5120 int i;
5121 for (i = 0; url_like_pat[i]; i++) {
5122 reAnchorNews(buf, url_like_pat[i]);
5123 }
5124 buf->check_url |= CHK_NMID;
5125 }
5126
5127 DEFUN(chkNMID, MARK_MID, "Turn Message-ID-like strings into hyperlinks")
5128 {
5129 chkNMIDBuffer(Currentbuf);
5130 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5131 }
5132 #endif /* USE_NNTP */
5133
5134 /* render frames */
5135 DEFUN(rFrame, FRAME, "Toggle rendering HTML frames")
5136 {
5137 Buffer *buf;
5138
5139 if ((buf = Currentbuf->linkBuffer[LB_FRAME]) != NULL) {
5140 Currentbuf = buf;
5141 displayBuffer(Currentbuf, B_NORMAL);
5142 return;
5143 }
5144 if (Currentbuf->frameset == NULL) {
5145 if ((buf = Currentbuf->linkBuffer[LB_N_FRAME]) != NULL) {
5146 Currentbuf = buf;
5147 displayBuffer(Currentbuf, B_NORMAL);
5148 }
5149 return;
5150 }
5151 if (fmInitialized) {
5152 message("Rendering frame", 0, 0);
5153 refresh();
5154 }
5155 buf = renderFrame(Currentbuf, 0);
5156 if (buf == NULL) {
5157 displayBuffer(Currentbuf, B_NORMAL);
5158 return;
5159 }
5160 buf->linkBuffer[LB_N_FRAME] = Currentbuf;
5161 Currentbuf->linkBuffer[LB_FRAME] = buf;
5162 pushBuffer(buf);
5163 if (fmInitialized && display_ok)
5164 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5165 }
5166
5167 /* spawn external browser */
5168 static void
invoke_browser(char * url)5169 invoke_browser(char *url)
5170 {
5171 Str cmd;
5172 char *browser = NULL;
5173 int bg = 0, len;
5174
5175 CurrentKeyData = NULL; /* not allowed in w3m-control: */
5176 browser = searchKeyData();
5177 if (browser == NULL || *browser == '\0') {
5178 switch (prec_num) {
5179 case 0:
5180 case 1:
5181 browser = ExtBrowser;
5182 break;
5183 case 2:
5184 browser = ExtBrowser2;
5185 break;
5186 case 3:
5187 browser = ExtBrowser3;
5188 break;
5189 case 4:
5190 browser = ExtBrowser4;
5191 break;
5192 case 5:
5193 browser = ExtBrowser5;
5194 break;
5195 case 6:
5196 browser = ExtBrowser6;
5197 break;
5198 case 7:
5199 browser = ExtBrowser7;
5200 break;
5201 case 8:
5202 browser = ExtBrowser8;
5203 break;
5204 case 9:
5205 browser = ExtBrowser9;
5206 break;
5207 }
5208 if (browser == NULL || *browser == '\0') {
5209 browser = inputStr("Browse command: ", NULL);
5210 if (browser != NULL)
5211 browser = conv_to_system(browser);
5212 }
5213 }
5214 else {
5215 browser = conv_to_system(browser);
5216 }
5217 if (browser == NULL || *browser == '\0') {
5218 displayBuffer(Currentbuf, B_NORMAL);
5219 return;
5220 }
5221
5222 if ((len = strlen(browser)) >= 2 && browser[len - 1] == '&' &&
5223 browser[len - 2] != '\\') {
5224 browser = allocStr(browser, len - 2);
5225 bg = 1;
5226 }
5227 cmd = myExtCommand(browser, shell_quote(url), FALSE);
5228 Strremovetrailingspaces(cmd);
5229 fmTerm();
5230 mySystem(cmd->ptr, bg);
5231 fmInit();
5232 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5233 }
5234
5235 DEFUN(extbrz, EXTERN, "Display using an external browser")
5236 {
5237 if (Currentbuf->bufferprop & BP_INTERNAL) {
5238 /* FIXME: gettextize? */
5239 disp_err_message("Can't browse...", TRUE);
5240 return;
5241 }
5242 if (Currentbuf->currentURL.scheme == SCM_LOCAL &&
5243 !strcmp(Currentbuf->currentURL.file, "-")) {
5244 /* file is std input */
5245 /* FIXME: gettextize? */
5246 disp_err_message("Can't browse stdin", TRUE);
5247 return;
5248 }
5249 invoke_browser(parsedURL2Str(&Currentbuf->currentURL)->ptr);
5250 }
5251
5252 DEFUN(linkbrz, EXTERN_LINK, "Display target using an external browser")
5253 {
5254 Anchor *a;
5255 ParsedURL pu;
5256
5257 if (Currentbuf->firstLine == NULL)
5258 return;
5259 a = retrieveCurrentAnchor(Currentbuf);
5260 if (a == NULL)
5261 return;
5262 parseURL2(a->url, &pu, baseURL(Currentbuf));
5263 invoke_browser(parsedURL2Str(&pu)->ptr);
5264 }
5265
5266 /* show current line number and number of lines in the entire document */
5267 DEFUN(curlno, LINE_INFO, "Display current position in document")
5268 {
5269 Line *l = Currentbuf->currentLine;
5270 Str tmp;
5271 int cur = 0, all = 0, col = 0, len = 0;
5272
5273 if (l != NULL) {
5274 cur = l->real_linenumber;
5275 col = l->bwidth + Currentbuf->currentColumn + Currentbuf->cursorX + 1;
5276 while (l->next && l->next->bpos)
5277 l = l->next;
5278 if (l->width < 0)
5279 l->width = COLPOS(l, l->len);
5280 len = l->bwidth + l->width;
5281 }
5282 if (Currentbuf->lastLine)
5283 all = Currentbuf->lastLine->real_linenumber;
5284 if (Currentbuf->pagerSource && !(Currentbuf->bufferprop & BP_CLOSE))
5285 tmp = Sprintf("line %d col %d/%d", cur, col, len);
5286 else
5287 tmp = Sprintf("line %d/%d (%d%%) col %d/%d", cur, all,
5288 (int)((double)cur * 100.0 / (double)(all ? all : 1)
5289 + 0.5), col, len);
5290 #ifdef USE_M17N
5291 Strcat_charp(tmp, " ");
5292 Strcat_charp(tmp, wc_ces_to_charset_desc(Currentbuf->document_charset));
5293 #endif
5294
5295 disp_message(tmp->ptr, FALSE);
5296 }
5297
5298 #ifdef USE_IMAGE
5299 DEFUN(dispI, DISPLAY_IMAGE, "Restart loading and drawing of images")
5300 {
5301 if (!displayImage)
5302 initImage();
5303 if (!activeImage)
5304 return;
5305 displayImage = TRUE;
5306 /*
5307 * if (!(Currentbuf->type && is_html_type(Currentbuf->type)))
5308 * return;
5309 */
5310 Currentbuf->image_flag = IMG_FLAG_AUTO;
5311 Currentbuf->need_reshape = TRUE;
5312 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
5313 }
5314
5315 DEFUN(stopI, STOP_IMAGE, "Stop loading and drawing of images")
5316 {
5317 if (!activeImage)
5318 return;
5319 /*
5320 * if (!(Currentbuf->type && is_html_type(Currentbuf->type)))
5321 * return;
5322 */
5323 Currentbuf->image_flag = IMG_FLAG_SKIP;
5324 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
5325 }
5326 #endif
5327
5328 #ifdef USE_MOUSE
5329
5330 static int
mouse_scroll_line(void)5331 mouse_scroll_line(void)
5332 {
5333 if (relative_wheel_scroll)
5334 return (relative_wheel_scroll_ratio * LASTLINE + 99) / 100;
5335 else
5336 return fixed_wheel_scroll_count;
5337 }
5338
5339 static TabBuffer *
posTab(int x,int y)5340 posTab(int x, int y)
5341 {
5342 TabBuffer *tab;
5343
5344 if (mouse_action.menu_str && x < mouse_action.menu_width && y == 0)
5345 return NO_TABBUFFER;
5346 if (y > LastTab->y)
5347 return NULL;
5348 for (tab = FirstTab; tab; tab = tab->nextTab) {
5349 if (tab->x1 <= x && x <= tab->x2 && tab->y == y)
5350 return tab;
5351 }
5352 return NULL;
5353 }
5354
5355 static void
do_mouse_action(int btn,int x,int y)5356 do_mouse_action(int btn, int x, int y)
5357 {
5358 MouseActionMap *map = NULL;
5359 int ny = -1;
5360
5361 if (nTab > 1 || mouse_action.menu_str)
5362 ny = LastTab->y + 1;
5363
5364 switch (btn) {
5365 case MOUSE_BTN1_DOWN:
5366 btn = 0;
5367 break;
5368 case MOUSE_BTN2_DOWN:
5369 btn = 1;
5370 break;
5371 case MOUSE_BTN3_DOWN:
5372 btn = 2;
5373 break;
5374 default:
5375 return;
5376 }
5377 if (y < ny) {
5378 if (mouse_action.menu_str && x >= 0 && x < mouse_action.menu_width) {
5379 if (mouse_action.menu_map[btn])
5380 map = &mouse_action.menu_map[btn][x];
5381 }
5382 else
5383 map = &mouse_action.tab_map[btn];
5384 }
5385 else if (y == LASTLINE) {
5386 if (mouse_action.lastline_str && x >= 0 &&
5387 x < mouse_action.lastline_width) {
5388 if (mouse_action.lastline_map[btn])
5389 map = &mouse_action.lastline_map[btn][x];
5390 }
5391 }
5392 else if (y > ny) {
5393 if (y == Currentbuf->cursorY + Currentbuf->rootY &&
5394 (x == Currentbuf->cursorX + Currentbuf->rootX
5395 #ifdef USE_M17N
5396 || (WcOption.use_wide && Currentbuf->currentLine != NULL &&
5397 (CharType(Currentbuf->currentLine->propBuf[Currentbuf->pos])
5398 == PC_KANJI1)
5399 && x == Currentbuf->cursorX + Currentbuf->rootX + 1)
5400 #endif
5401 )) {
5402 if (retrieveCurrentAnchor(Currentbuf) ||
5403 retrieveCurrentForm(Currentbuf)) {
5404 map = &mouse_action.active_map[btn];
5405 if (!(map && map->func))
5406 map = &mouse_action.anchor_map[btn];
5407 }
5408 }
5409 else {
5410 int cx = Currentbuf->cursorX, cy = Currentbuf->cursorY;
5411 cursorXY(Currentbuf, x - Currentbuf->rootX, y - Currentbuf->rootY);
5412 if (y == Currentbuf->cursorY + Currentbuf->rootY &&
5413 (x == Currentbuf->cursorX + Currentbuf->rootX
5414 #ifdef USE_M17N
5415 || (WcOption.use_wide && Currentbuf->currentLine != NULL &&
5416 (CharType(Currentbuf->currentLine->
5417 propBuf[Currentbuf->pos]) == PC_KANJI1)
5418 && x == Currentbuf->cursorX + Currentbuf->rootX + 1)
5419 #endif
5420 ) &&
5421 (retrieveCurrentAnchor(Currentbuf) ||
5422 retrieveCurrentForm(Currentbuf)))
5423 map = &mouse_action.anchor_map[btn];
5424 cursorXY(Currentbuf, cx, cy);
5425 }
5426 }
5427 else {
5428 return;
5429 }
5430 if (!(map && map->func))
5431 map = &mouse_action.default_map[btn];
5432 if (map && map->func) {
5433 mouse_action.in_action = TRUE;
5434 mouse_action.cursorX = x;
5435 mouse_action.cursorY = y;
5436 CurrentKey = -1;
5437 CurrentKeyData = NULL;
5438 CurrentCmdData = map->data;
5439 (*map->func) ();
5440 CurrentCmdData = NULL;
5441 }
5442 }
5443
5444 static void
process_mouse(int btn,int x,int y)5445 process_mouse(int btn, int x, int y)
5446 {
5447 int delta_x, delta_y, i;
5448 static int press_btn = MOUSE_BTN_RESET, press_x, press_y;
5449 TabBuffer *t;
5450 int ny = -1;
5451
5452 if (nTab > 1 || mouse_action.menu_str)
5453 ny = LastTab->y + 1;
5454 if (btn == MOUSE_BTN_UP) {
5455 switch (press_btn) {
5456 case MOUSE_BTN1_DOWN:
5457 if (press_y == y && press_x == x)
5458 do_mouse_action(press_btn, x, y);
5459 else if (ny > 0 && y < ny) {
5460 if (press_y < ny) {
5461 moveTab(posTab(press_x, press_y), posTab(x, y),
5462 (press_y == y) ? (press_x < x) : (press_y < y));
5463 return;
5464 }
5465 else if (press_x >= Currentbuf->rootX) {
5466 Buffer *buf = Currentbuf;
5467 int cx = Currentbuf->cursorX, cy = Currentbuf->cursorY;
5468
5469 t = posTab(x, y);
5470 if (t == NULL)
5471 return;
5472 if (t == NO_TABBUFFER)
5473 t = NULL; /* open new tab */
5474 cursorXY(Currentbuf, press_x - Currentbuf->rootX,
5475 press_y - Currentbuf->rootY);
5476 if (Currentbuf->cursorY == press_y - Currentbuf->rootY &&
5477 (Currentbuf->cursorX == press_x - Currentbuf->rootX
5478 #ifdef USE_M17N
5479 || (WcOption.use_wide &&
5480 Currentbuf->currentLine != NULL &&
5481 (CharType(Currentbuf->currentLine->
5482 propBuf[Currentbuf->pos]) == PC_KANJI1)
5483 && Currentbuf->cursorX == press_x
5484 - Currentbuf->rootX - 1)
5485 #endif
5486 )) {
5487 displayBuffer(Currentbuf, B_NORMAL);
5488 followTab(t);
5489 }
5490 if (buf == Currentbuf)
5491 cursorXY(Currentbuf, cx, cy);
5492 }
5493 return;
5494 }
5495 else {
5496 delta_x = x - press_x;
5497 delta_y = y - press_y;
5498
5499 if (abs(delta_x) < abs(delta_y) / 3)
5500 delta_x = 0;
5501 if (abs(delta_y) < abs(delta_x) / 3)
5502 delta_y = 0;
5503 if (reverse_mouse) {
5504 delta_y = -delta_y;
5505 delta_x = -delta_x;
5506 }
5507 if (delta_y > 0) {
5508 prec_num = delta_y;
5509 ldown1();
5510 }
5511 else if (delta_y < 0) {
5512 prec_num = -delta_y;
5513 lup1();
5514 }
5515 if (delta_x > 0) {
5516 prec_num = delta_x;
5517 col1L();
5518 }
5519 else if (delta_x < 0) {
5520 prec_num = -delta_x;
5521 col1R();
5522 }
5523 }
5524 break;
5525 case MOUSE_BTN2_DOWN:
5526 case MOUSE_BTN3_DOWN:
5527 if (press_y == y && press_x == x)
5528 do_mouse_action(press_btn, x, y);
5529 break;
5530 case MOUSE_BTN4_DOWN_RXVT:
5531 for (i = 0; i < mouse_scroll_line(); i++)
5532 ldown1();
5533 break;
5534 case MOUSE_BTN5_DOWN_RXVT:
5535 for (i = 0; i < mouse_scroll_line(); i++)
5536 lup1();
5537 break;
5538 }
5539 }
5540 else if (btn == MOUSE_BTN4_DOWN_XTERM) {
5541 for (i = 0; i < mouse_scroll_line(); i++)
5542 ldown1();
5543 }
5544 else if (btn == MOUSE_BTN5_DOWN_XTERM) {
5545 for (i = 0; i < mouse_scroll_line(); i++)
5546 lup1();
5547 }
5548
5549 if (btn != MOUSE_BTN4_DOWN_RXVT || press_btn == MOUSE_BTN_RESET) {
5550 press_btn = btn;
5551 press_x = x;
5552 press_y = y;
5553 }
5554 else {
5555 press_btn = MOUSE_BTN_RESET;
5556 }
5557 }
5558
5559 DEFUN(msToggle, MOUSE_TOGGLE, "Toggle mouse support")
5560 {
5561 if (use_mouse) {
5562 use_mouse = FALSE;
5563 }
5564 else {
5565 use_mouse = TRUE;
5566 }
5567 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5568 }
5569
5570 DEFUN(mouse, MOUSE, "mouse operation")
5571 {
5572 int btn, x, y;
5573
5574 btn = (unsigned char)getch() - 32;
5575 #if defined(__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005
5576 if (cygwin_mouse_btn_swapped) {
5577 if (btn == MOUSE_BTN2_DOWN)
5578 btn = MOUSE_BTN3_DOWN;
5579 else if (btn == MOUSE_BTN3_DOWN)
5580 btn = MOUSE_BTN2_DOWN;
5581 }
5582 #endif
5583 x = (unsigned char)getch() - 33;
5584 if (x < 0)
5585 x += 0x100;
5586 y = (unsigned char)getch() - 33;
5587 if (y < 0)
5588 y += 0x100;
5589
5590 if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
5591 return;
5592 process_mouse(btn, x, y);
5593 }
5594
5595 DEFUN(sgrmouse, SGRMOUSE, "SGR 1006 mouse operation")
5596 {
5597 int btn = 0, x = 0, y = 0;
5598 unsigned char c;
5599
5600 do {
5601 c = getch();
5602 if (IS_DIGIT(c))
5603 btn = btn * 10 + c - '0';
5604 else if (c == ';')
5605 break;
5606 else
5607 return;
5608 } while (1);
5609
5610 #if defined(__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005
5611 if (cygwin_mouse_btn_swapped) {
5612 if (btn == MOUSE_BTN2_DOWN)
5613 btn = MOUSE_BTN3_DOWN;
5614 else if (btn == MOUSE_BTN3_DOWN)
5615 btn = MOUSE_BTN2_DOWN;
5616 };
5617 #endif
5618
5619 do {
5620 c = getch();
5621 if (IS_DIGIT(c))
5622 x = x * 10 + c - '0';
5623 else if (c == ';')
5624 break;
5625 else
5626 return;
5627 } while (1);
5628 if (x>0) x--;
5629
5630 do {
5631 c = getch();
5632 if (IS_DIGIT(c))
5633 y = y * 10 + c - '0';
5634 else if (c == 'M')
5635 break;
5636 else if (c == 'm') {
5637 btn |= 3;
5638 break;
5639 } else
5640 return;
5641 } while (1);
5642 if (y>0) y--;
5643
5644 if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
5645 return;
5646 process_mouse(btn, x, y);
5647 }
5648
5649 #ifdef USE_GPM
5650 int
gpm_process_mouse(Gpm_Event * event,void * data)5651 gpm_process_mouse(Gpm_Event * event, void *data)
5652 {
5653 int btn = MOUSE_BTN_RESET, x, y;
5654 if (event->type & GPM_UP)
5655 btn = MOUSE_BTN_UP;
5656 else if (event->type & GPM_DOWN) {
5657 switch (event->buttons) {
5658 case GPM_B_LEFT:
5659 btn = MOUSE_BTN1_DOWN;
5660 break;
5661 case GPM_B_MIDDLE:
5662 btn = MOUSE_BTN2_DOWN;
5663 break;
5664 case GPM_B_RIGHT:
5665 btn = MOUSE_BTN3_DOWN;
5666 break;
5667 }
5668 }
5669 else {
5670 GPM_DRAWPOINTER(event);
5671 return 0;
5672 }
5673 x = event->x;
5674 y = event->y;
5675 process_mouse(btn, x - 1, y - 1);
5676 return 0;
5677 }
5678 #endif /* USE_GPM */
5679
5680 #ifdef USE_SYSMOUSE
5681 int
sysm_process_mouse(int x,int y,int nbs,int obs)5682 sysm_process_mouse(int x, int y, int nbs, int obs)
5683 {
5684 int btn;
5685 int bits;
5686
5687 if (obs & ~nbs)
5688 btn = MOUSE_BTN_UP;
5689 else if (nbs & ~obs) {
5690 bits = nbs & ~obs;
5691 btn = bits & 0x1 ? MOUSE_BTN1_DOWN :
5692 (bits & 0x2 ? MOUSE_BTN2_DOWN :
5693 (bits & 0x4 ? MOUSE_BTN3_DOWN : 0));
5694 }
5695 else /* nbs == obs */
5696 return 0;
5697 process_mouse(btn, x, y);
5698 return 0;
5699 }
5700 #endif /* USE_SYSMOUSE */
5701
5702 DEFUN(movMs, MOVE_MOUSE, "Move cursor to mouse pointer")
5703 {
5704 if (!mouse_action.in_action)
5705 return;
5706 if ((nTab > 1 || mouse_action.menu_str) &&
5707 mouse_action.cursorY < LastTab->y + 1)
5708 return;
5709 else if (mouse_action.cursorX >= Currentbuf->rootX &&
5710 mouse_action.cursorY < LASTLINE) {
5711 cursorXY(Currentbuf, mouse_action.cursorX - Currentbuf->rootX,
5712 mouse_action.cursorY - Currentbuf->rootY);
5713 }
5714 displayBuffer(Currentbuf, B_NORMAL);
5715 }
5716
5717 #ifdef USE_MENU
5718 #ifdef KANJI_SYMBOLS
5719 #define FRAME_WIDTH 2
5720 #else
5721 #define FRAME_WIDTH 1
5722 #endif
5723
5724 DEFUN(menuMs, MENU_MOUSE, "Pop up menu at mouse pointer")
5725 {
5726 if (!mouse_action.in_action)
5727 return;
5728 if ((nTab > 1 || mouse_action.menu_str) &&
5729 mouse_action.cursorY < LastTab->y + 1)
5730 mouse_action.cursorX -= FRAME_WIDTH + 1;
5731 else if (mouse_action.cursorX >= Currentbuf->rootX &&
5732 mouse_action.cursorY < LASTLINE) {
5733 cursorXY(Currentbuf, mouse_action.cursorX - Currentbuf->rootX,
5734 mouse_action.cursorY - Currentbuf->rootY);
5735 displayBuffer(Currentbuf, B_NORMAL);
5736 }
5737 mainMn();
5738 }
5739 #endif
5740
5741 DEFUN(tabMs, TAB_MOUSE, "Select tab by mouse action")
5742 {
5743 TabBuffer *tab;
5744
5745 if (!mouse_action.in_action)
5746 return;
5747 tab = posTab(mouse_action.cursorX, mouse_action.cursorY);
5748 if (!tab || tab == NO_TABBUFFER)
5749 return;
5750 CurrentTab = tab;
5751 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5752 }
5753
5754 DEFUN(closeTMs, CLOSE_TAB_MOUSE, "Close tab at mouse pointer")
5755 {
5756 TabBuffer *tab;
5757
5758 if (!mouse_action.in_action)
5759 return;
5760 tab = posTab(mouse_action.cursorX, mouse_action.cursorY);
5761 if (!tab || tab == NO_TABBUFFER)
5762 return;
5763 deleteTab(tab);
5764 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5765 }
5766 #endif /* USE_MOUSE */
5767
5768 DEFUN(dispVer, VERSION, "Display the version of w3m")
5769 {
5770 disp_message(Sprintf("w3m version %s", w3m_version)->ptr, TRUE);
5771 }
5772
5773 DEFUN(wrapToggle, WRAP_TOGGLE, "Toggle wrapping mode in searches")
5774 {
5775 if (WrapSearch) {
5776 WrapSearch = FALSE;
5777 /* FIXME: gettextize? */
5778 disp_message("Wrap search off", TRUE);
5779 }
5780 else {
5781 WrapSearch = TRUE;
5782 /* FIXME: gettextize? */
5783 disp_message("Wrap search on", TRUE);
5784 }
5785 }
5786
5787 static char *
getCurWord(Buffer * buf,int * spos,int * epos)5788 getCurWord(Buffer *buf, int *spos, int *epos)
5789 {
5790 char *p;
5791 Line *l = buf->currentLine;
5792 int b, e;
5793
5794 *spos = 0;
5795 *epos = 0;
5796 if (l == NULL)
5797 return NULL;
5798 p = l->lineBuf;
5799 e = buf->pos;
5800 while (e > 0 && !is_wordchar(getChar(&p[e])))
5801 prevChar(e, l);
5802 if (!is_wordchar(getChar(&p[e])))
5803 return NULL;
5804 b = e;
5805 while (b > 0) {
5806 int tmp = b;
5807 prevChar(tmp, l);
5808 if (!is_wordchar(getChar(&p[tmp])))
5809 break;
5810 b = tmp;
5811 }
5812 while (e < l->len && is_wordchar(getChar(&p[e])))
5813 nextChar(e, l);
5814 *spos = b;
5815 *epos = e;
5816 return &p[b];
5817 }
5818
5819 static char *
GetWord(Buffer * buf)5820 GetWord(Buffer *buf)
5821 {
5822 int b, e;
5823 char *p;
5824
5825 if ((p = getCurWord(buf, &b, &e)) != NULL) {
5826 return Strnew_charp_n(p, e - b)->ptr;
5827 }
5828 return NULL;
5829 }
5830
5831 #ifdef USE_DICT
5832 static void
execdict(char * word)5833 execdict(char *word)
5834 {
5835 char *w, *dictcmd;
5836 Buffer *buf;
5837
5838 if (!UseDictCommand || word == NULL || *word == '\0') {
5839 displayBuffer(Currentbuf, B_NORMAL);
5840 return;
5841 }
5842 w = conv_to_system(word);
5843 if (*w == '\0') {
5844 displayBuffer(Currentbuf, B_NORMAL);
5845 return;
5846 }
5847 dictcmd = Sprintf("%s?%s", DictCommand,
5848 Str_form_quote(Strnew_charp(w))->ptr)->ptr;
5849 buf = loadGeneralFile(dictcmd, NULL, NO_REFERER, 0, NULL);
5850 if (buf == NULL) {
5851 disp_message("Execution failed", TRUE);
5852 return;
5853 }
5854 else if (buf != NO_BUFFER) {
5855 buf->filename = w;
5856 buf->buffername = Sprintf("%s %s", DICTBUFFERNAME, word)->ptr;
5857 if (buf->type == NULL)
5858 buf->type = "text/plain";
5859 pushBuffer(buf);
5860 }
5861 displayBuffer(Currentbuf, B_FORCE_REDRAW);
5862 }
5863
5864 DEFUN(dictword, DICT_WORD, "Execute dictionary command (see README.dict)")
5865 {
5866 execdict(inputStr("(dictionary)!", ""));
5867 }
5868
5869 DEFUN(dictwordat, DICT_WORD_AT,
5870 "Execute dictionary command for word at cursor")
5871 {
5872 execdict(GetWord(Currentbuf));
5873 }
5874 #endif /* USE_DICT */
5875
5876 void
set_buffer_environ(Buffer * buf)5877 set_buffer_environ(Buffer *buf)
5878 {
5879 static Buffer *prev_buf = NULL;
5880 static Line *prev_line = NULL;
5881 static int prev_pos = -1;
5882 Line *l;
5883
5884 if (buf == NULL)
5885 return;
5886 if (buf != prev_buf) {
5887 set_environ("W3M_SOURCEFILE", buf->sourcefile);
5888 set_environ("W3M_FILENAME", buf->filename);
5889 set_environ("W3M_TITLE", buf->buffername);
5890 set_environ("W3M_URL", parsedURL2Str(&buf->currentURL)->ptr);
5891 set_environ("W3M_TYPE", buf->real_type ? buf->real_type : "unknown");
5892 #ifdef USE_M17N
5893 set_environ("W3M_CHARSET", wc_ces_to_charset(buf->document_charset));
5894 #endif
5895 }
5896 l = buf->currentLine;
5897 if (l && (buf != prev_buf || l != prev_line || buf->pos != prev_pos)) {
5898 Anchor *a;
5899 ParsedURL pu;
5900 char *s = GetWord(buf);
5901 set_environ("W3M_CURRENT_WORD", s ? s : "");
5902 a = retrieveCurrentAnchor(buf);
5903 if (a) {
5904 parseURL2(a->url, &pu, baseURL(buf));
5905 set_environ("W3M_CURRENT_LINK", parsedURL2Str(&pu)->ptr);
5906 }
5907 else
5908 set_environ("W3M_CURRENT_LINK", "");
5909 a = retrieveCurrentImg(buf);
5910 if (a) {
5911 parseURL2(a->url, &pu, baseURL(buf));
5912 set_environ("W3M_CURRENT_IMG", parsedURL2Str(&pu)->ptr);
5913 }
5914 else
5915 set_environ("W3M_CURRENT_IMG", "");
5916 a = retrieveCurrentForm(buf);
5917 if (a)
5918 set_environ("W3M_CURRENT_FORM", form2str((FormItemList *)a->url));
5919 else
5920 set_environ("W3M_CURRENT_FORM", "");
5921 set_environ("W3M_CURRENT_LINE", Sprintf("%ld",
5922 l->real_linenumber)->ptr);
5923 set_environ("W3M_CURRENT_COLUMN", Sprintf("%d",
5924 buf->currentColumn +
5925 buf->cursorX + 1)->ptr);
5926 }
5927 else if (!l) {
5928 set_environ("W3M_CURRENT_WORD", "");
5929 set_environ("W3M_CURRENT_LINK", "");
5930 set_environ("W3M_CURRENT_IMG", "");
5931 set_environ("W3M_CURRENT_FORM", "");
5932 set_environ("W3M_CURRENT_LINE", "0");
5933 set_environ("W3M_CURRENT_COLUMN", "0");
5934 }
5935 prev_buf = buf;
5936 prev_line = l;
5937 prev_pos = buf->pos;
5938 }
5939
5940 char *
searchKeyData(void)5941 searchKeyData(void)
5942 {
5943 char *data = NULL;
5944
5945 if (CurrentKeyData != NULL && *CurrentKeyData != '\0')
5946 data = CurrentKeyData;
5947 else if (CurrentCmdData != NULL && *CurrentCmdData != '\0')
5948 data = CurrentCmdData;
5949 else if (CurrentKey >= 0)
5950 data = getKeyData(CurrentKey);
5951 CurrentKeyData = NULL;
5952 CurrentCmdData = NULL;
5953 if (data == NULL || *data == '\0')
5954 return NULL;
5955 return allocStr(data, -1);
5956 }
5957
5958 static int
searchKeyNum(void)5959 searchKeyNum(void)
5960 {
5961 char *d;
5962 int n = 1;
5963
5964 d = searchKeyData();
5965 if (d != NULL)
5966 n = atoi(d);
5967 return n * PREC_NUM;
5968 }
5969
5970 #ifdef __EMX__
5971 #ifdef USE_M17N
5972 static char *
getCodePage(void)5973 getCodePage(void)
5974 {
5975 unsigned long CpList[8], CpSize;
5976
5977 if (!getenv("WINDOWID") && !DosQueryCp(sizeof(CpList), CpList, &CpSize))
5978 return Sprintf("CP%d", *CpList)->ptr;
5979 return NULL;
5980 }
5981 #endif
5982 #endif
5983
5984 void
deleteFiles()5985 deleteFiles()
5986 {
5987 Buffer *buf;
5988 char *f;
5989
5990 for (CurrentTab = FirstTab; CurrentTab; CurrentTab = CurrentTab->nextTab) {
5991 while (Firstbuf && Firstbuf != NO_BUFFER) {
5992 buf = Firstbuf->nextBuffer;
5993 discardBuffer(Firstbuf);
5994 Firstbuf = buf;
5995 }
5996 }
5997 while ((f = popText(fileToDelete)) != NULL) {
5998 unlink(f);
5999 if (enable_inline_image == INLINE_IMG_SIXEL && strcmp(f+strlen(f)-4, ".gif") == 0) {
6000 Str firstframe = Strnew_charp(f);
6001 Strcat_charp(firstframe, "-1");
6002 unlink(firstframe->ptr);
6003 }
6004 }
6005 }
6006
6007 void
w3m_exit(int i)6008 w3m_exit(int i)
6009 {
6010 #ifdef USE_MIGEMO
6011 init_migemo(); /* close pipe to migemo */
6012 #endif
6013 stopDownload();
6014 deleteFiles();
6015 #ifdef USE_SSL
6016 free_ssl_ctx();
6017 #endif
6018 disconnectFTP();
6019 #ifdef USE_NNTP
6020 disconnectNews();
6021 #endif
6022 #ifdef __MINGW32_VERSION
6023 WSACleanup();
6024 #endif
6025 #ifdef HAVE_MKDTEMP
6026 if (no_rc_dir && tmp_dir != rc_dir)
6027 if (rmdir(tmp_dir) != 0) {
6028 fprintf(stderr, "Can't remove temporary directory (%s)!\n", tmp_dir);
6029 exit(1);
6030 }
6031 #endif
6032 exit(i);
6033 }
6034
6035 DEFUN(execCmd, COMMAND, "Invoke w3m function(s)")
6036 {
6037 char *data, *p;
6038 int cmd;
6039
6040 CurrentKeyData = NULL; /* not allowed in w3m-control: */
6041 data = searchKeyData();
6042 if (data == NULL || *data == '\0') {
6043 data = inputStrHist("command [; ...]: ", "", TextHist);
6044 if (data == NULL) {
6045 displayBuffer(Currentbuf, B_NORMAL);
6046 return;
6047 }
6048 }
6049 /* data: FUNC [DATA] [; FUNC [DATA] ...] */
6050 while (*data) {
6051 SKIP_BLANKS(data);
6052 if (*data == ';') {
6053 data++;
6054 continue;
6055 }
6056 p = getWord(&data);
6057 cmd = getFuncList(p);
6058 if (cmd < 0)
6059 break;
6060 p = getQWord(&data);
6061 CurrentKey = -1;
6062 CurrentKeyData = NULL;
6063 CurrentCmdData = *p ? p : NULL;
6064 #ifdef USE_MOUSE
6065 if (use_mouse)
6066 mouse_inactive();
6067 #endif
6068 w3mFuncList[cmd].func();
6069 #ifdef USE_MOUSE
6070 if (use_mouse)
6071 mouse_active();
6072 #endif
6073 CurrentCmdData = NULL;
6074 }
6075 displayBuffer(Currentbuf, B_NORMAL);
6076 }
6077
6078 #ifdef USE_ALARM
6079 static MySignalHandler
SigAlarm(SIGNAL_ARG)6080 SigAlarm(SIGNAL_ARG)
6081 {
6082 char *data;
6083
6084 if (CurrentAlarm->sec > 0) {
6085 CurrentKey = -1;
6086 CurrentKeyData = NULL;
6087 CurrentCmdData = data = (char *)CurrentAlarm->data;
6088 #ifdef USE_MOUSE
6089 if (use_mouse)
6090 mouse_inactive();
6091 #endif
6092 w3mFuncList[CurrentAlarm->cmd].func();
6093 #ifdef USE_MOUSE
6094 if (use_mouse)
6095 mouse_active();
6096 #endif
6097 CurrentCmdData = NULL;
6098 if (CurrentAlarm->status == AL_IMPLICIT_ONCE) {
6099 CurrentAlarm->sec = 0;
6100 CurrentAlarm->status = AL_UNSET;
6101 }
6102 if (Currentbuf->event) {
6103 if (Currentbuf->event->status != AL_UNSET)
6104 CurrentAlarm = Currentbuf->event;
6105 else
6106 Currentbuf->event = NULL;
6107 }
6108 if (!Currentbuf->event)
6109 CurrentAlarm = &DefaultAlarm;
6110 if (CurrentAlarm->sec > 0) {
6111 mySignal(SIGALRM, SigAlarm);
6112 alarm(CurrentAlarm->sec);
6113 }
6114 }
6115 SIGNAL_RETURN;
6116 }
6117
6118
6119 DEFUN(setAlarm, ALARM, "Set alarm")
6120 {
6121 char *data;
6122 int sec = 0, cmd = -1;
6123
6124 CurrentKeyData = NULL; /* not allowed in w3m-control: */
6125 data = searchKeyData();
6126 if (data == NULL || *data == '\0') {
6127 data = inputStrHist("(Alarm)sec command: ", "", TextHist);
6128 if (data == NULL) {
6129 displayBuffer(Currentbuf, B_NORMAL);
6130 return;
6131 }
6132 }
6133 if (*data != '\0') {
6134 sec = atoi(getWord(&data));
6135 if (sec > 0)
6136 cmd = getFuncList(getWord(&data));
6137 }
6138 if (cmd >= 0) {
6139 data = getQWord(&data);
6140 setAlarmEvent(&DefaultAlarm, sec, AL_EXPLICIT, cmd, data);
6141 disp_message_nsec(Sprintf("%dsec %s %s", sec, w3mFuncList[cmd].id,
6142 data)->ptr, FALSE, 1, FALSE, TRUE);
6143 }
6144 else {
6145 setAlarmEvent(&DefaultAlarm, 0, AL_UNSET, FUNCNAME_nulcmd, NULL);
6146 }
6147 displayBuffer(Currentbuf, B_NORMAL);
6148 }
6149
6150 AlarmEvent *
setAlarmEvent(AlarmEvent * event,int sec,short status,int cmd,void * data)6151 setAlarmEvent(AlarmEvent * event, int sec, short status, int cmd, void *data)
6152 {
6153 if (event == NULL)
6154 event = New(AlarmEvent);
6155 event->sec = sec;
6156 event->status = status;
6157 event->cmd = cmd;
6158 event->data = data;
6159 return event;
6160 }
6161 #endif
6162
6163 DEFUN(reinit, REINIT, "Reload configuration file")
6164 {
6165 char *resource = searchKeyData();
6166
6167 if (resource == NULL) {
6168 init_rc();
6169 sync_with_option();
6170 #ifdef USE_COOKIE
6171 initCookie();
6172 #endif
6173 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
6174 return;
6175 }
6176
6177 if (!strcasecmp(resource, "CONFIG") || !strcasecmp(resource, "RC")) {
6178 init_rc();
6179 sync_with_option();
6180 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
6181 return;
6182 }
6183
6184 #ifdef USE_COOKIE
6185 if (!strcasecmp(resource, "COOKIE")) {
6186 initCookie();
6187 return;
6188 }
6189 #endif
6190
6191 if (!strcasecmp(resource, "KEYMAP")) {
6192 initKeymap(TRUE);
6193 return;
6194 }
6195
6196 if (!strcasecmp(resource, "MAILCAP")) {
6197 initMailcap();
6198 return;
6199 }
6200
6201 #ifdef USE_MOUSE
6202 if (!strcasecmp(resource, "MOUSE")) {
6203 initMouseAction();
6204 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
6205 return;
6206 }
6207 #endif
6208
6209 #ifdef USE_MENU
6210 if (!strcasecmp(resource, "MENU")) {
6211 initMenu();
6212 return;
6213 }
6214 #endif
6215
6216 if (!strcasecmp(resource, "MIMETYPES")) {
6217 initMimeTypes();
6218 return;
6219 }
6220
6221 #ifdef USE_EXTERNAL_URI_LOADER
6222 if (!strcasecmp(resource, "URIMETHODS")) {
6223 initURIMethods();
6224 return;
6225 }
6226 #endif
6227
6228 disp_err_message(Sprintf("Don't know how to reinitialize '%s'", resource)->
6229 ptr, FALSE);
6230 }
6231
6232 DEFUN(defKey, DEFINE_KEY, "Define a binding between a key stroke combination and a command")
6233 {
6234 char *data;
6235
6236 CurrentKeyData = NULL; /* not allowed in w3m-control: */
6237 data = searchKeyData();
6238 if (data == NULL || *data == '\0') {
6239 data = inputStrHist("Key definition: ", "", TextHist);
6240 if (data == NULL || *data == '\0') {
6241 displayBuffer(Currentbuf, B_NORMAL);
6242 return;
6243 }
6244 }
6245 setKeymap(allocStr(data, -1), -1, TRUE);
6246 displayBuffer(Currentbuf, B_NORMAL);
6247 }
6248
6249 TabBuffer *
newTab(void)6250 newTab(void)
6251 {
6252 TabBuffer *n;
6253
6254 n = New(TabBuffer);
6255 if (n == NULL)
6256 return NULL;
6257 n->nextTab = NULL;
6258 n->currentBuffer = NULL;
6259 n->firstBuffer = NULL;
6260 return n;
6261 }
6262
6263 static void
_newT(void)6264 _newT(void)
6265 {
6266 TabBuffer *tag;
6267 Buffer *buf;
6268 int i;
6269
6270 tag = newTab();
6271 if (!tag)
6272 return;
6273
6274 buf = newBuffer(Currentbuf->width);
6275 copyBuffer(buf, Currentbuf);
6276 buf->nextBuffer = NULL;
6277 for (i = 0; i < MAX_LB; i++)
6278 buf->linkBuffer[i] = NULL;
6279 (*buf->clone)++;
6280 tag->firstBuffer = tag->currentBuffer = buf;
6281
6282 tag->nextTab = CurrentTab->nextTab;
6283 tag->prevTab = CurrentTab;
6284 if (CurrentTab->nextTab)
6285 CurrentTab->nextTab->prevTab = tag;
6286 else
6287 LastTab = tag;
6288 CurrentTab->nextTab = tag;
6289 CurrentTab = tag;
6290 nTab++;
6291 }
6292
6293 DEFUN(newT, NEW_TAB, "Open a new tab (with current document)")
6294 {
6295 _newT();
6296 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
6297 }
6298
6299 static TabBuffer *
numTab(int n)6300 numTab(int n)
6301 {
6302 TabBuffer *tab;
6303 int i;
6304
6305 if (n == 0)
6306 return CurrentTab;
6307 if (n == 1)
6308 return FirstTab;
6309 if (nTab <= 1)
6310 return NULL;
6311 for (tab = FirstTab, i = 1; tab && i < n; tab = tab->nextTab, i++) ;
6312 return tab;
6313 }
6314
6315 void
calcTabPos(void)6316 calcTabPos(void)
6317 {
6318 TabBuffer *tab;
6319 #if 0
6320 int lcol = 0, rcol = 2, col;
6321 #else
6322 int lcol = 0, rcol = 0, col;
6323 #endif
6324 int n1, n2, na, nx, ny, ix, iy;
6325
6326 #ifdef USE_MOUSE
6327 lcol = mouse_action.menu_str ? mouse_action.menu_width : 0;
6328 #endif
6329
6330 if (nTab <= 0)
6331 return;
6332 n1 = (COLS - rcol - lcol) / TabCols;
6333 if (n1 >= nTab) {
6334 n2 = 1;
6335 ny = 1;
6336 }
6337 else {
6338 if (n1 < 0)
6339 n1 = 0;
6340 n2 = COLS / TabCols;
6341 if (n2 == 0)
6342 n2 = 1;
6343 ny = (nTab - n1 - 1) / n2 + 2;
6344 }
6345 na = n1 + n2 * (ny - 1);
6346 n1 -= (na - nTab) / ny;
6347 if (n1 < 0)
6348 n1 = 0;
6349 na = n1 + n2 * (ny - 1);
6350 tab = FirstTab;
6351 for (iy = 0; iy < ny && tab; iy++) {
6352 if (iy == 0) {
6353 nx = n1;
6354 col = COLS - rcol - lcol;
6355 }
6356 else {
6357 nx = n2 - (na - nTab + (iy - 1)) / (ny - 1);
6358 col = COLS;
6359 }
6360 for (ix = 0; ix < nx && tab; ix++, tab = tab->nextTab) {
6361 tab->x1 = col * ix / nx;
6362 tab->x2 = col * (ix + 1) / nx - 1;
6363 tab->y = iy;
6364 if (iy == 0) {
6365 tab->x1 += lcol;
6366 tab->x2 += lcol;
6367 }
6368 }
6369 }
6370 }
6371
6372 TabBuffer *
deleteTab(TabBuffer * tab)6373 deleteTab(TabBuffer * tab)
6374 {
6375 Buffer *buf, *next;
6376
6377 if (nTab <= 1)
6378 return FirstTab;
6379 if (tab->prevTab) {
6380 if (tab->nextTab)
6381 tab->nextTab->prevTab = tab->prevTab;
6382 else
6383 LastTab = tab->prevTab;
6384 tab->prevTab->nextTab = tab->nextTab;
6385 if (tab == CurrentTab)
6386 CurrentTab = tab->prevTab;
6387 }
6388 else { /* tab == FirstTab */
6389 tab->nextTab->prevTab = NULL;
6390 FirstTab = tab->nextTab;
6391 if (tab == CurrentTab)
6392 CurrentTab = tab->nextTab;
6393 }
6394 nTab--;
6395 buf = tab->firstBuffer;
6396 while (buf && buf != NO_BUFFER) {
6397 next = buf->nextBuffer;
6398 discardBuffer(buf);
6399 buf = next;
6400 }
6401 return FirstTab;
6402 }
6403
6404 DEFUN(closeT, CLOSE_TAB, "Close tab")
6405 {
6406 TabBuffer *tab;
6407
6408 if (nTab <= 1)
6409 return;
6410 if (prec_num)
6411 tab = numTab(PREC_NUM);
6412 else
6413 tab = CurrentTab;
6414 if (tab)
6415 deleteTab(tab);
6416 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
6417 }
6418
6419 DEFUN(nextT, NEXT_TAB, "Switch to the next tab")
6420 {
6421 int i;
6422
6423 if (nTab <= 1)
6424 return;
6425 for (i = 0; i < PREC_NUM; i++) {
6426 if (CurrentTab->nextTab)
6427 CurrentTab = CurrentTab->nextTab;
6428 else
6429 CurrentTab = FirstTab;
6430 }
6431 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
6432 }
6433
6434 DEFUN(prevT, PREV_TAB, "Switch to the previous tab")
6435 {
6436 int i;
6437
6438 if (nTab <= 1)
6439 return;
6440 for (i = 0; i < PREC_NUM; i++) {
6441 if (CurrentTab->prevTab)
6442 CurrentTab = CurrentTab->prevTab;
6443 else
6444 CurrentTab = LastTab;
6445 }
6446 displayBuffer(Currentbuf, B_REDRAW_IMAGE);
6447 }
6448
6449 static void
followTab(TabBuffer * tab)6450 followTab(TabBuffer * tab)
6451 {
6452 Buffer *buf;
6453 Anchor *a;
6454
6455 #ifdef USE_IMAGE
6456 a = retrieveCurrentImg(Currentbuf);
6457 if (!(a && a->image && a->image->map))
6458 #endif
6459 a = retrieveCurrentAnchor(Currentbuf);
6460 if (a == NULL)
6461 return;
6462
6463 if (tab == CurrentTab) {
6464 check_target = FALSE;
6465 followA();
6466 check_target = TRUE;
6467 return;
6468 }
6469 _newT();
6470 buf = Currentbuf;
6471 check_target = FALSE;
6472 followA();
6473 check_target = TRUE;
6474 if (tab == NULL) {
6475 if (buf != Currentbuf)
6476 delBuffer(buf);
6477 else
6478 deleteTab(CurrentTab);
6479 }
6480 else if (buf != Currentbuf) {
6481 /* buf <- p <- ... <- Currentbuf = c */
6482 Buffer *c, *p;
6483
6484 c = Currentbuf;
6485 p = prevBuffer(c, buf);
6486 p->nextBuffer = NULL;
6487 Firstbuf = buf;
6488 deleteTab(CurrentTab);
6489 CurrentTab = tab;
6490 for (buf = p; buf; buf = p) {
6491 p = prevBuffer(c, buf);
6492 pushBuffer(buf);
6493 }
6494 }
6495 displayBuffer(Currentbuf, B_FORCE_REDRAW);
6496 }
6497
6498 DEFUN(tabA, TAB_LINK, "Follow current hyperlink in a new tab")
6499 {
6500 followTab(prec_num ? numTab(PREC_NUM) : NULL);
6501 }
6502
6503 static void
tabURL0(TabBuffer * tab,char * prompt,int relative)6504 tabURL0(TabBuffer * tab, char *prompt, int relative)
6505 {
6506 Buffer *buf;
6507
6508 if (tab == CurrentTab) {
6509 goURL0(prompt, relative);
6510 return;
6511 }
6512 _newT();
6513 buf = Currentbuf;
6514 goURL0(prompt, relative);
6515 if (tab == NULL) {
6516 if (buf != Currentbuf)
6517 delBuffer(buf);
6518 else
6519 deleteTab(CurrentTab);
6520 }
6521 else if (buf != Currentbuf) {
6522 /* buf <- p <- ... <- Currentbuf = c */
6523 Buffer *c, *p;
6524
6525 c = Currentbuf;
6526 p = prevBuffer(c, buf);
6527 p->nextBuffer = NULL;
6528 Firstbuf = buf;
6529 deleteTab(CurrentTab);
6530 CurrentTab = tab;
6531 for (buf = p; buf; buf = p) {
6532 p = prevBuffer(c, buf);
6533 pushBuffer(buf);
6534 }
6535 }
6536 displayBuffer(Currentbuf, B_FORCE_REDRAW);
6537 }
6538
6539 DEFUN(tabURL, TAB_GOTO, "Open specified document in a new tab")
6540 {
6541 tabURL0(prec_num ? numTab(PREC_NUM) : NULL,
6542 "Goto URL on new tab: ", FALSE);
6543 }
6544
6545 DEFUN(tabrURL, TAB_GOTO_RELATIVE, "Open relative address in a new tab")
6546 {
6547 tabURL0(prec_num ? numTab(PREC_NUM) : NULL,
6548 "Goto relative URL on new tab: ", TRUE);
6549 }
6550
6551 static void
moveTab(TabBuffer * t,TabBuffer * t2,int right)6552 moveTab(TabBuffer * t, TabBuffer * t2, int right)
6553 {
6554 if (t2 == NO_TABBUFFER)
6555 t2 = FirstTab;
6556 if (!t || !t2 || t == t2 || t == NO_TABBUFFER)
6557 return;
6558 if (t->prevTab) {
6559 if (t->nextTab)
6560 t->nextTab->prevTab = t->prevTab;
6561 else
6562 LastTab = t->prevTab;
6563 t->prevTab->nextTab = t->nextTab;
6564 }
6565 else {
6566 t->nextTab->prevTab = NULL;
6567 FirstTab = t->nextTab;
6568 }
6569 if (right) {
6570 t->nextTab = t2->nextTab;
6571 t->prevTab = t2;
6572 if (t2->nextTab)
6573 t2->nextTab->prevTab = t;
6574 else
6575 LastTab = t;
6576 t2->nextTab = t;
6577 }
6578 else {
6579 t->prevTab = t2->prevTab;
6580 t->nextTab = t2;
6581 if (t2->prevTab)
6582 t2->prevTab->nextTab = t;
6583 else
6584 FirstTab = t;
6585 t2->prevTab = t;
6586 }
6587 displayBuffer(Currentbuf, B_FORCE_REDRAW);
6588 }
6589
6590 DEFUN(tabR, TAB_RIGHT, "Move right along the tab bar")
6591 {
6592 TabBuffer *tab;
6593 int i;
6594
6595 for (tab = CurrentTab, i = 0; tab && i < PREC_NUM;
6596 tab = tab->nextTab, i++) ;
6597 moveTab(CurrentTab, tab ? tab : LastTab, TRUE);
6598 }
6599
6600 DEFUN(tabL, TAB_LEFT, "Move left along the tab bar")
6601 {
6602 TabBuffer *tab;
6603 int i;
6604
6605 for (tab = CurrentTab, i = 0; tab && i < PREC_NUM;
6606 tab = tab->prevTab, i++) ;
6607 moveTab(CurrentTab, tab ? tab : FirstTab, FALSE);
6608 }
6609
6610 void
addDownloadList(pid_t pid,char * url,char * save,char * lock,clen_t size)6611 addDownloadList(pid_t pid, char *url, char *save, char *lock, clen_t size)
6612 {
6613 DownloadList *d;
6614
6615 d = New(DownloadList);
6616 d->pid = pid;
6617 d->url = url;
6618 if (save[0] != '/' && save[0] != '~')
6619 save = Strnew_m_charp(CurrentDir, "/", save, NULL)->ptr;
6620 d->save = expandPath(save);
6621 d->lock = lock;
6622 d->size = size;
6623 d->time = time(0);
6624 d->running = TRUE;
6625 d->err = 0;
6626 d->next = NULL;
6627 d->prev = LastDL;
6628 if (LastDL)
6629 LastDL->next = d;
6630 else
6631 FirstDL = d;
6632 LastDL = d;
6633 add_download_list = TRUE;
6634 }
6635
6636 int
checkDownloadList(void)6637 checkDownloadList(void)
6638 {
6639 DownloadList *d;
6640 struct stat st;
6641
6642 if (!FirstDL)
6643 return FALSE;
6644 for (d = FirstDL; d != NULL; d = d->next) {
6645 if (d->running && !lstat(d->lock, &st))
6646 return TRUE;
6647 }
6648 return FALSE;
6649 }
6650
6651 static char *
convert_size3(clen_t size)6652 convert_size3(clen_t size)
6653 {
6654 Str tmp = Strnew();
6655 int n;
6656
6657 do {
6658 n = size % 1000;
6659 size /= 1000;
6660 tmp = Sprintf(size ? ",%.3d%s" : "%d%s", n, tmp->ptr);
6661 } while (size);
6662 return tmp->ptr;
6663 }
6664
6665 static Buffer *
DownloadListBuffer(void)6666 DownloadListBuffer(void)
6667 {
6668 DownloadList *d;
6669 Str src = NULL;
6670 struct stat st;
6671 time_t cur_time;
6672 int duration, rate, eta;
6673 size_t size;
6674
6675 if (!FirstDL)
6676 return NULL;
6677 cur_time = time(0);
6678 /* FIXME: gettextize? */
6679 src = Strnew_charp("<html><head><title>" DOWNLOAD_LIST_TITLE
6680 "</title></head>\n<body><h1 align=center>"
6681 DOWNLOAD_LIST_TITLE "</h1>\n"
6682 "<form method=internal action=download><hr>\n");
6683 for (d = LastDL; d != NULL; d = d->prev) {
6684 if (lstat(d->lock, &st))
6685 d->running = FALSE;
6686 Strcat_charp(src, "<pre>\n");
6687 Strcat(src, Sprintf("%s\n --> %s\n ", html_quote(d->url),
6688 html_quote(conv_from_system(d->save))));
6689 duration = cur_time - d->time;
6690 if (!stat(d->save, &st)) {
6691 size = st.st_size;
6692 if (!d->running) {
6693 if (!d->err)
6694 d->size = size;
6695 duration = st.st_mtime - d->time;
6696 }
6697 }
6698 else
6699 size = 0;
6700 if (d->size) {
6701 int i, l = COLS - 6;
6702 if (size < d->size)
6703 i = 1.0 * l * size / d->size;
6704 else
6705 i = l;
6706 l -= i;
6707 while (i-- > 0)
6708 Strcat_char(src, '#');
6709 while (l-- > 0)
6710 Strcat_char(src, '_');
6711 Strcat_char(src, '\n');
6712 }
6713 if ((d->running || d->err) && size < d->size)
6714 Strcat(src, Sprintf(" %s / %s bytes (%d%%)",
6715 convert_size3(size), convert_size3(d->size),
6716 (int)(100.0 * size / d->size)));
6717 else
6718 Strcat(src, Sprintf(" %s bytes loaded", convert_size3(size)));
6719 if (duration > 0) {
6720 rate = size / duration;
6721 Strcat(src, Sprintf(" %02d:%02d:%02d rate %s/sec",
6722 duration / (60 * 60), (duration / 60) % 60,
6723 duration % 60, convert_size(rate, 1)));
6724 if (d->running && size < d->size && rate) {
6725 eta = (d->size - size) / rate;
6726 Strcat(src, Sprintf(" eta %02d:%02d:%02d", eta / (60 * 60),
6727 (eta / 60) % 60, eta % 60));
6728 }
6729 }
6730 Strcat_char(src, '\n');
6731 if (!d->running) {
6732 Strcat(src, Sprintf("<input type=submit name=ok%d value=OK>",
6733 d->pid));
6734 switch (d->err) {
6735 case 0: if (size < d->size)
6736 Strcat_charp(src, " Download ended but probably not complete");
6737 else
6738 Strcat_charp(src, " Download complete");
6739 break;
6740 case 1: Strcat_charp(src, " Error: could not open destination file");
6741 break;
6742 case 2: Strcat_charp(src, " Error: could not write to file (disk full)");
6743 break;
6744 default: Strcat_charp(src, " Error: unknown reason");
6745 }
6746 }
6747 else
6748 Strcat(src, Sprintf("<input type=submit name=stop%d value=STOP>",
6749 d->pid));
6750 Strcat_charp(src, "\n</pre><hr>\n");
6751 }
6752 Strcat_charp(src, "</form></body></html>");
6753 return loadHTMLString(src);
6754 }
6755
6756 void
download_action(struct parsed_tagarg * arg)6757 download_action(struct parsed_tagarg *arg)
6758 {
6759 DownloadList *d;
6760 pid_t pid;
6761
6762 for (; arg; arg = arg->next) {
6763 if (!strncmp(arg->arg, "stop", 4)) {
6764 pid = (pid_t) atoi(&arg->arg[4]);
6765 #ifndef __MINGW32_VERSION
6766 kill(pid, SIGKILL);
6767 #endif
6768 }
6769 else if (!strncmp(arg->arg, "ok", 2))
6770 pid = (pid_t) atoi(&arg->arg[2]);
6771 else
6772 continue;
6773 for (d = FirstDL; d; d = d->next) {
6774 if (d->pid == pid) {
6775 unlink(d->lock);
6776 if (d->prev)
6777 d->prev->next = d->next;
6778 else
6779 FirstDL = d->next;
6780 if (d->next)
6781 d->next->prev = d->prev;
6782 else
6783 LastDL = d->prev;
6784 break;
6785 }
6786 }
6787 }
6788 ldDL();
6789 }
6790
6791 void
stopDownload(void)6792 stopDownload(void)
6793 {
6794 DownloadList *d;
6795
6796 if (!FirstDL)
6797 return;
6798 for (d = FirstDL; d != NULL; d = d->next) {
6799 if (!d->running)
6800 continue;
6801 #ifndef __MINGW32_VERSION
6802 kill(d->pid, SIGKILL);
6803 #endif
6804 unlink(d->lock);
6805 }
6806 }
6807
6808 /* download panel */
6809 DEFUN(ldDL, DOWNLOAD_LIST, "Display downloads panel")
6810 {
6811 Buffer *buf;
6812 int replace = FALSE, new_tab = FALSE;
6813 #ifdef USE_ALARM
6814 int reload;
6815 #endif
6816
6817 if (Currentbuf->bufferprop & BP_INTERNAL &&
6818 !strcmp(Currentbuf->buffername, DOWNLOAD_LIST_TITLE))
6819 replace = TRUE;
6820 if (!FirstDL) {
6821 if (replace) {
6822 if (Currentbuf == Firstbuf && Currentbuf->nextBuffer == NULL) {
6823 if (nTab > 1)
6824 deleteTab(CurrentTab);
6825 }
6826 else
6827 delBuffer(Currentbuf);
6828 displayBuffer(Currentbuf, B_FORCE_REDRAW);
6829 }
6830 return;
6831 }
6832 #ifdef USE_ALARM
6833 reload = checkDownloadList();
6834 #endif
6835 buf = DownloadListBuffer();
6836 if (!buf) {
6837 displayBuffer(Currentbuf, B_NORMAL);
6838 return;
6839 }
6840 buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
6841 if (replace) {
6842 COPY_BUFROOT(buf, Currentbuf);
6843 restorePosition(buf, Currentbuf);
6844 }
6845 if (!replace && open_tab_dl_list) {
6846 _newT();
6847 new_tab = TRUE;
6848 }
6849 pushBuffer(buf);
6850 if (replace || new_tab)
6851 deletePrevBuf();
6852 #ifdef USE_ALARM
6853 if (reload)
6854 Currentbuf->event = setAlarmEvent(Currentbuf->event, 1, AL_IMPLICIT,
6855 FUNCNAME_reload, NULL);
6856 #endif
6857 displayBuffer(Currentbuf, B_FORCE_REDRAW);
6858 }
6859
6860 static void
save_buffer_position(Buffer * buf)6861 save_buffer_position(Buffer *buf)
6862 {
6863 BufferPos *b = buf->undo;
6864
6865 if (!buf->firstLine)
6866 return;
6867 if (b && b->top_linenumber == TOP_LINENUMBER(buf) &&
6868 b->cur_linenumber == CUR_LINENUMBER(buf) &&
6869 b->currentColumn == buf->currentColumn && b->pos == buf->pos)
6870 return;
6871 b = New(BufferPos);
6872 b->top_linenumber = TOP_LINENUMBER(buf);
6873 b->cur_linenumber = CUR_LINENUMBER(buf);
6874 b->currentColumn = buf->currentColumn;
6875 b->pos = buf->pos;
6876 b->bpos = buf->currentLine ? buf->currentLine->bpos : 0;
6877 b->next = NULL;
6878 b->prev = buf->undo;
6879 if (buf->undo)
6880 buf->undo->next = b;
6881 buf->undo = b;
6882 }
6883
6884 static void
resetPos(BufferPos * b)6885 resetPos(BufferPos * b)
6886 {
6887 Buffer buf;
6888 Line top, cur;
6889
6890 top.linenumber = b->top_linenumber;
6891 cur.linenumber = b->cur_linenumber;
6892 cur.bpos = b->bpos;
6893 buf.topLine = ⊤
6894 buf.currentLine = &cur;
6895 buf.pos = b->pos;
6896 buf.currentColumn = b->currentColumn;
6897 restorePosition(Currentbuf, &buf);
6898 Currentbuf->undo = b;
6899 displayBuffer(Currentbuf, B_FORCE_REDRAW);
6900 }
6901
6902 DEFUN(undoPos, UNDO, "Cancel the last cursor movement")
6903 {
6904 BufferPos *b = Currentbuf->undo;
6905 int i;
6906
6907 if (!Currentbuf->firstLine)
6908 return;
6909 if (!b || !b->prev)
6910 return;
6911 for (i = 0; i < PREC_NUM && b->prev; i++, b = b->prev) ;
6912 resetPos(b);
6913 }
6914
6915 DEFUN(redoPos, REDO, "Cancel the last undo")
6916 {
6917 BufferPos *b = Currentbuf->undo;
6918 int i;
6919
6920 if (!Currentbuf->firstLine)
6921 return;
6922 if (!b || !b->next)
6923 return;
6924 for (i = 0; i < PREC_NUM && b->next; i++, b = b->next) ;
6925 resetPos(b);
6926 }
6927
6928 DEFUN(cursorTop, CURSOR_TOP, "Move cursor to the top of the screen")
6929 {
6930 if (Currentbuf->firstLine == NULL)
6931 return;
6932 Currentbuf->currentLine = lineSkip(Currentbuf, Currentbuf->topLine,
6933 0, FALSE);
6934 arrangeLine(Currentbuf);
6935 displayBuffer(Currentbuf, B_NORMAL);
6936 }
6937
6938 DEFUN(cursorMiddle, CURSOR_MIDDLE, "Move cursor to the middle of the screen")
6939 {
6940 int offsety;
6941 if (Currentbuf->firstLine == NULL)
6942 return;
6943 offsety = (Currentbuf->LINES - 1) / 2;
6944 Currentbuf->currentLine = currentLineSkip(Currentbuf, Currentbuf->topLine,
6945 offsety, FALSE);
6946 arrangeLine(Currentbuf);
6947 displayBuffer(Currentbuf, B_NORMAL);
6948 }
6949
6950 DEFUN(cursorBottom, CURSOR_BOTTOM, "Move cursor to the bottom of the screen")
6951 {
6952 int offsety;
6953 if (Currentbuf->firstLine == NULL)
6954 return;
6955 offsety = Currentbuf->LINES - 1;
6956 Currentbuf->currentLine = currentLineSkip(Currentbuf, Currentbuf->topLine,
6957 offsety, FALSE);
6958 arrangeLine(Currentbuf);
6959 displayBuffer(Currentbuf, B_NORMAL);
6960 }
6961