/* $Id: main.c,v 1.270 2010/08/24 10:11:51 htrb Exp $ */ #define MAINPROGRAM #include "fm.h" #include #include #include #include #include #include #include #if defined(HAVE_WAITPID) || defined(HAVE_WAIT3) #include #endif #include #if defined(__CYGWIN__) && defined(USE_BINMODE_STREAM) #include #endif #include "terms.h" #include "myctype.h" #include "regex.h" #ifdef USE_M17N #include "wc.h" #include "wtf.h" #ifdef USE_UNICODE #include "ucs.h" #endif #endif #ifdef USE_MOUSE #ifdef USE_GPM #include #endif /* USE_GPM */ #if defined(USE_GPM) || defined(USE_SYSMOUSE) extern int do_getch(); #define getch() do_getch() #endif /* defined(USE_GPM) || defined(USE_SYSMOUSE) */ #endif #ifdef __MINGW32_VERSION #include WSADATA WSAData; #endif #define DSTR_LEN 256 Hist *LoadHist; Hist *SaveHist; Hist *URLHist; Hist *ShellHist; Hist *TextHist; typedef struct _Event { int cmd; void *data; struct _Event *next; } Event; static Event *CurrentEvent = NULL; static Event *LastEvent = NULL; #ifdef USE_ALARM static AlarmEvent DefaultAlarm = { 0, AL_UNSET, FUNCNAME_nulcmd, NULL }; static AlarmEvent *CurrentAlarm = &DefaultAlarm; static MySignalHandler SigAlarm(SIGNAL_ARG); #endif #ifdef SIGWINCH static int need_resize_screen = FALSE; static MySignalHandler resize_hook(SIGNAL_ARG); static void resize_screen(void); #endif #ifdef SIGPIPE static MySignalHandler SigPipe(SIGNAL_ARG); #endif #ifdef USE_MARK static char *MarkString = NULL; #endif static char *SearchString = NULL; int (*searchRoutine) (Buffer *, char *); #ifndef __MINGW32_VERSION JMP_BUF IntReturn; #else _JBTYPE IntReturn[_JBLEN]; #endif /* __MINGW32_VERSION */ static void delBuffer(Buffer *buf); static void cmd_loadfile(char *path); static void cmd_loadURL(char *url, ParsedURL *current, char *referer, FormList *request); static void cmd_loadBuffer(Buffer *buf, int prop, int linkid); static void keyPressEventProc(int c); int show_params_p = 0; void show_params(FILE * fp); static char *getCurWord(Buffer *buf, int *spos, int *epos); static int display_ok = FALSE; static void do_dump(Buffer *); int prec_num = 0; int prev_key = -1; int on_target = 1; static int add_download_list = FALSE; void set_buffer_environ(Buffer *); static void save_buffer_position(Buffer *buf); static void _followForm(int); static void _goLine(char *); static void _newT(void); static void followTab(TabBuffer * tab); static void moveTab(TabBuffer * t, TabBuffer * t2, int right); static void _nextA(int); static void _prevA(int); static int check_target = TRUE; #define PREC_NUM (prec_num ? prec_num : 1) #define PREC_LIMIT 10000 static int searchKeyNum(void); #define help() fusage(stdout, 0) #define usage() fusage(stderr, 1) int enable_inline_image; /* 1 == mlterm OSC 5379, 2 == sixel */ static void fversion(FILE * f) { fprintf(f, "w3m version %s, options %s\n", w3m_version, #if LANG == JA "lang=ja" #else "lang=en" #endif #ifdef USE_M17N ",m17n" #endif #ifdef USE_IMAGE ",image" #endif #ifdef USE_COLOR ",color" #ifdef USE_ANSI_COLOR ",ansi-color" #endif #endif #ifdef USE_MOUSE ",mouse" #ifdef USE_GPM ",gpm" #endif #ifdef USE_SYSMOUSE ",sysmouse" #endif #endif #ifdef USE_MENU ",menu" #endif #ifdef USE_COOKIE ",cookie" #endif #ifdef USE_SSL ",ssl" #ifdef USE_SSL_VERIFY ",ssl-verify" #endif #endif #ifdef USE_EXTERNAL_URI_LOADER ",external-uri-loader" #endif #ifdef USE_W3MMAILER ",w3mmailer" #endif #ifdef USE_NNTP ",nntp" #endif #ifdef USE_GOPHER ",gopher" #endif #ifdef INET6 ",ipv6" #endif #ifdef USE_ALARM ",alarm" #endif #ifdef USE_MARK ",mark" #endif #ifdef USE_MIGEMO ",migemo" #endif ); } static void fusage(FILE * f, int err) { fversion(f); /* FIXME: gettextize? */ fprintf(f, "usage: w3m [options] [URL or filename]\noptions:\n"); fprintf(f, " -t tab set tab width\n"); fprintf(f, " -r ignore backspace effect\n"); fprintf(f, " -l line # of preserved line (default 10000)\n"); #ifdef USE_M17N fprintf(f, " -I charset document charset\n"); fprintf(f, " -O charset display/output charset\n"); #if 0 /* use -O{s|j|e} instead */ fprintf(f, " -e EUC-JP\n"); fprintf(f, " -s Shift_JIS\n"); fprintf(f, " -j JIS\n"); #endif #endif fprintf(f, " -B load bookmark\n"); fprintf(f, " -bookmark file specify bookmark file\n"); fprintf(f, " -T type specify content-type\n"); fprintf(f, " -m internet message mode\n"); fprintf(f, " -v visual startup mode\n"); #ifdef USE_COLOR fprintf(f, " -M monochrome display\n"); #endif /* USE_COLOR */ fprintf(f, " -N open URL of command line on each new tab\n"); fprintf(f, " -F automatically render frames\n"); fprintf(f, " -cols width specify column width (used with -dump)\n"); fprintf(f, " -ppc count specify the number of pixels per character (4.0...32.0)\n"); #ifdef USE_IMAGE fprintf(f, " -ppl count specify the number of pixels per line (4.0...64.0)\n"); #endif fprintf(f, " -dump dump formatted page into stdout\n"); fprintf(f, " -dump_head dump response of HEAD request into stdout\n"); fprintf(f, " -dump_source dump page source into stdout\n"); fprintf(f, " -dump_both dump HEAD and source into stdout\n"); fprintf(f, " -dump_extra dump HEAD, source, and extra information into stdout\n"); fprintf(f, " -post file use POST method with file content\n"); fprintf(f, " -header string insert string as a header\n"); fprintf(f, " + goto line\n"); fprintf(f, " -num show line number\n"); fprintf(f, " -no-proxy don't use proxy\n"); #ifdef INET6 fprintf(f, " -4 IPv4 only (-o dns_order=4)\n"); fprintf(f, " -6 IPv6 only (-o dns_order=6)\n"); #endif #ifdef USE_MOUSE fprintf(f, " -no-mouse don't use mouse\n"); #endif /* USE_MOUSE */ #ifdef USE_COOKIE fprintf(f, " -cookie use cookie (-no-cookie: don't use cookie)\n"); #endif /* USE_COOKIE */ fprintf(f, " -graph use DEC special graphics for border of table and menu\n"); fprintf(f, " -no-graph use ASCII character for border of table and menu\n"); #if 1 /* pager requires -s */ fprintf(f, " -s squeeze multiple blank lines\n"); #else fprintf(f, " -S squeeze multiple blank lines\n"); #endif fprintf(f, " -W toggle search wrap mode\n"); fprintf(f, " -X don't use termcap init/deinit\n"); fprintf(f, " -title[=TERM] set buffer name to terminal title string\n"); fprintf(f, " -o opt=value assign value to config option\n"); fprintf(f, " -show-option print all config options\n"); fprintf(f, " -config file specify config file\n"); fprintf(f, " -help print this usage message\n"); fprintf(f, " -version print w3m version\n"); fprintf(f, " -reqlog write request logfile\n"); fprintf(f, " -debug DO NOT USE\n"); if (show_params_p) show_params(f); exit(err); } #ifdef USE_M17N #ifdef __EMX__ static char *getCodePage(void); #endif #endif static GC_warn_proc orig_GC_warn_proc = NULL; #define GC_WARN_KEEP_MAX (20) static void wrap_GC_warn_proc(char *msg, GC_word arg) { if (fmInitialized) { /* *INDENT-OFF* */ static struct { char *msg; GC_word arg; } msg_ring[GC_WARN_KEEP_MAX]; /* *INDENT-ON* */ static int i = 0; static int n = 0; static int lock = 0; int j; j = (i + n) % (sizeof(msg_ring) / sizeof(msg_ring[0])); msg_ring[j].msg = msg; msg_ring[j].arg = arg; if (n < sizeof(msg_ring) / sizeof(msg_ring[0])) ++n; else ++i; if (!lock) { lock = 1; for (; n > 0; --n, ++i) { i %= sizeof(msg_ring) / sizeof(msg_ring[0]); printf(msg_ring[i].msg, (unsigned long)msg_ring[i].arg); sleep_till_anykey(1, 1); } lock = 0; } } else if (orig_GC_warn_proc) orig_GC_warn_proc(msg, arg); else fprintf(stderr, msg, (unsigned long)arg); } #ifdef SIGCHLD static void sig_chld(int signo) { int p_stat; pid_t pid; #ifdef HAVE_WAITPID while ((pid = waitpid(-1, &p_stat, WNOHANG)) > 0) #elif HAVE_WAIT3 while ((pid = wait3(&p_stat, WNOHANG, NULL)) > 0) #else if ((pid = wait(&p_stat)) > 0) #endif { DownloadList *d; if (WIFEXITED(p_stat)) { for (d = FirstDL; d != NULL; d = d->next) { if (d->pid == pid) { d->err = WEXITSTATUS(p_stat); break; } } } } mySignal(SIGCHLD, sig_chld); return; } #endif Str make_optional_header_string(char *s) { char *p; Str hs; if (strchr(s, '\n') || strchr(s, '\r')) return NULL; for (p = s; *p && *p != ':'; p++) ; if (*p != ':' || p == s) return NULL; hs = Strnew_size(strlen(s) + 3); Strcopy_charp_n(hs, s, p - s); if (!Strcasecmp_charp(hs, "content-type")) override_content_type = TRUE; if (!Strcasecmp_charp(hs, "user-agent")) override_user_agent = TRUE; Strcat_charp(hs, ": "); if (*(++p)) { /* not null header */ SKIP_BLANKS(p); /* skip white spaces */ Strcat_charp(hs, p); } Strcat_charp(hs, "\r\n"); return hs; } static void * die_oom(size_t bytes) { fprintf(stderr, "Out of memory: %lu bytes unavailable!\n", (unsigned long)bytes); exit(1); } int main(int argc, char **argv, char **envp) { Buffer *newbuf = NULL; char *p; int c, i; InputStream redin; char *line_str = NULL; char **load_argv; FormList *request; int load_argc = 0; int load_bookmark = FALSE; int visual_start = FALSE; int open_new_tab = FALSE; char search_header = FALSE; char *default_type = NULL; char *post_file = NULL; Str err_msg; #ifdef USE_M17N char *Locale = NULL; wc_uint8 auto_detect; #ifdef __EMX__ wc_ces CodePage; #endif #endif #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) char **getimage_args = NULL; #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ GC_INIT(); #if (GC_VERSION_MAJOR>7) || ((GC_VERSION_MAJOR==7) && (GC_VERSION_MINOR>=2)) GC_set_oom_fn(die_oom); #else GC_oom_fn = die_oom; #endif #if defined(ENABLE_NLS) || (defined(USE_M17N) && defined(HAVE_LANGINFO_CODESET)) setlocale(LC_ALL, ""); #endif #ifdef ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif NO_proxy_domains = newTextList(); fileToDelete = newTextList(); load_argv = New_N(char *, argc - 1); load_argc = 0; CurrentDir = currentdir(); CurrentPid = (int)getpid(); #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) if (argv[0] && *argv[0]) MyProgramName = argv[0]; #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ BookmarkFile = NULL; config_file = NULL; /* argument search 1 */ for (i = 1; i < argc; i++) { if (*argv[i] == '-') { if (!strcmp("-config", argv[i])) { argv[i] = "-dummy"; if (++i >= argc) usage(); config_file = argv[i]; argv[i] = "-dummy"; } else if (!strcmp("-h", argv[i]) || !strcmp("-help", argv[i])) help(); else if (!strcmp("-V", argv[i]) || !strcmp("-version", argv[i])) { fversion(stdout); exit(0); } } } #ifdef USE_M17N if (non_null(Locale = getenv("LC_ALL")) || non_null(Locale = getenv("LC_CTYPE")) || non_null(Locale = getenv("LANG"))) { DisplayCharset = wc_guess_locale_charset(Locale, DisplayCharset); DocumentCharset = wc_guess_locale_charset(Locale, DocumentCharset); SystemCharset = wc_guess_locale_charset(Locale, SystemCharset); } #ifdef __EMX__ CodePage = wc_guess_charset(getCodePage(), 0); if (CodePage) DisplayCharset = DocumentCharset = SystemCharset = CodePage; #endif #endif /* initializations */ init_rc(); LoadHist = newHist(); SaveHist = newHist(); ShellHist = newHist(); TextHist = newHist(); URLHist = newHist(); #ifdef USE_M17N if (FollowLocale && Locale) { DisplayCharset = wc_guess_locale_charset(Locale, DisplayCharset); SystemCharset = wc_guess_locale_charset(Locale, SystemCharset); } auto_detect = WcOption.auto_detect; BookmarkCharset = DocumentCharset; #endif if (!non_null(HTTP_proxy) && ((p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy")) || (p = getenv("HTTP_proxy")))) HTTP_proxy = p; #ifdef USE_SSL if (!non_null(HTTPS_proxy) && ((p = getenv("HTTPS_PROXY")) || (p = getenv("https_proxy")) || (p = getenv("HTTPS_proxy")))) HTTPS_proxy = p; if (HTTPS_proxy == NULL && non_null(HTTP_proxy)) HTTPS_proxy = HTTP_proxy; #endif /* USE_SSL */ #ifdef USE_GOPHER if (!non_null(GOPHER_proxy) && ((p = getenv("GOPHER_PROXY")) || (p = getenv("gopher_proxy")) || (p = getenv("GOPHER_proxy")))) GOPHER_proxy = p; #endif /* USE_GOPHER */ if (!non_null(FTP_proxy) && ((p = getenv("FTP_PROXY")) || (p = getenv("ftp_proxy")) || (p = getenv("FTP_proxy")))) FTP_proxy = p; if (!non_null(NO_proxy) && ((p = getenv("NO_PROXY")) || (p = getenv("no_proxy")) || (p = getenv("NO_proxy")))) NO_proxy = p; #ifdef USE_NNTP if (!non_null(NNTP_server) && (p = getenv("NNTPSERVER")) != NULL) NNTP_server = p; if (!non_null(NNTP_mode) && (p = getenv("NNTPMODE")) != NULL) NNTP_mode = p; #endif if (!non_null(Editor) && (p = getenv("EDITOR")) != NULL) Editor = p; if (!non_null(Mailer) && (p = getenv("MAILER")) != NULL) Mailer = p; /* argument search 2 */ i = 1; while (i < argc) { if (*argv[i] == '-') { if (!strcmp("-t", argv[i])) { if (++i >= argc) usage(); if (atoi(argv[i]) > 0) Tabstop = atoi(argv[i]); } else if (!strcmp("-r", argv[i])) ShowEffect = FALSE; else if (!strcmp("-l", argv[i])) { if (++i >= argc) usage(); if (atoi(argv[i]) > 0) PagerMax = atoi(argv[i]); } #ifdef USE_M17N #if 0 /* use -O{s|j|e} instead */ else if (!strcmp("-s", argv[i])) DisplayCharset = WC_CES_SHIFT_JIS; else if (!strcmp("-j", argv[i])) DisplayCharset = WC_CES_ISO_2022_JP; else if (!strcmp("-e", argv[i])) DisplayCharset = WC_CES_EUC_JP; #endif else if (!strncmp("-I", argv[i], 2)) { if (argv[i][2] != '\0') p = argv[i] + 2; else { if (++i >= argc) usage(); p = argv[i]; } DocumentCharset = wc_guess_charset_short(p, DocumentCharset); WcOption.auto_detect = WC_OPT_DETECT_OFF; UseContentCharset = FALSE; } else if (!strncmp("-O", argv[i], 2)) { if (argv[i][2] != '\0') p = argv[i] + 2; else { if (++i >= argc) usage(); p = argv[i]; } DisplayCharset = wc_guess_charset_short(p, DisplayCharset); } #endif else if (!strcmp("-graph", argv[i])) UseGraphicChar = GRAPHIC_CHAR_DEC; else if (!strcmp("-no-graph", argv[i])) UseGraphicChar = GRAPHIC_CHAR_ASCII; else if (!strcmp("-T", argv[i])) { if (++i >= argc) usage(); DefaultType = default_type = argv[i]; } else if (!strcmp("-m", argv[i])) SearchHeader = search_header = TRUE; else if (!strcmp("-v", argv[i])) visual_start = TRUE; else if (!strcmp("-N", argv[i])) open_new_tab = TRUE; #ifdef USE_COLOR else if (!strcmp("-M", argv[i])) useColor = FALSE; #endif /* USE_COLOR */ else if (!strcmp("-B", argv[i])) load_bookmark = TRUE; else if (!strcmp("-bookmark", argv[i])) { if (++i >= argc) usage(); BookmarkFile = argv[i]; if (BookmarkFile[0] != '~' && BookmarkFile[0] != '/') { Str tmp = Strnew_charp(CurrentDir); if (Strlastchar(tmp) != '/') Strcat_char(tmp, '/'); Strcat_charp(tmp, BookmarkFile); BookmarkFile = cleanupName(tmp->ptr); } } else if (!strcmp("-F", argv[i])) RenderFrame = TRUE; else if (!strcmp("-W", argv[i])) { if (WrapDefault) WrapDefault = FALSE; else WrapDefault = TRUE; } else if (!strcmp("-dump", argv[i])) w3m_dump = DUMP_BUFFER; else if (!strcmp("-dump_source", argv[i])) w3m_dump = DUMP_SOURCE; else if (!strcmp("-dump_head", argv[i])) w3m_dump = DUMP_HEAD; else if (!strcmp("-dump_both", argv[i])) w3m_dump = (DUMP_HEAD | DUMP_SOURCE); else if (!strcmp("-dump_extra", argv[i])) w3m_dump = (DUMP_HEAD | DUMP_SOURCE | DUMP_EXTRA); else if (!strcmp("-halfdump", argv[i])) w3m_dump = DUMP_HALFDUMP; else if (!strcmp("-halfload", argv[i])) { w3m_dump = 0; w3m_halfload = TRUE; DefaultType = default_type = "text/html"; } else if (!strcmp("-backend", argv[i])) { w3m_backend = TRUE; } else if (!strcmp("-backend_batch", argv[i])) { w3m_backend = TRUE; if (++i >= argc) usage(); if (!backend_batch_commands) backend_batch_commands = newTextList(); pushText(backend_batch_commands, argv[i]); } else if (!strcmp("-cols", argv[i])) { if (++i >= argc) usage(); COLS = atoi(argv[i]); if (COLS > MAXIMUM_COLS) { COLS = MAXIMUM_COLS; } } else if (!strcmp("-ppc", argv[i])) { double ppc; if (++i >= argc) usage(); ppc = atof(argv[i]); if (ppc >= MINIMUM_PIXEL_PER_CHAR && ppc <= MAXIMUM_PIXEL_PER_CHAR) { pixel_per_char = ppc; set_pixel_per_char = TRUE; } } #ifdef USE_IMAGE else if (!strcmp("-ppl", argv[i])) { double ppc; if (++i >= argc) usage(); ppc = atof(argv[i]); if (ppc >= MINIMUM_PIXEL_PER_CHAR && ppc <= MAXIMUM_PIXEL_PER_CHAR * 2) { pixel_per_line = ppc; set_pixel_per_line = TRUE; } } #endif else if (!strcmp("-ri", argv[i])) { enable_inline_image = 1; } else if (!strcmp("-sixel", argv[i])) { enable_inline_image = 2; } else if (!strcmp("-num", argv[i])) showLineNum = TRUE; else if (!strcmp("-no-proxy", argv[i])) use_proxy = FALSE; #ifdef INET6 else if (!strcmp("-4", argv[i]) || !strcmp("-6", argv[i])) set_param_option(Sprintf("dns_order=%c", argv[i][1])->ptr); #endif else if (!strcmp("-post", argv[i])) { if (++i >= argc) usage(); post_file = argv[i]; } else if (!strcmp("-header", argv[i])) { Str hs; if (++i >= argc) usage(); if ((hs = make_optional_header_string(argv[i])) != NULL) { if (header_string == NULL) header_string = hs; else Strcat(header_string, hs); } while (argv[i][0]) { argv[i][0] = '\0'; argv[i]++; } } #ifdef USE_MOUSE else if (!strcmp("-no-mouse", argv[i])) { use_mouse = FALSE; } #endif /* USE_MOUSE */ #ifdef USE_COOKIE else if (!strcmp("-no-cookie", argv[i])) { use_cookie = FALSE; accept_cookie = FALSE; } else if (!strcmp("-cookie", argv[i])) { use_cookie = TRUE; accept_cookie = TRUE; } #endif /* USE_COOKIE */ #if 1 /* pager requires -s */ else if (!strcmp("-s", argv[i])) #else else if (!strcmp("-S", argv[i])) #endif squeezeBlankLine = TRUE; else if (!strcmp("-X", argv[i])) Do_not_use_ti_te = TRUE; else if (!strcmp("-title", argv[i])) displayTitleTerm = getenv("TERM"); else if (!strncmp("-title=", argv[i], 7)) displayTitleTerm = argv[i] + 7; else if (!strcmp("-o", argv[i]) || !strcmp("-show-option", argv[i])) { if (!strcmp("-show-option", argv[i]) || ++i >= argc || !strcmp(argv[i], "?")) { show_params(stdout); exit(0); } if (!set_param_option(argv[i])) { /* option set failed */ /* FIXME: gettextize? */ fprintf(stderr, "%s: bad option\n", argv[i]); show_params_p = 1; usage(); } } else if (!strcmp("-dummy", argv[i])) { /* do nothing */ } else if (!strcmp("-debug", argv[i])) { w3m_debug = TRUE; } else if (!strcmp("-reqlog",argv[i])) { w3m_reqlog=rcFile("request.log"); } #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) else if (!strcmp("-$$getimage", argv[i])) { ++i; getimage_args = argv + i; i += 4; if (i > argc) usage(); } #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ else { usage(); } } else if (*argv[i] == '+') { line_str = argv[i] + 1; } else { load_argv[load_argc++] = argv[i]; } i++; } #ifdef __WATT32__ if (w3m_debug) dbug_init(); sock_init(); #endif #ifdef __MINGW32_VERSION { int err; WORD wVerReq; wVerReq = MAKEWORD(1, 1); err = WSAStartup(wVerReq, &WSAData); if (err != 0) { fprintf(stderr, "Can't find winsock\n"); return 1; } _fmode = _O_BINARY; } #endif FirstTab = NULL; LastTab = NULL; nTab = 0; CurrentTab = NULL; CurrentKey = -1; if (BookmarkFile == NULL) BookmarkFile = rcFile(BOOKMARK); if (!isatty(1) && !w3m_dump) { /* redirected output */ w3m_dump = DUMP_BUFFER; } if (w3m_dump) { if (COLS == 0) COLS = DEFAULT_COLS; } #ifdef USE_BINMODE_STREAM setmode(fileno(stdout), O_BINARY); #endif if (!w3m_dump && !w3m_backend) { fmInit(); #ifdef SIGWINCH mySignal(SIGWINCH, resize_hook); #else /* not SIGWINCH */ setlinescols(); setupscreen(); #endif /* not SIGWINCH */ } #ifdef USE_IMAGE else if (w3m_halfdump && displayImage) activeImage = TRUE; #endif sync_with_option(); #ifdef USE_COOKIE initCookie(); #endif /* USE_COOKIE */ #ifdef USE_HISTORY if (UseHistory) loadHistory(URLHist); #endif /* not USE_HISTORY */ #ifdef USE_M17N wtf_init(DocumentCharset, DisplayCharset); /* if (w3m_dump) * WcOption.pre_conv = WC_TRUE; */ #endif if (w3m_backend) backend(); #if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) if (getimage_args) { char *image_url = conv_from_system(getimage_args[0]); char *base_url = conv_from_system(getimage_args[1]); ParsedURL base_pu; parseURL2(base_url, &base_pu, NULL); image_source = getimage_args[2]; newbuf = loadGeneralFile(image_url, &base_pu, NULL, 0, NULL); if (!newbuf || !newbuf->real_type || strncasecmp(newbuf->real_type, "image/", 6)) unlink(getimage_args[2]); #if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT) symlink(getimage_args[2], getimage_args[3]); #else { FILE *f = fopen(getimage_args[3], "w"); if (f) fclose(f); } #endif w3m_exit(0); } #endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ if (w3m_dump) mySignal(SIGINT, SIG_IGN); #ifdef SIGCHLD mySignal(SIGCHLD, sig_chld); #endif #ifdef SIGPIPE mySignal(SIGPIPE, SigPipe); #endif #if (GC_VERSION_MAJOR>7) || ((GC_VERSION_MAJOR==7) && (GC_VERSION_MINOR>=2)) orig_GC_warn_proc = GC_get_warn_proc(); GC_set_warn_proc(wrap_GC_warn_proc); #else orig_GC_warn_proc = GC_set_warn_proc(wrap_GC_warn_proc); #endif err_msg = Strnew(); if (load_argc == 0) { /* no URL specified */ if (!isatty(0)) { redin = newFileStream(fdopen(dup(0), "rb"), (void (*)())pclose); newbuf = openGeneralPagerBuffer(redin); dup2(1, 0); } else if (load_bookmark) { newbuf = loadGeneralFile(BookmarkFile, NULL, NO_REFERER, 0, NULL); if (newbuf == NULL) Strcat_charp(err_msg, "w3m: Can't load bookmark.\n"); } else if (visual_start) { /* FIXME: gettextize? */ Str s_page; s_page = Strnew_charp ("W3M startup page
Welcome to "); Strcat_charp(s_page, ""); Strcat_m_charp(s_page, "w3m!

This is w3m version ", w3m_version, "
Written by Akinori Ito", NULL); newbuf = loadHTMLString(s_page); if (newbuf == NULL) Strcat_charp(err_msg, "w3m: Can't load string.\n"); else if (newbuf != NO_BUFFER) newbuf->bufferprop |= (BP_INTERNAL | BP_NO_URL); } else if ((p = getenv("HTTP_HOME")) != NULL || (p = getenv("WWW_HOME")) != NULL) { newbuf = loadGeneralFile(p, NULL, NO_REFERER, 0, NULL); if (newbuf == NULL) Strcat(err_msg, Sprintf("w3m: Can't load %s.\n", p)); else if (newbuf != NO_BUFFER) pushHashHist(URLHist, parsedURL2Str(&newbuf->currentURL)->ptr); } else { if (fmInitialized) fmTerm(); usage(); } if (newbuf == NULL) { if (fmInitialized) fmTerm(); if (err_msg->length) fprintf(stderr, "%s", err_msg->ptr); w3m_exit(2); } i = -1; } else { i = 0; } for (; i < load_argc; i++) { if (i >= 0) { SearchHeader = search_header; DefaultType = default_type; char *url; url = load_argv[i]; if (getURLScheme(&url) == SCM_MISSING && !ArgvIsURL) url = file_to_url(load_argv[i]); else url = url_encode(conv_from_system(load_argv[i]), NULL, 0); if (w3m_dump == DUMP_HEAD) { request = New(FormList); request->method = FORM_METHOD_HEAD; newbuf = loadGeneralFile(url, NULL, NO_REFERER, 0, request); } else { if (post_file && i == 0) { FILE *fp; Str body; if (!strcmp(post_file, "-")) fp = stdin; else fp = fopen(post_file, "r"); if (fp == NULL) { /* FIXME: gettextize? */ Strcat(err_msg, Sprintf("w3m: Can't open %s.\n", post_file)); continue; } body = Strfgetall(fp); if (fp != stdin) fclose(fp); request = newFormList(NULL, "post", NULL, NULL, NULL, NULL, NULL); request->body = body->ptr; request->boundary = NULL; request->length = body->length; } else { request = NULL; } newbuf = loadGeneralFile(url, NULL, NO_REFERER, 0, request); } if (newbuf == NULL) { /* FIXME: gettextize? */ Strcat(err_msg, Sprintf("w3m: Can't load %s.\n", load_argv[i])); continue; } else if (newbuf == NO_BUFFER) continue; switch (newbuf->real_scheme) { case SCM_MAILTO: break; case SCM_LOCAL: case SCM_LOCAL_CGI: unshiftHist(LoadHist, url); default: pushHashHist(URLHist, parsedURL2Str(&newbuf->currentURL)->ptr); break; } } else if (newbuf == NO_BUFFER) continue; if (newbuf->pagerSource || (newbuf->real_scheme == SCM_LOCAL && newbuf->header_source && newbuf->currentURL.file && strcmp(newbuf->currentURL.file, "-"))) newbuf->search_header = search_header; if (CurrentTab == NULL) { FirstTab = LastTab = CurrentTab = newTab(); nTab = 1; Firstbuf = Currentbuf = newbuf; } else if (open_new_tab) { _newT(); Currentbuf->nextBuffer = newbuf; delBuffer(Currentbuf); } else { Currentbuf->nextBuffer = newbuf; Currentbuf = newbuf; } if (!w3m_dump || w3m_dump == DUMP_BUFFER) { if (Currentbuf->frameset != NULL && RenderFrame) rFrame(); } if (w3m_dump) do_dump(Currentbuf); else { Currentbuf = newbuf; #ifdef USE_BUFINFO saveBufferInfo(); #endif } } if (w3m_dump) { if (err_msg->length) fprintf(stderr, "%s", err_msg->ptr); #ifdef USE_COOKIE save_cookies(); #endif /* USE_COOKIE */ w3m_exit(0); } if (add_download_list) { add_download_list = FALSE; CurrentTab = LastTab; if (!FirstTab) { FirstTab = LastTab = CurrentTab = newTab(); nTab = 1; } if (!Firstbuf || Firstbuf == NO_BUFFER) { Firstbuf = Currentbuf = newBuffer(INIT_BUFFER_WIDTH); Currentbuf->bufferprop = BP_INTERNAL | BP_NO_URL; Currentbuf->buffername = DOWNLOAD_LIST_TITLE; } else Currentbuf = Firstbuf; ldDL(); } else CurrentTab = FirstTab; if (!FirstTab || !Firstbuf || Firstbuf == NO_BUFFER) { if (newbuf == NO_BUFFER) { if (fmInitialized) /* FIXME: gettextize? */ inputChar("Hit any key to quit w3m:"); } if (fmInitialized) fmTerm(); if (err_msg->length) fprintf(stderr, "%s", err_msg->ptr); if (newbuf == NO_BUFFER) { #ifdef USE_COOKIE save_cookies(); #endif /* USE_COOKIE */ if (!err_msg->length) w3m_exit(0); } w3m_exit(2); } if (err_msg->length) disp_message_nsec(err_msg->ptr, FALSE, 1, TRUE, FALSE); SearchHeader = FALSE; DefaultType = NULL; #ifdef USE_M17N UseContentCharset = TRUE; WcOption.auto_detect = auto_detect; #endif Currentbuf = Firstbuf; displayBuffer(Currentbuf, B_FORCE_REDRAW); if (line_str) { _goLine(line_str); } for (;;) { if (add_download_list) { add_download_list = FALSE; ldDL(); } if (Currentbuf->submit) { Anchor *a = Currentbuf->submit; Currentbuf->submit = NULL; gotoLine(Currentbuf, a->start.line); Currentbuf->pos = a->start.pos; _followForm(TRUE); continue; } /* event processing */ if (CurrentEvent) { CurrentKey = -1; CurrentKeyData = NULL; CurrentCmdData = (char *)CurrentEvent->data; w3mFuncList[CurrentEvent->cmd].func(); CurrentCmdData = NULL; CurrentEvent = CurrentEvent->next; continue; } /* get keypress event */ #ifdef USE_ALARM if (Currentbuf->event) { if (Currentbuf->event->status != AL_UNSET) { CurrentAlarm = Currentbuf->event; if (CurrentAlarm->sec == 0) { /* refresh (0sec) */ Currentbuf->event = NULL; CurrentKey = -1; CurrentKeyData = NULL; CurrentCmdData = (char *)CurrentAlarm->data; w3mFuncList[CurrentAlarm->cmd].func(); CurrentCmdData = NULL; continue; } } else Currentbuf->event = NULL; } if (!Currentbuf->event) CurrentAlarm = &DefaultAlarm; #endif #ifdef USE_MOUSE mouse_action.in_action = FALSE; if (use_mouse) mouse_active(); #endif /* USE_MOUSE */ #ifdef USE_ALARM if (CurrentAlarm->sec > 0) { mySignal(SIGALRM, SigAlarm); alarm(CurrentAlarm->sec); } #endif #ifdef SIGWINCH mySignal(SIGWINCH, resize_hook); #endif #ifdef USE_IMAGE if (activeImage && displayImage && Currentbuf->img && !Currentbuf->image_loaded) { do { #ifdef SIGWINCH if (need_resize_screen) resize_screen(); #endif loadImage(Currentbuf, IMG_FLAG_NEXT); } while (sleep_till_anykey(1, 0) <= 0); } #ifdef SIGWINCH else #endif #endif #ifdef SIGWINCH { do { if (need_resize_screen) resize_screen(); } while (sleep_till_anykey(1, 0) <= 0); } #endif c = getch(); #ifdef USE_ALARM if (CurrentAlarm->sec > 0) { alarm(0); } #endif #ifdef USE_MOUSE if (use_mouse) mouse_inactive(); #endif /* USE_MOUSE */ if (IS_ASCII(c)) { /* Ascii */ if (('0' <= c) && (c <= '9') && (prec_num || (GlobalKeymap[c] == FUNCNAME_nulcmd))) { prec_num = prec_num * 10 + (int)(c - '0'); if (prec_num > PREC_LIMIT) prec_num = PREC_LIMIT; } else { set_buffer_environ(Currentbuf); save_buffer_position(Currentbuf); keyPressEventProc((int)c); prec_num = 0; } } prev_key = CurrentKey; CurrentKey = -1; CurrentKeyData = NULL; } } static void keyPressEventProc(int c) { CurrentKey = c; w3mFuncList[(int)GlobalKeymap[c]].func(); } void pushEvent(int cmd, void *data) { Event *event; event = New(Event); event->cmd = cmd; event->data = data; event->next = NULL; if (CurrentEvent) LastEvent->next = event; else CurrentEvent = event; LastEvent = event; } static void dump_source(Buffer *buf) { FILE *f; int c; if (buf->sourcefile == NULL) return; f = fopen(buf->sourcefile, "r"); if (f == NULL) return; while ((c = fgetc(f)) != EOF) { putchar(c); } fclose(f); } static void dump_head(Buffer *buf) { TextListItem *ti; if (buf->document_header == NULL) { if (w3m_dump & DUMP_EXTRA) printf("\n"); return; } for (ti = buf->document_header->first; ti; ti = ti->next) { #ifdef USE_M17N printf("%s", wc_conv_strict(ti->ptr, InnerCharset, buf->document_charset)->ptr); #else printf("%s", ti->ptr); #endif } puts(""); } static void dump_extra(Buffer *buf) { printf("W3m-current-url: %s\n", parsedURL2Str(&buf->currentURL)->ptr); if (buf->baseURL) printf("W3m-base-url: %s\n", parsedURL2Str(buf->baseURL)->ptr); #ifdef USE_M17N printf("W3m-document-charset: %s\n", wc_ces_to_charset(buf->document_charset)); #endif #ifdef USE_SSL if (buf->ssl_certificate) { Str tmp = Strnew(); char *p; for (p = buf->ssl_certificate; *p; p++) { Strcat_char(tmp, *p); if (*p == '\n') { for (; *(p + 1) == '\n'; p++) ; if (*(p + 1)) Strcat_char(tmp, '\t'); } } if (Strlastchar(tmp) != '\n') Strcat_char(tmp, '\n'); printf("W3m-ssl-certificate: %s", tmp->ptr); } #endif } static int cmp_anchor_hseq(const void *a, const void *b) { return (*((const Anchor **) a))->hseq - (*((const Anchor **) b))->hseq; } static void do_dump(Buffer *buf) { MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; prevtrap = mySignal(SIGINT, intTrap); if (SETJMP(IntReturn) != 0) { mySignal(SIGINT, prevtrap); return; } if (w3m_dump & DUMP_EXTRA) dump_extra(buf); if (w3m_dump & DUMP_HEAD) dump_head(buf); if (w3m_dump & DUMP_SOURCE) dump_source(buf); if (w3m_dump == DUMP_BUFFER) { int i; saveBuffer(buf, stdout, FALSE); if (displayLinkNumber && buf->href) { int nanchor = buf->href->nanchor; printf("\nReferences:\n\n"); Anchor **in_order = New_N(Anchor *, buf->href->nanchor); for (i = 0; i < nanchor; i++) in_order[i] = buf->href->anchors + i; qsort(in_order, nanchor, sizeof(Anchor *), cmp_anchor_hseq); for (i = 0; i < nanchor; i++) { ParsedURL pu; char *url; if (in_order[i]->slave) continue; parseURL2(in_order[i]->url, &pu, baseURL(buf)); url = url_decode2(parsedURL2Str(&pu)->ptr, Currentbuf); printf("[%d] %s\n", in_order[i]->hseq + 1, url); } } } mySignal(SIGINT, prevtrap); } DEFUN(nulcmd, NOTHING NULL @@@, "Do nothing") { /* do nothing */ } #ifdef __EMX__ DEFUN(pcmap, PCMAP, "pcmap") { w3mFuncList[(int)PcKeymap[(int)getch()]].func(); } #else /* not __EMX__ */ void pcmap(void) { } #endif static void escKeyProc(int c, int esc, unsigned char *map) { if (CurrentKey >= 0 && CurrentKey & K_MULTI) { unsigned char **mmap; mmap = (unsigned char **)getKeyData(MULTI_KEY(CurrentKey)); if (!mmap) return; switch (esc) { case K_ESCD: map = mmap[3]; break; case K_ESCB: map = mmap[2]; break; case K_ESC: map = mmap[1]; break; default: map = mmap[0]; break; } esc |= (CurrentKey & ~0xFFFF); } CurrentKey = esc | c; w3mFuncList[(int)map[c]].func(); } DEFUN(escmap, ESCMAP, "ESC map") { char c; c = getch(); if (IS_ASCII(c)) escKeyProc((int)c, K_ESC, EscKeymap); } DEFUN(escbmap, ESCBMAP, "ESC [ map") { char c; c = getch(); if (IS_DIGIT(c)) { escdmap(c); return; } if (IS_ASCII(c)) escKeyProc((int)c, K_ESCB, EscBKeymap); } void escdmap(char c) { int d; d = (int)c - (int)'0'; c = getch(); if (IS_DIGIT(c)) { d = d * 10 + (int)c - (int)'0'; c = getch(); } if (c == '~') escKeyProc((int)d, K_ESCD, EscDKeymap); } DEFUN(multimap, MULTIMAP, "multimap") { char c; c = getch(); if (IS_ASCII(c)) { CurrentKey = K_MULTI | (CurrentKey << 16) | c; escKeyProc((int)c, 0, NULL); } } void tmpClearBuffer(Buffer *buf) { if (buf->pagerSource == NULL && writeBufferCache(buf) == 0) { buf->firstLine = NULL; buf->topLine = NULL; buf->currentLine = NULL; buf->lastLine = NULL; } } static Str currentURL(void); #ifdef USE_BUFINFO void saveBufferInfo() { FILE *fp; if (w3m_dump) return; if ((fp = fopen(rcFile("bufinfo"), "w")) == NULL) { return; } fprintf(fp, "%s\n", currentURL()->ptr); fclose(fp); } #endif static void pushBuffer(Buffer *buf) { Buffer *b; #ifdef USE_IMAGE deleteImage(Currentbuf); #endif if (clear_buffer) tmpClearBuffer(Currentbuf); if (Firstbuf == Currentbuf) { buf->nextBuffer = Firstbuf; Firstbuf = Currentbuf = buf; } else if ((b = prevBuffer(Firstbuf, Currentbuf)) != NULL) { b->nextBuffer = buf; buf->nextBuffer = Currentbuf; Currentbuf = buf; } #ifdef USE_BUFINFO saveBufferInfo(); #endif } static void delBuffer(Buffer *buf) { if (buf == NULL) return; if (Currentbuf == buf) Currentbuf = buf->nextBuffer; Firstbuf = deleteBuffer(Firstbuf, buf); if (!Currentbuf) Currentbuf = Firstbuf; } static void repBuffer(Buffer *oldbuf, Buffer *buf) { Firstbuf = replaceBuffer(Firstbuf, oldbuf, buf); Currentbuf = buf; } MySignalHandler intTrap(SIGNAL_ARG) { /* Interrupt catcher */ LONGJMP(IntReturn, 0); SIGNAL_RETURN; } #ifdef SIGWINCH static MySignalHandler resize_hook(SIGNAL_ARG) { need_resize_screen = TRUE; mySignal(SIGWINCH, resize_hook); SIGNAL_RETURN; } static void resize_screen(void) { need_resize_screen = FALSE; setlinescols(); setupscreen(); if (CurrentTab) displayBuffer(Currentbuf, B_FORCE_REDRAW); } #endif /* SIGWINCH */ #ifdef SIGPIPE static MySignalHandler SigPipe(SIGNAL_ARG) { #ifdef USE_MIGEMO init_migemo(); #endif mySignal(SIGPIPE, SigPipe); SIGNAL_RETURN; } #endif /* * Command functions: These functions are called with a keystroke. */ static void nscroll(int n, int mode) { Buffer *buf = Currentbuf; Line *top = buf->topLine, *cur = buf->currentLine; int lnum, tlnum, llnum, diff_n; if (buf->firstLine == NULL) return; lnum = cur->linenumber; buf->topLine = lineSkip(buf, top, n, FALSE); if (buf->topLine == top) { lnum += n; if (lnum < buf->topLine->linenumber) lnum = buf->topLine->linenumber; else if (lnum > buf->lastLine->linenumber) lnum = buf->lastLine->linenumber; } else { tlnum = buf->topLine->linenumber; llnum = buf->topLine->linenumber + buf->LINES - 1; if (nextpage_topline) diff_n = 0; else diff_n = n - (tlnum - top->linenumber); if (lnum < tlnum) lnum = tlnum + diff_n; if (lnum > llnum) lnum = llnum + diff_n; } gotoLine(buf, lnum); arrangeLine(buf); if (n > 0) { if (buf->currentLine->bpos && buf->currentLine->bwidth >= buf->currentColumn + buf->visualpos) cursorDown(buf, 1); else { while (buf->currentLine->next && buf->currentLine->next->bpos && buf->currentLine->bwidth + buf->currentLine->width < buf->currentColumn + buf->visualpos) cursorDown0(buf, 1); } } else { if (buf->currentLine->bwidth + buf->currentLine->width < buf->currentColumn + buf->visualpos) cursorUp(buf, 1); else { while (buf->currentLine->prev && buf->currentLine->bpos && buf->currentLine->bwidth >= buf->currentColumn + buf->visualpos) cursorUp0(buf, 1); } } displayBuffer(buf, mode); } /* Move page forward */ DEFUN(pgFore, NEXT_PAGE, "Scroll down one page") { if (vi_prec_num) nscroll(searchKeyNum() * (Currentbuf->LINES - 1), B_NORMAL); else nscroll(prec_num ? searchKeyNum() : searchKeyNum() * (Currentbuf->LINES - 1), prec_num ? B_SCROLL : B_NORMAL); } /* Move page backward */ DEFUN(pgBack, PREV_PAGE, "Scroll up one page") { if (vi_prec_num) nscroll(-searchKeyNum() * (Currentbuf->LINES - 1), B_NORMAL); else nscroll(-(prec_num ? searchKeyNum() : searchKeyNum() * (Currentbuf->LINES - 1)), prec_num ? B_SCROLL : B_NORMAL); } /* Move half page forward */ DEFUN(hpgFore, NEXT_HALF_PAGE, "Scroll down half a page") { nscroll(searchKeyNum() * (Currentbuf->LINES / 2 - 1), B_NORMAL); } /* Move half page backward */ DEFUN(hpgBack, PREV_HALF_PAGE, "Scroll up half a page") { nscroll(-searchKeyNum() * (Currentbuf->LINES / 2 - 1), B_NORMAL); } /* 1 line up */ DEFUN(lup1, UP, "Scroll the screen up one line") { nscroll(searchKeyNum(), B_SCROLL); } /* 1 line down */ DEFUN(ldown1, DOWN, "Scroll the screen down one line") { nscroll(-searchKeyNum(), B_SCROLL); } /* move cursor position to the center of screen */ DEFUN(ctrCsrV, CENTER_V, "Center on cursor line") { int offsety; if (Currentbuf->firstLine == NULL) return; offsety = Currentbuf->LINES / 2 - Currentbuf->cursorY; if (offsety != 0) { #if 0 Currentbuf->currentLine = lineSkip(Currentbuf, Currentbuf->currentLine, offsety, FALSE); #endif Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine, -offsety, FALSE); arrangeLine(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } } DEFUN(ctrCsrH, CENTER_H, "Center on cursor column") { int offsetx; if (Currentbuf->firstLine == NULL) return; offsetx = Currentbuf->cursorX - Currentbuf->COLS / 2; if (offsetx != 0) { columnSkip(Currentbuf, offsetx); arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } } /* Redraw screen */ DEFUN(rdrwSc, REDRAW, "Draw the screen anew") { clear(); arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); } static void clear_mark(Line *l) { int pos; if (!l) return; for (pos = 0; pos < l->size; pos++) l->propBuf[pos] &= ~PE_MARK; } /* search by regular expression */ static int srchcore(char *volatile str, int (*func) (Buffer *, char *)) { MySignalHandler(*prevtrap) (); volatile int i, result = SR_NOTFOUND; if (str != NULL && str != SearchString) SearchString = str; if (SearchString == NULL || *SearchString == '\0') return SR_NOTFOUND; str = conv_search_string(SearchString, DisplayCharset); prevtrap = mySignal(SIGINT, intTrap); crmode(); if (SETJMP(IntReturn) == 0) { for (i = 0; i < PREC_NUM; i++) { result = func(Currentbuf, str); if (i < PREC_NUM - 1 && result & SR_FOUND) clear_mark(Currentbuf->currentLine); } } mySignal(SIGINT, prevtrap); term_raw(); return result; } static void disp_srchresult(int result, char *prompt, char *str) { if (str == NULL) str = ""; if (result & SR_NOTFOUND) disp_message(Sprintf("Not found: %s", str)->ptr, TRUE); else if (result & SR_WRAPPED) disp_message(Sprintf("Search wrapped: %s", str)->ptr, TRUE); else if (show_srch_str) disp_message(Sprintf("%s%s", prompt, str)->ptr, TRUE); } static int dispincsrch(int ch, Str buf, Lineprop *prop) { static Buffer sbuf; static Line *currentLine; static int pos; char *str; int do_next_search = FALSE; if (ch == 0 && buf == NULL) { SAVE_BUFPOSITION(&sbuf); /* search starting point */ currentLine = sbuf.currentLine; pos = sbuf.pos; return -1; } str = buf->ptr; switch (ch) { case 022: /* C-r */ searchRoutine = backwardSearch; do_next_search = TRUE; break; case 023: /* C-s */ searchRoutine = forwardSearch; do_next_search = TRUE; break; #ifdef USE_MIGEMO case 034: migemo_active = -migemo_active; goto done; #endif default: if (ch >= 0) return ch; /* use InputKeymap */ } if (do_next_search) { if (*str) { if (searchRoutine == forwardSearch) Currentbuf->pos += 1; SAVE_BUFPOSITION(&sbuf); if (srchcore(str, searchRoutine) == SR_NOTFOUND && searchRoutine == forwardSearch) { Currentbuf->pos -= 1; SAVE_BUFPOSITION(&sbuf); } arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); clear_mark(Currentbuf->currentLine); return -1; } else return 020; /* _prev completion for C-s C-s */ } else if (*str) { RESTORE_BUFPOSITION(&sbuf); arrangeCursor(Currentbuf); srchcore(str, searchRoutine); arrangeCursor(Currentbuf); currentLine = Currentbuf->currentLine; pos = Currentbuf->pos; } displayBuffer(Currentbuf, B_FORCE_REDRAW); clear_mark(Currentbuf->currentLine); #ifdef USE_MIGEMO done: while (*str++ != '\0') { if (migemo_active > 0) *prop++ |= PE_UNDER; else *prop++ &= ~PE_UNDER; } #endif return -1; } void isrch(int (*func) (Buffer *, char *), char *prompt) { char *str; Buffer sbuf; SAVE_BUFPOSITION(&sbuf); dispincsrch(0, NULL, NULL); /* initialize incremental search state */ searchRoutine = func; str = inputLineHistSearch(prompt, NULL, IN_STRING, TextHist, dispincsrch); if (str == NULL) { RESTORE_BUFPOSITION(&sbuf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } void srch(int (*func) (Buffer *, char *), char *prompt) { char *str; int result; int disp = FALSE; int pos; str = searchKeyData(); if (str == NULL || *str == '\0') { str = inputStrHist(prompt, NULL, TextHist); if (str != NULL && *str == '\0') str = SearchString; if (str == NULL) { displayBuffer(Currentbuf, B_NORMAL); return; } disp = TRUE; } pos = Currentbuf->pos; if (func == forwardSearch) Currentbuf->pos += 1; result = srchcore(str, func); if (result & SR_FOUND) clear_mark(Currentbuf->currentLine); else Currentbuf->pos = pos; displayBuffer(Currentbuf, B_NORMAL); if (disp) disp_srchresult(result, prompt, str); searchRoutine = func; } /* Search regular expression forward */ DEFUN(srchfor, SEARCH SEARCH_FORE WHEREIS, "Search forward") { srch(forwardSearch, "Forward: "); } DEFUN(isrchfor, ISEARCH, "Incremental search forward") { isrch(forwardSearch, "I-search: "); } /* Search regular expression backward */ DEFUN(srchbak, SEARCH_BACK, "Search backward") { srch(backwardSearch, "Backward: "); } DEFUN(isrchbak, ISEARCH_BACK, "Incremental search backward") { isrch(backwardSearch, "I-search backward: "); } static void srch_nxtprv(int reverse) { int result; /* *INDENT-OFF* */ static int (*routine[2]) (Buffer *, char *) = { forwardSearch, backwardSearch }; /* *INDENT-ON* */ if (searchRoutine == NULL) { /* FIXME: gettextize? */ disp_message("No previous regular expression", TRUE); return; } if (reverse != 0) reverse = 1; if (searchRoutine == backwardSearch) reverse ^= 1; if (reverse == 0) Currentbuf->pos += 1; result = srchcore(SearchString, routine[reverse]); if (result & SR_FOUND) clear_mark(Currentbuf->currentLine); else { if (reverse == 0) Currentbuf->pos -= 1; } displayBuffer(Currentbuf, B_NORMAL); disp_srchresult(result, (reverse ? "Backward: " : "Forward: "), SearchString); } /* Search next matching */ DEFUN(srchnxt, SEARCH_NEXT, "Continue search forward") { srch_nxtprv(0); } /* Search previous matching */ DEFUN(srchprv, SEARCH_PREV, "Continue search backward") { srch_nxtprv(1); } static void shiftvisualpos(Buffer *buf, int shift) { Line *l = buf->currentLine; buf->visualpos -= shift; if (buf->visualpos - l->bwidth >= buf->COLS) buf->visualpos = l->bwidth + buf->COLS - 1; else if (buf->visualpos - l->bwidth < 0) buf->visualpos = l->bwidth; arrangeLine(buf); if (buf->visualpos - l->bwidth == -shift && buf->cursorX == 0) buf->visualpos = l->bwidth; } /* Shift screen left */ DEFUN(shiftl, SHIFT_LEFT, "Shift screen left") { int column; if (Currentbuf->firstLine == NULL) return; column = Currentbuf->currentColumn; columnSkip(Currentbuf, searchKeyNum() * (-Currentbuf->COLS + 1) + 1); shiftvisualpos(Currentbuf, Currentbuf->currentColumn - column); displayBuffer(Currentbuf, B_NORMAL); } /* Shift screen right */ DEFUN(shiftr, SHIFT_RIGHT, "Shift screen right") { int column; if (Currentbuf->firstLine == NULL) return; column = Currentbuf->currentColumn; columnSkip(Currentbuf, searchKeyNum() * (Currentbuf->COLS - 1) - 1); shiftvisualpos(Currentbuf, Currentbuf->currentColumn - column); displayBuffer(Currentbuf, B_NORMAL); } DEFUN(col1R, RIGHT, "Shift screen one column right") { Buffer *buf = Currentbuf; Line *l = buf->currentLine; int j, column, n = searchKeyNum(); if (l == NULL) return; for (j = 0; j < n; j++) { column = buf->currentColumn; columnSkip(Currentbuf, 1); if (column == buf->currentColumn) break; shiftvisualpos(Currentbuf, 1); } displayBuffer(Currentbuf, B_NORMAL); } DEFUN(col1L, LEFT, "Shift screen one column left") { Buffer *buf = Currentbuf; Line *l = buf->currentLine; int j, n = searchKeyNum(); if (l == NULL) return; for (j = 0; j < n; j++) { if (buf->currentColumn == 0) break; columnSkip(Currentbuf, -1); shiftvisualpos(Currentbuf, -1); } displayBuffer(Currentbuf, B_NORMAL); } DEFUN(setEnv, SETENV, "Set environment variable") { char *env; char *var, *value; CurrentKeyData = NULL; /* not allowed in w3m-control: */ env = searchKeyData(); if (env == NULL || *env == '\0' || strchr(env, '=') == NULL) { if (env != NULL && *env != '\0') env = Sprintf("%s=", env)->ptr; env = inputStrHist("Set environ: ", env, TextHist); if (env == NULL || *env == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } } if ((value = strchr(env, '=')) != NULL && value > env) { var = allocStr(env, value - env); value++; set_environ(var, value); } displayBuffer(Currentbuf, B_NORMAL); } DEFUN(pipeBuf, PIPE_BUF, "Pipe current buffer through a shell command and display output") { Buffer *buf; char *cmd, *tmpf; FILE *f; CurrentKeyData = NULL; /* not allowed in w3m-control: */ cmd = searchKeyData(); if (cmd == NULL || *cmd == '\0') { /* FIXME: gettextize? */ cmd = inputLineHist("Pipe buffer to: ", "", IN_COMMAND, ShellHist); } if (cmd != NULL) cmd = conv_to_system(cmd); if (cmd == NULL || *cmd == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } tmpf = tmpfname(TMPF_DFL, NULL)->ptr; f = fopen(tmpf, "w"); if (f == NULL) { /* FIXME: gettextize? */ disp_message(Sprintf("Can't save buffer to %s", cmd)->ptr, TRUE); return; } saveBuffer(Currentbuf, f, TRUE); fclose(f); buf = getpipe(myExtCommand(cmd, shell_quote(tmpf), TRUE)->ptr); if (buf == NULL) { disp_message("Execution failed", TRUE); return; } else { buf->filename = cmd; buf->buffername = Sprintf("%s %s", PIPEBUFFERNAME, conv_from_system(cmd))->ptr; buf->bufferprop |= (BP_INTERNAL | BP_NO_URL); if (buf->type == NULL) buf->type = "text/plain"; buf->currentURL.file = "-"; pushBuffer(buf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* Execute shell command and read output ac pipe. */ DEFUN(pipesh, PIPE_SHELL, "Execute shell command and display output") { Buffer *buf; char *cmd; CurrentKeyData = NULL; /* not allowed in w3m-control: */ cmd = searchKeyData(); if (cmd == NULL || *cmd == '\0') { cmd = inputLineHist("(read shell[pipe])!", "", IN_COMMAND, ShellHist); } if (cmd != NULL) cmd = conv_to_system(cmd); if (cmd == NULL || *cmd == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } buf = getpipe(cmd); if (buf == NULL) { disp_message("Execution failed", TRUE); return; } else { buf->bufferprop |= (BP_INTERNAL | BP_NO_URL); if (buf->type == NULL) buf->type = "text/plain"; pushBuffer(buf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* Execute shell command and load entire output to buffer */ DEFUN(readsh, READ_SHELL, "Execute shell command and display output") { Buffer *buf; MySignalHandler(*prevtrap) (); char *cmd; CurrentKeyData = NULL; /* not allowed in w3m-control: */ cmd = searchKeyData(); if (cmd == NULL || *cmd == '\0') { cmd = inputLineHist("(read shell)!", "", IN_COMMAND, ShellHist); } if (cmd != NULL) cmd = conv_to_system(cmd); if (cmd == NULL || *cmd == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } prevtrap = mySignal(SIGINT, intTrap); crmode(); buf = getshell(cmd); mySignal(SIGINT, prevtrap); term_raw(); if (buf == NULL) { /* FIXME: gettextize? */ disp_message("Execution failed", TRUE); return; } else { buf->bufferprop |= (BP_INTERNAL | BP_NO_URL); if (buf->type == NULL) buf->type = "text/plain"; pushBuffer(buf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* Execute shell command */ DEFUN(execsh, EXEC_SHELL SHELL, "Execute shell command and display output") { char *cmd; CurrentKeyData = NULL; /* not allowed in w3m-control: */ cmd = searchKeyData(); if (cmd == NULL || *cmd == '\0') { cmd = inputLineHist("(exec shell)!", "", IN_COMMAND, ShellHist); } if (cmd != NULL) cmd = conv_to_system(cmd); if (cmd != NULL && *cmd != '\0') { fmTerm(); printf("\n"); system(cmd); /* FIXME: gettextize? */ printf("\n[Hit any key]"); fflush(stdout); fmInit(); getch(); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* Load file */ DEFUN(ldfile, LOAD, "Open local file in a new buffer") { char *fn; fn = searchKeyData(); if (fn == NULL || *fn == '\0') { /* FIXME: gettextize? */ fn = inputFilenameHist("(Load)Filename? ", NULL, LoadHist); } if (fn != NULL) fn = conv_to_system(fn); if (fn == NULL || *fn == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } cmd_loadfile(fn); } /* Load help file */ DEFUN(ldhelp, HELP, "Show help panel") { #ifdef USE_HELP_CGI char *lang; int n; Str tmp; lang = AcceptLang; n = strcspn(lang, ";, \t"); tmp = Sprintf("file:///$LIB/" HELP_CGI CGI_EXTENSION "?version=%s&lang=%s", Str_form_quote(Strnew_charp(w3m_version))->ptr, Str_form_quote(Strnew_charp_n(lang, n))->ptr); cmd_loadURL(tmp->ptr, NULL, NO_REFERER, NULL); #else cmd_loadURL(helpFile(HELP_FILE), NULL, NO_REFERER, NULL); #endif } static void cmd_loadfile(char *fn) { Buffer *buf; buf = loadGeneralFile(file_to_url(fn), NULL, NO_REFERER, 0, NULL); if (buf == NULL) { /* FIXME: gettextize? */ char *emsg = Sprintf("%s not found", conv_from_system(fn))->ptr; disp_err_message(emsg, FALSE); } else if (buf != NO_BUFFER) { pushBuffer(buf); if (RenderFrame && Currentbuf->frameset != NULL) rFrame(); } displayBuffer(Currentbuf, B_NORMAL); } /* Move cursor left */ static void _movL(int n) { int i, m = searchKeyNum(); if (Currentbuf->firstLine == NULL) return; for (i = 0; i < m; i++) cursorLeft(Currentbuf, n); displayBuffer(Currentbuf, B_NORMAL); } DEFUN(movL, MOVE_LEFT, "Cursor left") { _movL(Currentbuf->COLS / 2); } DEFUN(movL1, MOVE_LEFT1, "Cursor left. With edge touched, slide") { _movL(1); } /* Move cursor downward */ static void _movD(int n) { int i, m = searchKeyNum(); if (Currentbuf->firstLine == NULL) return; for (i = 0; i < m; i++) cursorDown(Currentbuf, n); displayBuffer(Currentbuf, B_NORMAL); } DEFUN(movD, MOVE_DOWN, "Cursor down") { _movD((Currentbuf->LINES + 1) / 2); } DEFUN(movD1, MOVE_DOWN1, "Cursor down. With edge touched, slide") { _movD(1); } /* move cursor upward */ static void _movU(int n) { int i, m = searchKeyNum(); if (Currentbuf->firstLine == NULL) return; for (i = 0; i < m; i++) cursorUp(Currentbuf, n); displayBuffer(Currentbuf, B_NORMAL); } DEFUN(movU, MOVE_UP, "Cursor up") { _movU((Currentbuf->LINES + 1) / 2); } DEFUN(movU1, MOVE_UP1, "Cursor up. With edge touched, slide") { _movU(1); } /* Move cursor right */ static void _movR(int n) { int i, m = searchKeyNum(); if (Currentbuf->firstLine == NULL) return; for (i = 0; i < m; i++) cursorRight(Currentbuf, n); displayBuffer(Currentbuf, B_NORMAL); } DEFUN(movR, MOVE_RIGHT, "Cursor right") { _movR(Currentbuf->COLS / 2); } DEFUN(movR1, MOVE_RIGHT1, "Cursor right. With edge touched, slide") { _movR(1); } /* movLW, movRW */ /* * From: Takashi Nishimoto Date: Mon, 14 Jun * 1999 09:29:56 +0900 */ #if defined(USE_M17N) && defined(USE_UNICODE) #define nextChar(s, l) do { (s)++; } while ((s) < (l)->len && (l)->propBuf[s] & PC_WCHAR2) #define prevChar(s, l) do { (s)--; } while ((s) > 0 && (l)->propBuf[s] & PC_WCHAR2) static wc_uint32 getChar(char *p) { return wc_any_to_ucs(wtf_parse1((wc_uchar **)&p)); } static int is_wordchar(wc_uint32 c) { return wc_is_ucs_alnum(c); } #else #define nextChar(s, l) (s)++ #define prevChar(s, l) (s)-- #define getChar(p) ((int)*(p)) static int is_wordchar(int c) { return IS_ALNUM(c); } #endif static int prev_nonnull_line(Line *line) { Line *l; for (l = line; l != NULL && l->len == 0; l = l->prev) ; if (l == NULL || l->len == 0) return -1; Currentbuf->currentLine = l; if (l != line) Currentbuf->pos = Currentbuf->currentLine->len; return 0; } DEFUN(movLW, PREV_WORD, "Move to the previous word") { char *lb; Line *pline, *l; int ppos; int i, n = searchKeyNum(); if (Currentbuf->firstLine == NULL) return; for (i = 0; i < n; i++) { pline = Currentbuf->currentLine; ppos = Currentbuf->pos; if (prev_nonnull_line(Currentbuf->currentLine) < 0) goto end; while (1) { l = Currentbuf->currentLine; lb = l->lineBuf; while (Currentbuf->pos > 0) { int tmp = Currentbuf->pos; prevChar(tmp, l); if (is_wordchar(getChar(&lb[tmp]))) break; Currentbuf->pos = tmp; } if (Currentbuf->pos > 0) break; if (prev_nonnull_line(Currentbuf->currentLine->prev) < 0) { Currentbuf->currentLine = pline; Currentbuf->pos = ppos; goto end; } Currentbuf->pos = Currentbuf->currentLine->len; } l = Currentbuf->currentLine; lb = l->lineBuf; while (Currentbuf->pos > 0) { int tmp = Currentbuf->pos; prevChar(tmp, l); if (!is_wordchar(getChar(&lb[tmp]))) break; Currentbuf->pos = tmp; } } end: arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } static int next_nonnull_line(Line *line) { Line *l; for (l = line; l != NULL && l->len == 0; l = l->next) ; if (l == NULL || l->len == 0) return -1; Currentbuf->currentLine = l; if (l != line) Currentbuf->pos = 0; return 0; } DEFUN(movRW, NEXT_WORD, "Move to the next word") { char *lb; Line *pline, *l; int ppos; int i, n = searchKeyNum(); if (Currentbuf->firstLine == NULL) return; for (i = 0; i < n; i++) { pline = Currentbuf->currentLine; ppos = Currentbuf->pos; if (next_nonnull_line(Currentbuf->currentLine) < 0) goto end; l = Currentbuf->currentLine; lb = l->lineBuf; while (Currentbuf->pos < l->len && is_wordchar(getChar(&lb[Currentbuf->pos]))) nextChar(Currentbuf->pos, l); while (1) { while (Currentbuf->pos < l->len && !is_wordchar(getChar(&lb[Currentbuf->pos]))) nextChar(Currentbuf->pos, l); if (Currentbuf->pos < l->len) break; if (next_nonnull_line(Currentbuf->currentLine->next) < 0) { Currentbuf->currentLine = pline; Currentbuf->pos = ppos; goto end; } Currentbuf->pos = 0; l = Currentbuf->currentLine; lb = l->lineBuf; } } end: arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } static void _quitfm(int confirm) { char *ans = "y"; if (checkDownloadList()) /* FIXME: gettextize? */ ans = inputChar("Download process retains. " "Do you want to exit w3m? (y/n)"); else if (confirm) /* FIXME: gettextize? */ ans = inputChar("Do you want to exit w3m? (y/n)"); if (!(ans && TOLOWER(*ans) == 'y')) { displayBuffer(Currentbuf, B_NORMAL); return; } term_title(""); /* XXX */ #ifdef USE_IMAGE if (activeImage) termImage(); #endif fmTerm(); #ifdef USE_COOKIE save_cookies(); #endif /* USE_COOKIE */ #ifdef USE_HISTORY if (UseHistory && SaveURLHist) saveHistory(URLHist, URLHistSize); #endif /* USE_HISTORY */ w3m_exit(0); } /* Quit */ DEFUN(quitfm, ABORT EXIT, "Quit at once") { _quitfm(FALSE); } /* Question and Quit */ DEFUN(qquitfm, QUIT, "Quit with confirmation request") { _quitfm(confirm_on_quit); } /* Select buffer */ DEFUN(selBuf, SELECT, "Display buffer-stack panel") { Buffer *buf; int ok; char cmd; ok = FALSE; do { buf = selectBuffer(Firstbuf, Currentbuf, &cmd); switch (cmd) { case 'B': ok = TRUE; break; case '\n': case ' ': Currentbuf = buf; ok = TRUE; break; case 'D': delBuffer(buf); if (Firstbuf == NULL) { /* No more buffer */ Firstbuf = nullBuffer(); Currentbuf = Firstbuf; } break; case 'q': qquitfm(); break; case 'Q': quitfm(); break; } } while (!ok); for (buf = Firstbuf; buf != NULL; buf = buf->nextBuffer) { if (buf == Currentbuf) continue; #ifdef USE_IMAGE deleteImage(buf); #endif if (clear_buffer) tmpClearBuffer(buf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* Suspend (on BSD), or run interactive shell (on SysV) */ DEFUN(susp, INTERRUPT SUSPEND, "Suspend w3m to background") { #ifndef SIGSTOP char *shell; #endif /* not SIGSTOP */ move(LASTLINE, 0); clrtoeolx(); refresh(); fmTerm(); #ifndef SIGSTOP shell = getenv("SHELL"); if (shell == NULL) shell = "/bin/sh"; system(shell); #else /* SIGSTOP */ #ifdef SIGTSTP signal(SIGTSTP, SIG_DFL); /* just in case */ /* * Note: If susp() was called from SIGTSTP handler, * unblocking SIGTSTP would be required here. * Currently not. */ kill(0, SIGTSTP); /* stop whole job, not a single process */ #else kill((pid_t) 0, SIGSTOP); #endif #endif /* SIGSTOP */ fmInit(); displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* Go to specified line */ static void _goLine(char *l) { if (l == NULL || *l == '\0' || Currentbuf->currentLine == NULL) { displayBuffer(Currentbuf, B_FORCE_REDRAW); return; } Currentbuf->pos = 0; if (((*l == '^') || (*l == '$')) && prec_num) { gotoRealLine(Currentbuf, prec_num); } else if (*l == '^') { Currentbuf->topLine = Currentbuf->currentLine = Currentbuf->firstLine; } else if (*l == '$') { Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->lastLine, -(Currentbuf->LINES + 1) / 2, TRUE); Currentbuf->currentLine = Currentbuf->lastLine; } else gotoRealLine(Currentbuf, atoi(l)); arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(goLine, GOTO_LINE, "Go to the specified line") { char *str = searchKeyData(); if (prec_num) _goLine("^"); else if (str) _goLine(str); else /* FIXME: gettextize? */ _goLine(inputStr("Goto line: ", "")); } DEFUN(goLineF, BEGIN, "Go to the first line") { _goLine("^"); } DEFUN(goLineL, END, "Go to the last line") { _goLine("$"); } /* Go to the beginning of the line */ DEFUN(linbeg, LINE_BEGIN, "Go to the beginning of the line") { if (Currentbuf->firstLine == NULL) return; while (Currentbuf->currentLine->prev && Currentbuf->currentLine->bpos) cursorUp0(Currentbuf, 1); Currentbuf->pos = 0; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* Go to the bottom of the line */ DEFUN(linend, LINE_END, "Go to the end of the line") { if (Currentbuf->firstLine == NULL) return; while (Currentbuf->currentLine->next && Currentbuf->currentLine->next->bpos) cursorDown0(Currentbuf, 1); Currentbuf->pos = Currentbuf->currentLine->len - 1; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } static int cur_real_linenumber(Buffer *buf) { Line *l, *cur = buf->currentLine; int n; if (!cur) return 1; n = cur->real_linenumber ? cur->real_linenumber : 1; for (l = buf->firstLine; l && l != cur && l->real_linenumber == 0; l = l->next) { /* header */ if (l->bpos == 0) n++; } return n; } /* Run editor on the current buffer */ DEFUN(editBf, EDIT, "Edit local source") { char *fn = Currentbuf->filename; Str cmd; if (fn == NULL || Currentbuf->pagerSource != NULL || /* Behaving as a pager */ (Currentbuf->type == NULL && Currentbuf->edit == NULL) || /* Reading shell */ Currentbuf->real_scheme != SCM_LOCAL || !strcmp(Currentbuf->currentURL.file, "-") || /* file is std input */ Currentbuf->bufferprop & BP_FRAME) { /* Frame */ disp_err_message("Can't edit other than local file", TRUE); return; } if (Currentbuf->edit) cmd = unquote_mailcap(Currentbuf->edit, Currentbuf->real_type, fn, checkHeader(Currentbuf, "Content-Type:"), NULL); else cmd = myEditor(Editor, shell_quote(fn), cur_real_linenumber(Currentbuf)); fmTerm(); system(cmd->ptr); fmInit(); displayBuffer(Currentbuf, B_FORCE_REDRAW); reload(); } /* Run editor on the current screen */ DEFUN(editScr, EDIT_SCREEN, "Edit rendered copy of document") { char *tmpf; FILE *f; tmpf = tmpfname(TMPF_DFL, NULL)->ptr; f = fopen(tmpf, "w"); if (f == NULL) { /* FIXME: gettextize? */ disp_err_message(Sprintf("Can't open %s", tmpf)->ptr, TRUE); return; } saveBuffer(Currentbuf, f, TRUE); fclose(f); fmTerm(); system(myEditor(Editor, shell_quote(tmpf), cur_real_linenumber(Currentbuf))->ptr); fmInit(); unlink(tmpf); displayBuffer(Currentbuf, B_FORCE_REDRAW); } #ifdef USE_MARK /* Set / unset mark */ DEFUN(_mark, MARK, "Set/unset mark") { Line *l; if (!use_mark) return; if (Currentbuf->firstLine == NULL) return; l = Currentbuf->currentLine; l->propBuf[Currentbuf->pos] ^= PE_MARK; displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* Go to next mark */ DEFUN(nextMk, NEXT_MARK, "Go to the next mark") { Line *l; int i; if (!use_mark) return; if (Currentbuf->firstLine == NULL) return; i = Currentbuf->pos + 1; l = Currentbuf->currentLine; if (i >= l->len) { i = 0; l = l->next; } while (l != NULL) { for (; i < l->len; i++) { if (l->propBuf[i] & PE_MARK) { Currentbuf->currentLine = l; Currentbuf->pos = i; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); return; } } l = l->next; i = 0; } /* FIXME: gettextize? */ disp_message("No mark exist after here", TRUE); } /* Go to previous mark */ DEFUN(prevMk, PREV_MARK, "Go to the previous mark") { Line *l; int i; if (!use_mark) return; if (Currentbuf->firstLine == NULL) return; i = Currentbuf->pos - 1; l = Currentbuf->currentLine; if (i < 0) { l = l->prev; if (l != NULL) i = l->len - 1; } while (l != NULL) { for (; i >= 0; i--) { if (l->propBuf[i] & PE_MARK) { Currentbuf->currentLine = l; Currentbuf->pos = i; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); return; } } l = l->prev; if (l != NULL) i = l->len - 1; } /* FIXME: gettextize? */ disp_message("No mark exist before here", TRUE); } /* Mark place to which the regular expression matches */ DEFUN(reMark, REG_MARK, "Mark all occurences of a pattern") { Line *l; char *str; char *p, *p1, *p2; if (!use_mark) return; str = searchKeyData(); if (str == NULL || *str == '\0') { str = inputStrHist("(Mark)Regexp: ", MarkString, TextHist); if (str == NULL || *str == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } } str = conv_search_string(str, DisplayCharset); if ((str = regexCompile(str, 1)) != NULL) { disp_message(str, TRUE); return; } MarkString = str; for (l = Currentbuf->firstLine; l != NULL; l = l->next) { p = l->lineBuf; for (;;) { if (regexMatch(p, &l->lineBuf[l->len] - p, p == l->lineBuf) == 1) { matchedPosition(&p1, &p2); l->propBuf[p1 - l->lineBuf] |= PE_MARK; p = p2; } else break; } } displayBuffer(Currentbuf, B_FORCE_REDRAW); } #endif /* USE_MARK */ static Buffer * loadNormalBuf(Buffer *buf, int renderframe) { pushBuffer(buf); if (renderframe && RenderFrame && Currentbuf->frameset != NULL) rFrame(); return buf; } static Buffer * loadLink(char *url, char *target, char *referer, FormList *request) { Buffer *buf, *nfbuf; union frameset_element *f_element = NULL; int flag = 0; ParsedURL *base, pu; const int *no_referer_ptr; message(Sprintf("loading %s", url)->ptr, 0, 0); refresh(); no_referer_ptr = query_SCONF_NO_REFERER_FROM(&Currentbuf->currentURL); base = baseURL(Currentbuf); if ((no_referer_ptr && *no_referer_ptr) || base == NULL || base->scheme == SCM_LOCAL || base->scheme == SCM_LOCAL_CGI) referer = NO_REFERER; if (referer == NULL) referer = parsedURL2Str(&Currentbuf->currentURL)->ptr; buf = loadGeneralFile(url, baseURL(Currentbuf), referer, flag, request); if (buf == NULL) { char *emsg = Sprintf("Can't load %s", url)->ptr; disp_err_message(emsg, FALSE); return NULL; } parseURL2(url, &pu, base); pushHashHist(URLHist, parsedURL2Str(&pu)->ptr); if (buf == NO_BUFFER) { return NULL; } if (!on_target) /* open link as an indivisual page */ return loadNormalBuf(buf, TRUE); if (do_download) /* download (thus no need to render frames) */ return loadNormalBuf(buf, FALSE); if (target == NULL || /* no target specified (that means this page is not a frame page) */ !strcmp(target, "_top") || /* this link is specified to be opened as an indivisual * page */ !(Currentbuf->bufferprop & BP_FRAME) /* This page is not a frame page */ ) { return loadNormalBuf(buf, TRUE); } nfbuf = Currentbuf->linkBuffer[LB_N_FRAME]; if (nfbuf == NULL) { /* original page (that contains tag) doesn't exist */ return loadNormalBuf(buf, TRUE); } f_element = search_frame(nfbuf->frameset, target); if (f_element == NULL) { /* specified target doesn't exist in this frameset */ return loadNormalBuf(buf, TRUE); } /* frame page */ /* stack current frameset */ pushFrameTree(&(nfbuf->frameQ), copyFrameSet(nfbuf->frameset), Currentbuf); /* delete frame view buffer */ delBuffer(Currentbuf); Currentbuf = nfbuf; /* nfbuf->frameset = copyFrameSet(nfbuf->frameset); */ resetFrameElement(f_element, buf, referer, request); discardBuffer(buf); rFrame(); { Anchor *al = NULL; char *label = pu.label; if (label && f_element->element->attr == F_BODY) { al = searchAnchor(f_element->body->nameList, label); } if (!al) { label = Strnew_m_charp("_", target, NULL)->ptr; al = searchURLLabel(Currentbuf, label); } if (al) { gotoLine(Currentbuf, al->start.line); if (label_topline) Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine, Currentbuf->currentLine-> linenumber - Currentbuf->topLine->linenumber, FALSE); Currentbuf->pos = al->start.pos; arrangeCursor(Currentbuf); } } displayBuffer(Currentbuf, B_NORMAL); return buf; } static void gotoLabel(char *label) { Buffer *buf; Anchor *al; int i; al = searchURLLabel(Currentbuf, label); if (al == NULL) { /* FIXME: gettextize? */ disp_message(Sprintf("%s is not found", label)->ptr, TRUE); return; } buf = newBuffer(Currentbuf->width); copyBuffer(buf, Currentbuf); for (i = 0; i < MAX_LB; i++) buf->linkBuffer[i] = NULL; buf->currentURL.label = allocStr(label, -1); pushHashHist(URLHist, parsedURL2Str(&buf->currentURL)->ptr); (*buf->clone)++; pushBuffer(buf); gotoLine(Currentbuf, al->start.line); if (label_topline) Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine, Currentbuf->currentLine->linenumber - Currentbuf->topLine->linenumber, FALSE); Currentbuf->pos = al->start.pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); return; } static int handleMailto(char *url) { Str to; char *pos; if (strncasecmp(url, "mailto:", 7)) return 0; #ifdef USE_W3MMAILER if (! non_null(Mailer) || MailtoOptions == MAILTO_OPTIONS_USE_W3MMAILER) return 0; #else if (!non_null(Mailer)) { /* FIXME: gettextize? */ disp_err_message("no mailer is specified", TRUE); return 1; } #endif /* invoke external mailer */ if (MailtoOptions == MAILTO_OPTIONS_USE_MAILTO_URL) { to = Strnew_charp(html_unquote(url)); } else { to = Strnew_charp(url + 7); if ((pos = strchr(to->ptr, '?')) != NULL) Strtruncate(to, pos - to->ptr); } fmTerm(); system(myExtCommand(Mailer, shell_quote(file_unquote(to->ptr)), FALSE)->ptr); fmInit(); displayBuffer(Currentbuf, B_FORCE_REDRAW); pushHashHist(URLHist, url); return 1; } /* follow HREF link */ DEFUN(followA, GOTO_LINK, "Follow current hyperlink in a new buffer") { Anchor *a; ParsedURL u; #ifdef USE_IMAGE int x = 0, y = 0, map = 0; #endif char *url; if (Currentbuf->firstLine == NULL) return; #ifdef USE_IMAGE a = retrieveCurrentImg(Currentbuf); if (a && a->image && a->image->map) { _followForm(FALSE); return; } if (a && a->image && a->image->ismap) { getMapXY(Currentbuf, a, &x, &y); map = 1; } #else a = retrieveCurrentMap(Currentbuf); if (a) { _followForm(FALSE); return; } #endif a = retrieveCurrentAnchor(Currentbuf); if (a == NULL) { _followForm(FALSE); return; } if (*a->url == '#') { /* index within this buffer */ gotoLabel(a->url + 1); return; } parseURL2(a->url, &u, baseURL(Currentbuf)); if (Strcmp(parsedURL2Str(&u), parsedURL2Str(&Currentbuf->currentURL)) == 0) { /* index within this buffer */ if (u.label) { gotoLabel(u.label); return; } } if (handleMailto(a->url)) return; #if 0 else if (!strncasecmp(a->url, "news:", 5) && strchr(a->url, '@') == NULL) { /* news:newsgroup is not supported */ /* FIXME: gettextize? */ disp_err_message("news:newsgroup_name is not supported", TRUE); return; } #endif /* USE_NNTP */ url = a->url; #ifdef USE_IMAGE if (map) url = Sprintf("%s?%d,%d", a->url, x, y)->ptr; #endif if (check_target && open_tab_blank && a->target && (!strcasecmp(a->target, "_new") || !strcasecmp(a->target, "_blank"))) { Buffer *buf; _newT(); buf = Currentbuf; loadLink(url, a->target, a->referer, NULL); if (buf != Currentbuf) delBuffer(buf); else deleteTab(CurrentTab); displayBuffer(Currentbuf, B_FORCE_REDRAW); return; } loadLink(url, a->target, a->referer, NULL); displayBuffer(Currentbuf, B_NORMAL); } /* follow HREF link in the buffer */ void bufferA(void) { on_target = FALSE; followA(); on_target = TRUE; } /* view inline image */ DEFUN(followI, VIEW_IMAGE, "Display image in viewer") { Anchor *a; Buffer *buf; if (Currentbuf->firstLine == NULL) return; a = retrieveCurrentImg(Currentbuf); if (a == NULL) return; /* FIXME: gettextize? */ message(Sprintf("loading %s", a->url)->ptr, 0, 0); refresh(); buf = loadGeneralFile(a->url, baseURL(Currentbuf), NULL, 0, NULL); if (buf == NULL) { /* FIXME: gettextize? */ char *emsg = Sprintf("Can't load %s", a->url)->ptr; disp_err_message(emsg, FALSE); } else if (buf != NO_BUFFER) { pushBuffer(buf); } displayBuffer(Currentbuf, B_NORMAL); } static FormItemList * save_submit_formlist(FormItemList *src) { FormList *list; FormList *srclist; FormItemList *srcitem; FormItemList *item; FormItemList *ret = NULL; #ifdef MENU_SELECT FormSelectOptionItem *opt; FormSelectOptionItem *curopt; FormSelectOptionItem *srcopt; #endif /* MENU_SELECT */ if (src == NULL) return NULL; srclist = src->parent; list = New(FormList); list->method = srclist->method; list->action = Strdup(srclist->action); #ifdef USE_M17N list->charset = srclist->charset; #endif list->enctype = srclist->enctype; list->nitems = srclist->nitems; list->body = srclist->body; list->boundary = srclist->boundary; list->length = srclist->length; for (srcitem = srclist->item; srcitem; srcitem = srcitem->next) { item = New(FormItemList); item->type = srcitem->type; item->name = Strdup(srcitem->name); item->value = Strdup(srcitem->value); item->checked = srcitem->checked; item->accept = srcitem->accept; item->size = srcitem->size; item->rows = srcitem->rows; item->maxlength = srcitem->maxlength; item->readonly = srcitem->readonly; #ifdef MENU_SELECT opt = curopt = NULL; for (srcopt = srcitem->select_option; srcopt; srcopt = srcopt->next) { if (!srcopt->checked) continue; opt = New(FormSelectOptionItem); opt->value = Strdup(srcopt->value); opt->label = Strdup(srcopt->label); opt->checked = srcopt->checked; if (item->select_option == NULL) { item->select_option = curopt = opt; } else { curopt->next = opt; curopt = curopt->next; } } item->select_option = opt; if (srcitem->label) item->label = Strdup(srcitem->label); #endif /* MENU_SELECT */ item->parent = list; item->next = NULL; if (list->lastitem == NULL) { list->item = list->lastitem = item; } else { list->lastitem->next = item; list->lastitem = item; } if (srcitem == src) ret = item; } return ret; } #ifdef USE_M17N static Str conv_form_encoding(Str val, FormItemList *fi, Buffer *buf) { wc_ces charset = SystemCharset; if (fi->parent->charset) charset = fi->parent->charset; else if (buf->document_charset && buf->document_charset != WC_CES_US_ASCII) charset = buf->document_charset; return wc_Str_conv_strict(val, InnerCharset, charset); } #else #define conv_form_encoding(val, fi, buf) (val) #endif static void query_from_followform(Str *query, FormItemList *fi, int multipart) { FormItemList *f2; FILE *body = NULL; if (multipart) { *query = tmpfname(TMPF_DFL, NULL); body = fopen((*query)->ptr, "w"); if (body == NULL) { return; } fi->parent->body = (*query)->ptr; fi->parent->boundary = Sprintf("------------------------------%d%ld%ld%ld", CurrentPid, fi->parent, fi->parent->body, fi->parent->boundary)->ptr; } *query = Strnew(); for (f2 = fi->parent->item; f2; f2 = f2->next) { if (f2->name == NULL) continue; /* is translated into single text form */ if (f2->name->length == 0 && (multipart || f2->type != FORM_INPUT_TEXT)) continue; switch (f2->type) { case FORM_INPUT_RESET: /* do nothing */ continue; case FORM_INPUT_SUBMIT: case FORM_INPUT_IMAGE: if (f2 != fi || f2->value == NULL) continue; break; case FORM_INPUT_RADIO: case FORM_INPUT_CHECKBOX: if (!f2->checked) continue; } if (multipart) { if (f2->type == FORM_INPUT_IMAGE) { int x = 0, y = 0; #ifdef USE_IMAGE getMapXY(Currentbuf, retrieveCurrentImg(Currentbuf), &x, &y); #endif *query = Strdup(conv_form_encoding(f2->name, fi, Currentbuf)); Strcat_charp(*query, ".x"); form_write_data(body, fi->parent->boundary, (*query)->ptr, Sprintf("%d", x)->ptr); *query = Strdup(conv_form_encoding(f2->name, fi, Currentbuf)); Strcat_charp(*query, ".y"); form_write_data(body, fi->parent->boundary, (*query)->ptr, Sprintf("%d", y)->ptr); } else if (f2->name && f2->name->length > 0 && f2->value != NULL) { /* not IMAGE */ *query = conv_form_encoding(f2->value, fi, Currentbuf); if (f2->type == FORM_INPUT_FILE) form_write_from_file(body, fi->parent->boundary, conv_form_encoding(f2->name, fi, Currentbuf)->ptr, (*query)->ptr, Str_conv_to_system(f2->value)->ptr); else form_write_data(body, fi->parent->boundary, conv_form_encoding(f2->name, fi, Currentbuf)->ptr, (*query)->ptr); } } else { /* not multipart */ if (f2->type == FORM_INPUT_IMAGE) { int x = 0, y = 0; #ifdef USE_IMAGE getMapXY(Currentbuf, retrieveCurrentImg(Currentbuf), &x, &y); #endif Strcat(*query, Str_form_quote(conv_form_encoding (f2->name, fi, Currentbuf))); Strcat(*query, Sprintf(".x=%d&", x)); Strcat(*query, Str_form_quote(conv_form_encoding (f2->name, fi, Currentbuf))); Strcat(*query, Sprintf(".y=%d", y)); } else { /* not IMAGE */ if (f2->name && f2->name->length > 0) { Strcat(*query, Str_form_quote(conv_form_encoding (f2->name, fi, Currentbuf))); Strcat_char(*query, '='); } if (f2->value != NULL) { if (fi->parent->method == FORM_METHOD_INTERNAL) Strcat(*query, Str_form_quote(f2->value)); else { Strcat(*query, Str_form_quote(conv_form_encoding (f2->value, fi, Currentbuf))); } } } if (f2->next) Strcat_char(*query, '&'); } } if (multipart) { fprintf(body, "--%s--\r\n", fi->parent->boundary); fclose(body); } else { /* remove trailing & */ while (Strlastchar(*query) == '&') Strshrink(*query, 1); } } /* submit form */ DEFUN(submitForm, SUBMIT, "Submit form") { _followForm(TRUE); } /* process form */ void followForm(void) { _followForm(FALSE); } static void _followForm(int submit) { Anchor *a, *a2; char *p; FormItemList *fi, *f2; Str tmp, tmp2; int multipart = 0, i; if (Currentbuf->firstLine == NULL) return; a = retrieveCurrentForm(Currentbuf); if (a == NULL) return; fi = (FormItemList *)a->url; switch (fi->type) { case FORM_INPUT_TEXT: if (submit) goto do_submit; if (fi->readonly) /* FIXME: gettextize? */ disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE); /* FIXME: gettextize? */ p = inputStrHist("TEXT:", fi->value ? fi->value->ptr : NULL, TextHist); if (p == NULL || fi->readonly) break; fi->value = Strnew_charp(p); formUpdateBuffer(a, Currentbuf, fi); if (fi->accept || fi->parent->nitems == 1) goto do_submit; break; case FORM_INPUT_FILE: if (submit) goto do_submit; if (fi->readonly) /* FIXME: gettextize? */ disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE); /* FIXME: gettextize? */ p = inputFilenameHist("Filename:", fi->value ? fi->value->ptr : NULL, NULL); if (p == NULL || fi->readonly) break; fi->value = Strnew_charp(p); formUpdateBuffer(a, Currentbuf, fi); if (fi->accept || fi->parent->nitems == 1) goto do_submit; break; case FORM_INPUT_PASSWORD: if (submit) goto do_submit; if (fi->readonly) { /* FIXME: gettextize? */ disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE); break; } /* FIXME: gettextize? */ p = inputLine("Password:", fi->value ? fi->value->ptr : NULL, IN_PASSWORD); if (p == NULL) break; fi->value = Strnew_charp(p); formUpdateBuffer(a, Currentbuf, fi); if (fi->accept) goto do_submit; break; case FORM_TEXTAREA: if (submit) goto do_submit; if (fi->readonly) /* FIXME: gettextize? */ disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE); input_textarea(fi); formUpdateBuffer(a, Currentbuf, fi); break; case FORM_INPUT_RADIO: if (submit) goto do_submit; if (fi->readonly) { /* FIXME: gettextize? */ disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE); break; } formRecheckRadio(a, Currentbuf, fi); break; case FORM_INPUT_CHECKBOX: if (submit) goto do_submit; if (fi->readonly) { /* FIXME: gettextize? */ disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE); break; } fi->checked = !fi->checked; formUpdateBuffer(a, Currentbuf, fi); break; #ifdef MENU_SELECT case FORM_SELECT: if (submit) goto do_submit; if (!formChooseOptionByMenu(fi, Currentbuf->cursorX - Currentbuf->pos + a->start.pos + Currentbuf->rootX, Currentbuf->cursorY + Currentbuf->rootY)) break; formUpdateBuffer(a, Currentbuf, fi); if (fi->parent->nitems == 1) goto do_submit; break; #endif /* MENU_SELECT */ case FORM_INPUT_IMAGE: case FORM_INPUT_SUBMIT: case FORM_INPUT_BUTTON: do_submit: tmp = Strnew(); multipart = (fi->parent->method == FORM_METHOD_POST && fi->parent->enctype == FORM_ENCTYPE_MULTIPART); query_from_followform(&tmp, fi, multipart); tmp2 = Strdup(fi->parent->action); if (!Strcmp_charp(tmp2, "!CURRENT_URL!")) { /* It means "current URL" */ tmp2 = parsedURL2Str(&Currentbuf->currentURL); if ((p = strchr(tmp2->ptr, '?')) != NULL) Strshrink(tmp2, (tmp2->ptr + tmp2->length) - p); } if (fi->parent->method == FORM_METHOD_GET) { if ((p = strchr(tmp2->ptr, '?')) != NULL) Strshrink(tmp2, (tmp2->ptr + tmp2->length) - p); Strcat_charp(tmp2, "?"); Strcat(tmp2, tmp); loadLink(tmp2->ptr, a->target, NULL, NULL); } else if (fi->parent->method == FORM_METHOD_POST) { Buffer *buf; if (multipart) { struct stat st; stat(fi->parent->body, &st); fi->parent->length = st.st_size; } else { fi->parent->body = tmp->ptr; fi->parent->length = tmp->length; } buf = loadLink(tmp2->ptr, a->target, NULL, fi->parent); if (multipart) { unlink(fi->parent->body); } if (buf && !(buf->bufferprop & BP_REDIRECTED)) { /* buf must be Currentbuf */ /* BP_REDIRECTED means that the buffer is obtained through * Location: header. In this case, buf->form_submit must not be set * because the page is not loaded by POST method but GET method. */ buf->form_submit = save_submit_formlist(fi); } } 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 */ do_internal(tmp2->ptr, tmp->ptr); } else { disp_err_message("Can't send form because of illegal method.", FALSE); } break; case FORM_INPUT_RESET: for (i = 0; i < Currentbuf->formitem->nanchor; i++) { a2 = &Currentbuf->formitem->anchors[i]; f2 = (FormItemList *)a2->url; if (f2->parent == fi->parent && f2->name && f2->value && f2->type != FORM_INPUT_SUBMIT && f2->type != FORM_INPUT_HIDDEN && f2->type != FORM_INPUT_RESET) { f2->value = f2->init_value; f2->checked = f2->init_checked; #ifdef MENU_SELECT f2->label = f2->init_label; f2->selected = f2->init_selected; #endif /* MENU_SELECT */ formUpdateBuffer(a2, Currentbuf, f2); } } break; case FORM_INPUT_HIDDEN: default: break; } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* go to the top anchor */ DEFUN(topA, LINK_BEGIN, "Move to the first hyperlink") { HmarkerList *hl = Currentbuf->hmarklist; BufferPoint *po; Anchor *an; int hseq = 0; if (Currentbuf->firstLine == NULL) return; if (!hl || hl->nmark == 0) return; if (prec_num > hl->nmark) hseq = hl->nmark - 1; else if (prec_num > 0) hseq = prec_num - 1; do { if (hseq >= hl->nmark) return; po = hl->marks + hseq; an = retrieveAnchor(Currentbuf->href, po->line, po->pos); if (an == NULL) an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos); hseq++; } while (an == NULL); gotoLine(Currentbuf, po->line); Currentbuf->pos = po->pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* go to the last anchor */ DEFUN(lastA, LINK_END, "Move to the last hyperlink") { HmarkerList *hl = Currentbuf->hmarklist; BufferPoint *po; Anchor *an; int hseq; if (Currentbuf->firstLine == NULL) return; if (!hl || hl->nmark == 0) return; if (prec_num >= hl->nmark) hseq = 0; else if (prec_num > 0) hseq = hl->nmark - prec_num; else hseq = hl->nmark - 1; do { if (hseq < 0) return; po = hl->marks + hseq; an = retrieveAnchor(Currentbuf->href, po->line, po->pos); if (an == NULL) an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos); hseq--; } while (an == NULL); gotoLine(Currentbuf, po->line); Currentbuf->pos = po->pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* go to the nth anchor */ DEFUN(nthA, LINK_N, "Go to the nth link") { HmarkerList *hl = Currentbuf->hmarklist; BufferPoint *po; Anchor *an; int n = searchKeyNum(); if (n < 0 || n > hl->nmark) return; if (Currentbuf->firstLine == NULL) return; if (!hl || hl->nmark == 0) return; po = hl->marks + n-1; an = retrieveAnchor(Currentbuf->href, po->line, po->pos); if (an == NULL) an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos); if (an == NULL) return; gotoLine(Currentbuf, po->line); Currentbuf->pos = po->pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* go to the next anchor */ DEFUN(nextA, NEXT_LINK, "Move to the next hyperlink") { _nextA(FALSE); } /* go to the previous anchor */ DEFUN(prevA, PREV_LINK, "Move to the previous hyperlink") { _prevA(FALSE); } /* go to the next visited anchor */ DEFUN(nextVA, NEXT_VISITED, "Move to the next visited hyperlink") { _nextA(TRUE); } /* go to the previous visited anchor */ DEFUN(prevVA, PREV_VISITED, "Move to the previous visited hyperlink") { _prevA(TRUE); } /* go to the next [visited] anchor */ static void _nextA(int visited) { HmarkerList *hl = Currentbuf->hmarklist; BufferPoint *po; Anchor *an, *pan; int i, x, y, n = searchKeyNum(); ParsedURL url; if (Currentbuf->firstLine == NULL) return; if (!hl || hl->nmark == 0) return; an = retrieveCurrentAnchor(Currentbuf); if (visited != TRUE && an == NULL) an = retrieveCurrentForm(Currentbuf); y = Currentbuf->currentLine->linenumber; x = Currentbuf->pos; if (visited == TRUE) { n = hl->nmark; } for (i = 0; i < n; i++) { pan = an; if (an && an->hseq >= 0) { int hseq = an->hseq + 1; do { if (hseq >= hl->nmark) { if (visited == TRUE) return; an = pan; goto _end; } po = &hl->marks[hseq]; an = retrieveAnchor(Currentbuf->href, po->line, po->pos); if (visited != TRUE && an == NULL) an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos); hseq++; if (visited == TRUE && an) { parseURL2(an->url, &url, baseURL(Currentbuf)); if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) { goto _end; } } } while (an == NULL || an == pan); } else { an = closest_next_anchor(Currentbuf->href, NULL, x, y); if (visited != TRUE) an = closest_next_anchor(Currentbuf->formitem, an, x, y); if (an == NULL) { if (visited == TRUE) return; an = pan; break; } x = an->start.pos; y = an->start.line; if (visited == TRUE) { parseURL2(an->url, &url, baseURL(Currentbuf)); if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) { goto _end; } } } } if (visited == TRUE) return; _end: if (an == NULL || an->hseq < 0) return; po = &hl->marks[an->hseq]; gotoLine(Currentbuf, po->line); Currentbuf->pos = po->pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* go to the previous anchor */ static void _prevA(int visited) { HmarkerList *hl = Currentbuf->hmarklist; BufferPoint *po; Anchor *an, *pan; int i, x, y, n = searchKeyNum(); ParsedURL url; if (Currentbuf->firstLine == NULL) return; if (!hl || hl->nmark == 0) return; an = retrieveCurrentAnchor(Currentbuf); if (visited != TRUE && an == NULL) an = retrieveCurrentForm(Currentbuf); y = Currentbuf->currentLine->linenumber; x = Currentbuf->pos; if (visited == TRUE) { n = hl->nmark; } for (i = 0; i < n; i++) { pan = an; if (an && an->hseq >= 0) { int hseq = an->hseq - 1; do { if (hseq < 0) { if (visited == TRUE) return; an = pan; goto _end; } po = hl->marks + hseq; an = retrieveAnchor(Currentbuf->href, po->line, po->pos); if (visited != TRUE && an == NULL) an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos); hseq--; if (visited == TRUE && an) { parseURL2(an->url, &url, baseURL(Currentbuf)); if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) { goto _end; } } } while (an == NULL || an == pan); } else { an = closest_prev_anchor(Currentbuf->href, NULL, x, y); if (visited != TRUE) an = closest_prev_anchor(Currentbuf->formitem, an, x, y); if (an == NULL) { if (visited == TRUE) return; an = pan; break; } x = an->start.pos; y = an->start.line; if (visited == TRUE && an) { parseURL2(an->url, &url, baseURL(Currentbuf)); if (getHashHist(URLHist, parsedURL2Str(&url)->ptr)) { goto _end; } } } } if (visited == TRUE) return; _end: if (an == NULL || an->hseq < 0) return; po = hl->marks + an->hseq; gotoLine(Currentbuf, po->line); Currentbuf->pos = po->pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* go to the next left/right anchor */ static void nextX(int d, int dy) { HmarkerList *hl = Currentbuf->hmarklist; Anchor *an, *pan; Line *l; int i, x, y, n = searchKeyNum(); if (Currentbuf->firstLine == NULL) return; if (!hl || hl->nmark == 0) return; an = retrieveCurrentAnchor(Currentbuf); if (an == NULL) an = retrieveCurrentForm(Currentbuf); l = Currentbuf->currentLine; x = Currentbuf->pos; y = l->linenumber; pan = NULL; for (i = 0; i < n; i++) { if (an) x = (d > 0) ? an->end.pos : an->start.pos - 1; an = NULL; while (1) { for (; x >= 0 && x < l->len; x += d) { an = retrieveAnchor(Currentbuf->href, y, x); if (!an) an = retrieveAnchor(Currentbuf->formitem, y, x); if (an) { pan = an; break; } } if (!dy || an) break; l = (dy > 0) ? l->next : l->prev; if (!l) break; x = (d > 0) ? 0 : l->len - 1; y = l->linenumber; } if (!an) break; } if (pan == NULL) return; gotoLine(Currentbuf, y); Currentbuf->pos = pan->start.pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* go to the next downward/upward anchor */ static void nextY(int d) { HmarkerList *hl = Currentbuf->hmarklist; Anchor *an, *pan; int i, x, y, n = searchKeyNum(); int hseq; if (Currentbuf->firstLine == NULL) return; if (!hl || hl->nmark == 0) return; an = retrieveCurrentAnchor(Currentbuf); if (an == NULL) an = retrieveCurrentForm(Currentbuf); x = Currentbuf->pos; y = Currentbuf->currentLine->linenumber + d; pan = NULL; hseq = -1; for (i = 0; i < n; i++) { if (an) hseq = abs(an->hseq); an = NULL; for (; y >= 0 && y <= Currentbuf->lastLine->linenumber; y += d) { an = retrieveAnchor(Currentbuf->href, y, x); if (!an) an = retrieveAnchor(Currentbuf->formitem, y, x); if (an && hseq != abs(an->hseq)) { pan = an; break; } } if (!an) break; } if (pan == NULL) return; gotoLine(Currentbuf, pan->start.line); arrangeLine(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } /* go to the next left anchor */ DEFUN(nextL, NEXT_LEFT, "Move left to the next hyperlink") { nextX(-1, 0); } /* go to the next left-up anchor */ DEFUN(nextLU, NEXT_LEFT_UP, "Move left or upward to the next hyperlink") { nextX(-1, -1); } /* go to the next right anchor */ DEFUN(nextR, NEXT_RIGHT, "Move right to the next hyperlink") { nextX(1, 0); } /* go to the next right-down anchor */ DEFUN(nextRD, NEXT_RIGHT_DOWN, "Move right or downward to the next hyperlink") { nextX(1, 1); } /* go to the next downward anchor */ DEFUN(nextD, NEXT_DOWN, "Move downward to the next hyperlink") { nextY(1); } /* go to the next upward anchor */ DEFUN(nextU, NEXT_UP, "Move upward to the next hyperlink") { nextY(-1); } /* go to the next bufferr */ DEFUN(nextBf, NEXT, "Switch to the next buffer") { Buffer *buf; int i; for (i = 0; i < PREC_NUM; i++) { buf = prevBuffer(Firstbuf, Currentbuf); if (!buf) { if (i == 0) return; break; } Currentbuf = buf; } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* go to the previous bufferr */ DEFUN(prevBf, PREV, "Switch to the previous buffer") { Buffer *buf; int i; for (i = 0; i < PREC_NUM; i++) { buf = Currentbuf->nextBuffer; if (!buf) { if (i == 0) return; break; } Currentbuf = buf; } displayBuffer(Currentbuf, B_FORCE_REDRAW); } static int checkBackBuffer(Buffer *buf) { Buffer *fbuf = buf->linkBuffer[LB_N_FRAME]; if (fbuf) { if (fbuf->frameQ) return TRUE; /* Currentbuf has stacked frames */ /* when no frames stacked and next is frame source, try next's * nextBuffer */ if (RenderFrame && fbuf == buf->nextBuffer) { if (fbuf->nextBuffer != NULL) return TRUE; else return FALSE; } } if (buf->nextBuffer) return TRUE; return FALSE; } /* delete current buffer and back to the previous buffer */ DEFUN(backBf, BACK, "Close current buffer and return to the one below in stack") { Buffer *buf = Currentbuf->linkBuffer[LB_N_FRAME]; if (!checkBackBuffer(Currentbuf)) { if (close_tab_back && nTab >= 1) { deleteTab(CurrentTab); displayBuffer(Currentbuf, B_FORCE_REDRAW); } else /* FIXME: gettextize? */ disp_message("Can't go back...", TRUE); return; } delBuffer(Currentbuf); if (buf) { if (buf->frameQ) { struct frameset *fs; long linenumber = buf->frameQ->linenumber; long top = buf->frameQ->top_linenumber; int pos = buf->frameQ->pos; int currentColumn = buf->frameQ->currentColumn; AnchorList *formitem = buf->frameQ->formitem; fs = popFrameTree(&(buf->frameQ)); deleteFrameSet(buf->frameset); buf->frameset = fs; if (buf == Currentbuf) { rFrame(); Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->firstLine, top - 1, FALSE); gotoLine(Currentbuf, linenumber); Currentbuf->pos = pos; Currentbuf->currentColumn = currentColumn; arrangeCursor(Currentbuf); formResetBuffer(Currentbuf, formitem); } } else if (RenderFrame && buf == Currentbuf) { delBuffer(Currentbuf); } } displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(deletePrevBuf, DELETE_PREVBUF, "Delete previous buffer (mainly for local CGI-scripts)") { Buffer *buf = Currentbuf->nextBuffer; if (buf) delBuffer(buf); } static void cmd_loadURL(char *url, ParsedURL *current, char *referer, FormList *request) { Buffer *buf; if (handleMailto(url)) return; #if 0 if (!strncasecmp(url, "news:", 5) && strchr(url, '@') == NULL) { /* news:newsgroup is not supported */ /* FIXME: gettextize? */ disp_err_message("news:newsgroup_name is not supported", TRUE); return; } #endif /* USE_NNTP */ refresh(); buf = loadGeneralFile(url, current, referer, 0, request); if (buf == NULL) { /* FIXME: gettextize? */ char *emsg = Sprintf("Can't load %s", conv_from_system(url))->ptr; disp_err_message(emsg, FALSE); } else if (buf != NO_BUFFER) { pushBuffer(buf); if (RenderFrame && Currentbuf->frameset != NULL) rFrame(); } displayBuffer(Currentbuf, B_NORMAL); } /* go to specified URL */ static void goURL0(char *prompt, int relative) { char *url, *referer; ParsedURL p_url, *current; Buffer *cur_buf = Currentbuf; const int *no_referer_ptr; url = searchKeyData(); if (url == NULL) { Hist *hist = copyHist(URLHist); Anchor *a; current = baseURL(Currentbuf); if (current) { char *c_url = parsedURL2Str(current)->ptr; if (DefaultURLString == DEFAULT_URL_CURRENT) url = url_decode2(c_url, NULL); else pushHist(hist, c_url); } a = retrieveCurrentAnchor(Currentbuf); if (a) { char *a_url; parseURL2(a->url, &p_url, current); a_url = parsedURL2Str(&p_url)->ptr; if (DefaultURLString == DEFAULT_URL_LINK) url = url_decode2(a_url, Currentbuf); else pushHist(hist, a_url); } url = inputLineHist(prompt, url, IN_URL, hist); if (url != NULL) SKIP_BLANKS(url); } if (relative) { no_referer_ptr = query_SCONF_NO_REFERER_FROM(&Currentbuf->currentURL); current = baseURL(Currentbuf); if ((no_referer_ptr && *no_referer_ptr) || current == NULL || current->scheme == SCM_LOCAL || current->scheme == SCM_LOCAL_CGI) referer = NO_REFERER; else referer = parsedURL2Str(&Currentbuf->currentURL)->ptr; url = url_encode(url, current, Currentbuf->document_charset); } else { current = NULL; referer = NULL; url = url_encode(url, NULL, 0); } if (url == NULL || *url == '\0') { displayBuffer(Currentbuf, B_FORCE_REDRAW); return; } if (*url == '#') { gotoLabel(url + 1); return; } parseURL2(url, &p_url, current); pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr); cmd_loadURL(url, current, referer, NULL); if (Currentbuf != cur_buf) /* success */ pushHashHist(URLHist, parsedURL2Str(&Currentbuf->currentURL)->ptr); } DEFUN(goURL, GOTO, "Open specified document in a new buffer") { goURL0("Goto URL: ", FALSE); } DEFUN(goHome, GOTO_HOME, "Open home page in a new buffer") { char *url; if ((url = getenv("HTTP_HOME")) != NULL || (url = getenv("WWW_HOME")) != NULL) { ParsedURL p_url; Buffer *cur_buf = Currentbuf; SKIP_BLANKS(url); url = url_encode(url, NULL, 0); parseURL2(url, &p_url, NULL); pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr); cmd_loadURL(url, NULL, NULL, NULL); if (Currentbuf != cur_buf) /* success */ pushHashHist(URLHist, parsedURL2Str(&Currentbuf->currentURL)->ptr); } } DEFUN(gorURL, GOTO_RELATIVE, "Go to relative address") { goURL0("Goto relative URL: ", TRUE); } static void cmd_loadBuffer(Buffer *buf, int prop, int linkid) { if (buf == NULL) { disp_err_message("Can't load string", FALSE); } else if (buf != NO_BUFFER) { buf->bufferprop |= (BP_INTERNAL | prop); if (!(buf->bufferprop & BP_NO_URL)) copyParsedURL(&buf->currentURL, &Currentbuf->currentURL); if (linkid != LB_NOLINK) { buf->linkBuffer[REV_LB[linkid]] = Currentbuf; Currentbuf->linkBuffer[linkid] = buf; } pushBuffer(buf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* load bookmark */ DEFUN(ldBmark, BOOKMARK VIEW_BOOKMARK, "View bookmarks") { cmd_loadURL(BookmarkFile, NULL, NO_REFERER, NULL); } /* Add current to bookmark */ DEFUN(adBmark, ADD_BOOKMARK, "Add current page to bookmarks") { Str tmp; FormList *request; tmp = Sprintf("mode=panel&cookie=%s&bmark=%s&url=%s&title=%s" #ifdef USE_M17N "&charset=%s" #endif , (Str_form_quote(localCookie()))->ptr, (Str_form_quote(Strnew_charp(BookmarkFile)))->ptr, (Str_form_quote(parsedURL2Str(&Currentbuf->currentURL)))-> ptr, #ifdef USE_M17N (Str_form_quote(wc_conv_strict(Currentbuf->buffername, InnerCharset, BookmarkCharset)))->ptr, wc_ces_to_charset(BookmarkCharset)); #else (Str_form_quote(Strnew_charp(Currentbuf->buffername)))->ptr); #endif request = newFormList(NULL, "post", NULL, NULL, NULL, NULL, NULL); request->body = tmp->ptr; request->length = tmp->length; cmd_loadURL("file:///$LIB/" W3MBOOKMARK_CMDNAME, NULL, NO_REFERER, request); } /* option setting */ DEFUN(ldOpt, OPTIONS, "Display options setting panel") { cmd_loadBuffer(load_option_panel(), BP_NO_URL, LB_NOLINK); } /* set an option */ DEFUN(setOpt, SET_OPTION, "Set option") { char *opt; CurrentKeyData = NULL; /* not allowed in w3m-control: */ opt = searchKeyData(); if (opt == NULL || *opt == '\0' || strchr(opt, '=') == NULL) { if (opt != NULL && *opt != '\0') { char *v = get_param_option(opt); opt = Sprintf("%s=%s", opt, v ? v : "")->ptr; } opt = inputStrHist("Set option: ", opt, TextHist); if (opt == NULL || *opt == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } } if (set_param_option(opt)) sync_with_option(); displayBuffer(Currentbuf, B_REDRAW_IMAGE); } /* error message list */ DEFUN(msgs, MSGS, "Display error messages") { cmd_loadBuffer(message_list_panel(), BP_NO_URL, LB_NOLINK); } /* page info */ DEFUN(pginfo, INFO, "Display information about the current document") { Buffer *buf; if ((buf = Currentbuf->linkBuffer[LB_N_INFO]) != NULL) { Currentbuf = buf; displayBuffer(Currentbuf, B_NORMAL); return; } if ((buf = Currentbuf->linkBuffer[LB_INFO]) != NULL) delBuffer(buf); buf = page_info_panel(Currentbuf); cmd_loadBuffer(buf, BP_NORMAL, LB_INFO); } void follow_map(struct parsed_tagarg *arg) { char *name = tag_get_value(arg, "link"); #if defined(MENU_MAP) || defined(USE_IMAGE) Anchor *an; MapArea *a; int x, y; ParsedURL p_url; an = retrieveCurrentImg(Currentbuf); x = Currentbuf->cursorX + Currentbuf->rootX; y = Currentbuf->cursorY + Currentbuf->rootY; a = follow_map_menu(Currentbuf, name, an, x, y); if (a == NULL || a->url == NULL || *(a->url) == '\0') { #endif #ifndef MENU_MAP Buffer *buf = follow_map_panel(Currentbuf, name); if (buf != NULL) cmd_loadBuffer(buf, BP_NORMAL, LB_NOLINK); #endif #if defined(MENU_MAP) || defined(USE_IMAGE) return; } if (*(a->url) == '#') { gotoLabel(a->url + 1); return; } parseURL2(a->url, &p_url, baseURL(Currentbuf)); pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr); if (check_target && open_tab_blank && a->target && (!strcasecmp(a->target, "_new") || !strcasecmp(a->target, "_blank"))) { Buffer *buf; _newT(); buf = Currentbuf; cmd_loadURL(a->url, baseURL(Currentbuf), parsedURL2Str(&Currentbuf->currentURL)->ptr, NULL); if (buf != Currentbuf) delBuffer(buf); else deleteTab(CurrentTab); displayBuffer(Currentbuf, B_FORCE_REDRAW); return; } cmd_loadURL(a->url, baseURL(Currentbuf), parsedURL2Str(&Currentbuf->currentURL)->ptr, NULL); #endif } #ifdef USE_MENU /* link menu */ DEFUN(linkMn, LINK_MENU, "Pop up link element menu") { LinkList *l = link_menu(Currentbuf); ParsedURL p_url; if (!l || !l->url) return; if (*(l->url) == '#') { gotoLabel(l->url + 1); return; } parseURL2(l->url, &p_url, baseURL(Currentbuf)); pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr); cmd_loadURL(l->url, baseURL(Currentbuf), parsedURL2Str(&Currentbuf->currentURL)->ptr, NULL); } static void anchorMn(Anchor *(*menu_func) (Buffer *), int go) { Anchor *a; BufferPoint *po; if (!Currentbuf->href || !Currentbuf->hmarklist) return; a = menu_func(Currentbuf); if (!a || a->hseq < 0) return; po = &Currentbuf->hmarklist->marks[a->hseq]; gotoLine(Currentbuf, po->line); Currentbuf->pos = po->pos; arrangeCursor(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); if (go) followA(); } /* accesskey */ DEFUN(accessKey, ACCESSKEY, "Pop up accesskey menu") { anchorMn(accesskey_menu, TRUE); } /* list menu */ DEFUN(listMn, LIST_MENU, "Pop up menu for hyperlinks to browse to") { anchorMn(list_menu, TRUE); } DEFUN(movlistMn, MOVE_LIST_MENU, "Pop up menu to navigate between hyperlinks") { anchorMn(list_menu, FALSE); } #endif /* link,anchor,image list */ DEFUN(linkLst, LIST, "Show all URLs referenced") { Buffer *buf; buf = link_list_panel(Currentbuf); if (buf != NULL) { #ifdef USE_M17N buf->document_charset = Currentbuf->document_charset; #endif cmd_loadBuffer(buf, BP_NORMAL, LB_NOLINK); } } #ifdef USE_COOKIE /* cookie list */ DEFUN(cooLst, COOKIE, "View cookie list") { Buffer *buf; buf = cookie_list_panel(); if (buf != NULL) cmd_loadBuffer(buf, BP_NO_URL, LB_NOLINK); } #endif /* USE_COOKIE */ #ifdef USE_HISTORY /* History page */ DEFUN(ldHist, HISTORY, "Show browsing history") { cmd_loadBuffer(historyBuffer(URLHist), BP_NO_URL, LB_NOLINK); } #endif /* USE_HISTORY */ /* download HREF link */ DEFUN(svA, SAVE_LINK, "Save hyperlink target") { CurrentKeyData = NULL; /* not allowed in w3m-control: */ do_download = TRUE; followA(); do_download = FALSE; } /* download IMG link */ DEFUN(svI, SAVE_IMAGE, "Save inline image") { CurrentKeyData = NULL; /* not allowed in w3m-control: */ do_download = TRUE; followI(); do_download = FALSE; } /* save buffer */ DEFUN(svBuf, PRINT SAVE_SCREEN, "Save rendered document") { char *qfile = NULL, *file; FILE *f; int is_pipe; CurrentKeyData = NULL; /* not allowed in w3m-control: */ file = searchKeyData(); if (file == NULL || *file == '\0') { /* FIXME: gettextize? */ qfile = inputLineHist("Save buffer to: ", NULL, IN_COMMAND, SaveHist); if (qfile == NULL || *qfile == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } } file = conv_to_system(qfile ? qfile : file); if (*file == '|') { is_pipe = TRUE; f = popen(file + 1, "w"); } else { if (qfile) { file = unescape_spaces(Strnew_charp(qfile))->ptr; file = conv_to_system(file); } file = expandPath(file); if (checkOverWrite(file) < 0) { displayBuffer(Currentbuf, B_NORMAL); return; } f = fopen(file, "w"); is_pipe = FALSE; } if (f == NULL) { /* FIXME: gettextize? */ char *emsg = Sprintf("Can't open %s", conv_from_system(file))->ptr; disp_err_message(emsg, TRUE); return; } saveBuffer(Currentbuf, f, TRUE); if (is_pipe) pclose(f); else fclose(f); displayBuffer(Currentbuf, B_NORMAL); } /* save source */ DEFUN(svSrc, DOWNLOAD SAVE, "Save document source") { char *file; if (Currentbuf->sourcefile == NULL) return; CurrentKeyData = NULL; /* not allowed in w3m-control: */ PermitSaveToPipe = TRUE; if (Currentbuf->real_scheme == SCM_LOCAL) file = conv_from_system(guess_save_name(NULL, Currentbuf->currentURL. real_file)); else file = guess_save_name(Currentbuf, Currentbuf->currentURL.file); doFileCopy(Currentbuf->sourcefile, file); PermitSaveToPipe = FALSE; displayBuffer(Currentbuf, B_NORMAL); } static void _peekURL(int only_img) { Anchor *a; ParsedURL pu; static Str s = NULL; #ifdef USE_M17N static Lineprop *p = NULL; Lineprop *pp; #endif static int offset = 0, n; if (Currentbuf->firstLine == NULL) return; if (CurrentKey == prev_key && s != NULL) { if (s->length - offset >= COLS) offset++; else if (s->length <= offset) /* bug ? */ offset = 0; goto disp; } else { offset = 0; } s = NULL; a = (only_img ? NULL : retrieveCurrentAnchor(Currentbuf)); if (a == NULL) { a = (only_img ? NULL : retrieveCurrentForm(Currentbuf)); if (a == NULL) { a = retrieveCurrentImg(Currentbuf); if (a == NULL) return; } else s = Strnew_charp(form2str((FormItemList *)a->url)); } if (s == NULL) { parseURL2(a->url, &pu, baseURL(Currentbuf)); s = parsedURL2Str(&pu); } if (DecodeURL) s = Strnew_charp(url_decode2(s->ptr, Currentbuf)); #ifdef USE_M17N s = checkType(s, &pp, NULL); p = NewAtom_N(Lineprop, s->length); bcopy((void *)pp, (void *)p, s->length * sizeof(Lineprop)); #endif disp: n = searchKeyNum(); if (n > 1 && s->length > (n - 1) * (COLS - 1)) offset = (n - 1) * (COLS - 1); #ifdef USE_M17N while (offset < s->length && p[offset] & PC_WCHAR2) offset++; #endif disp_message_nomouse(&s->ptr[offset], TRUE); } /* peek URL */ DEFUN(peekURL, PEEK_LINK, "Show target address") { _peekURL(0); } /* peek URL of image */ DEFUN(peekIMG, PEEK_IMG, "Show image address") { _peekURL(1); } /* show current URL */ static Str currentURL(void) { if (Currentbuf->bufferprop & BP_INTERNAL) return Strnew_size(0); return parsedURL2Str(&Currentbuf->currentURL); } DEFUN(curURL, PEEK, "Show current address") { static Str s = NULL; #ifdef USE_M17N static Lineprop *p = NULL; Lineprop *pp; #endif static int offset = 0, n; if (Currentbuf->bufferprop & BP_INTERNAL) return; if (CurrentKey == prev_key && s != NULL) { if (s->length - offset >= COLS) offset++; else if (s->length <= offset) /* bug ? */ offset = 0; } else { offset = 0; s = currentURL(); if (DecodeURL) s = Strnew_charp(url_decode2(s->ptr, NULL)); #ifdef USE_M17N s = checkType(s, &pp, NULL); p = NewAtom_N(Lineprop, s->length); bcopy((void *)pp, (void *)p, s->length * sizeof(Lineprop)); #endif } n = searchKeyNum(); if (n > 1 && s->length > (n - 1) * (COLS - 1)) offset = (n - 1) * (COLS - 1); #ifdef USE_M17N while (offset < s->length && p[offset] & PC_WCHAR2) offset++; #endif disp_message_nomouse(&s->ptr[offset], TRUE); } /* view HTML source */ DEFUN(vwSrc, SOURCE VIEW, "Toggle between HTML shown or processed") { Buffer *buf; if (Currentbuf->type == NULL || Currentbuf->bufferprop & BP_FRAME) return; if ((buf = Currentbuf->linkBuffer[LB_SOURCE]) != NULL || (buf = Currentbuf->linkBuffer[LB_N_SOURCE]) != NULL) { Currentbuf = buf; displayBuffer(Currentbuf, B_NORMAL); return; } if (Currentbuf->sourcefile == NULL) { if (Currentbuf->pagerSource && !strcasecmp(Currentbuf->type, "text/plain")) { #ifdef USE_M17N wc_ces old_charset; wc_bool old_fix_width_conv; #endif FILE *f; Str tmpf = tmpfname(TMPF_SRC, NULL); f = fopen(tmpf->ptr, "w"); if (f == NULL) return; #ifdef USE_M17N old_charset = DisplayCharset; old_fix_width_conv = WcOption.fix_width_conv; DisplayCharset = (Currentbuf->document_charset != WC_CES_US_ASCII) ? Currentbuf->document_charset : 0; WcOption.fix_width_conv = WC_FALSE; #endif saveBufferBody(Currentbuf, f, TRUE); #ifdef USE_M17N DisplayCharset = old_charset; WcOption.fix_width_conv = old_fix_width_conv; #endif fclose(f); Currentbuf->sourcefile = tmpf->ptr; } else { return; } } buf = newBuffer(INIT_BUFFER_WIDTH); if (is_html_type(Currentbuf->type)) { buf->type = "text/plain"; if (Currentbuf->real_type && is_html_type(Currentbuf->real_type)) buf->real_type = "text/plain"; else buf->real_type = Currentbuf->real_type; buf->buffername = Sprintf("source of %s", Currentbuf->buffername)->ptr; buf->linkBuffer[LB_N_SOURCE] = Currentbuf; Currentbuf->linkBuffer[LB_SOURCE] = buf; } else if (!strcasecmp(Currentbuf->type, "text/plain")) { buf->type = "text/html"; if (Currentbuf->real_type && !strcasecmp(Currentbuf->real_type, "text/plain")) buf->real_type = "text/html"; else buf->real_type = Currentbuf->real_type; buf->buffername = Sprintf("HTML view of %s", Currentbuf->buffername)->ptr; buf->linkBuffer[LB_SOURCE] = Currentbuf; Currentbuf->linkBuffer[LB_N_SOURCE] = buf; } else { return; } buf->currentURL = Currentbuf->currentURL; buf->real_scheme = Currentbuf->real_scheme; buf->filename = Currentbuf->filename; buf->sourcefile = Currentbuf->sourcefile; buf->header_source = Currentbuf->header_source; buf->search_header = Currentbuf->search_header; #ifdef USE_M17N buf->document_charset = Currentbuf->document_charset; #endif buf->clone = Currentbuf->clone; (*buf->clone)++; buf->need_reshape = TRUE; reshapeBuffer(buf); pushBuffer(buf); displayBuffer(Currentbuf, B_NORMAL); } /* reload */ DEFUN(reload, RELOAD, "Load current document anew") { Buffer *buf, *fbuf = NULL, sbuf; #ifdef USE_M17N wc_ces old_charset; #endif Str url; FormList *request; int multipart; if (Currentbuf->bufferprop & BP_INTERNAL) { if (!strcmp(Currentbuf->buffername, DOWNLOAD_LIST_TITLE)) { ldDL(); return; } /* FIXME: gettextize? */ disp_err_message("Can't reload...", TRUE); return; } if (Currentbuf->currentURL.scheme == SCM_LOCAL && !strcmp(Currentbuf->currentURL.file, "-")) { /* file is std input */ /* FIXME: gettextize? */ disp_err_message("Can't reload stdin", TRUE); return; } copyBuffer(&sbuf, Currentbuf); if (Currentbuf->bufferprop & BP_FRAME && (fbuf = Currentbuf->linkBuffer[LB_N_FRAME])) { if (fmInitialized) { message("Rendering frame", 0, 0); refresh(); } if (!(buf = renderFrame(fbuf, 1))) { displayBuffer(Currentbuf, B_NORMAL); return; } if (fbuf->linkBuffer[LB_FRAME]) { if (buf->sourcefile && fbuf->linkBuffer[LB_FRAME]->sourcefile && !strcmp(buf->sourcefile, fbuf->linkBuffer[LB_FRAME]->sourcefile)) fbuf->linkBuffer[LB_FRAME]->sourcefile = NULL; delBuffer(fbuf->linkBuffer[LB_FRAME]); } fbuf->linkBuffer[LB_FRAME] = buf; buf->linkBuffer[LB_N_FRAME] = fbuf; pushBuffer(buf); Currentbuf = buf; if (Currentbuf->firstLine) { COPY_BUFROOT(Currentbuf, &sbuf); restorePosition(Currentbuf, &sbuf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); return; } else if (Currentbuf->frameset != NULL) fbuf = Currentbuf->linkBuffer[LB_FRAME]; multipart = 0; if (Currentbuf->form_submit) { request = Currentbuf->form_submit->parent; if (request->method == FORM_METHOD_POST && request->enctype == FORM_ENCTYPE_MULTIPART) { Str query; struct stat st; multipart = 1; query_from_followform(&query, Currentbuf->form_submit, multipart); stat(request->body, &st); request->length = st.st_size; } } else { request = NULL; } url = parsedURL2Str(&Currentbuf->currentURL); /* FIXME: gettextize? */ message("Reloading...", 0, 0); refresh(); #ifdef USE_M17N old_charset = DocumentCharset; if (Currentbuf->document_charset != WC_CES_US_ASCII) DocumentCharset = Currentbuf->document_charset; #endif SearchHeader = Currentbuf->search_header; DefaultType = Currentbuf->real_type; buf = loadGeneralFile(url->ptr, NULL, NO_REFERER, RG_NOCACHE, request); #ifdef USE_M17N DocumentCharset = old_charset; #endif SearchHeader = FALSE; DefaultType = NULL; if (multipart) unlink(request->body); if (buf == NULL) { /* FIXME: gettextize? */ disp_err_message("Can't reload...", TRUE); return; } else if (buf == NO_BUFFER) { displayBuffer(Currentbuf, B_NORMAL); return; } if (fbuf != NULL) Firstbuf = deleteBuffer(Firstbuf, fbuf); repBuffer(Currentbuf, buf); if ((buf->type != NULL) && (sbuf.type != NULL) && ((!strcasecmp(buf->type, "text/plain") && is_html_type(sbuf.type)) || (is_html_type(buf->type) && !strcasecmp(sbuf.type, "text/plain")))) { vwSrc(); if (Currentbuf != buf) Firstbuf = deleteBuffer(Firstbuf, buf); } Currentbuf->search_header = sbuf.search_header; Currentbuf->form_submit = sbuf.form_submit; if (Currentbuf->firstLine) { COPY_BUFROOT(Currentbuf, &sbuf); restorePosition(Currentbuf, &sbuf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* reshape */ DEFUN(reshape, RESHAPE, "Re-render document") { Currentbuf->need_reshape = TRUE; reshapeBuffer(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); } #ifdef USE_M17N static void _docCSet(wc_ces charset) { if (Currentbuf->bufferprop & BP_INTERNAL) return; if (Currentbuf->sourcefile == NULL) { disp_message("Can't reload...", FALSE); return; } Currentbuf->document_charset = charset; Currentbuf->need_reshape = TRUE; displayBuffer(Currentbuf, B_FORCE_REDRAW); } void change_charset(struct parsed_tagarg *arg) { Buffer *buf = Currentbuf->linkBuffer[LB_N_INFO]; wc_ces charset; if (buf == NULL) return; delBuffer(Currentbuf); Currentbuf = buf; if (Currentbuf->bufferprop & BP_INTERNAL) return; charset = Currentbuf->document_charset; for (; arg; arg = arg->next) { if (!strcmp(arg->arg, "charset")) charset = atoi(arg->value); } _docCSet(charset); } DEFUN(docCSet, CHARSET, "Change the character encoding for the current document") { char *cs; wc_ces charset; cs = searchKeyData(); if (cs == NULL || *cs == '\0') /* FIXME: gettextize? */ cs = inputStr("Document charset: ", wc_ces_to_charset(Currentbuf->document_charset)); charset = wc_guess_charset_short(cs, 0); if (charset == 0) { displayBuffer(Currentbuf, B_NORMAL); return; } _docCSet(charset); } DEFUN(defCSet, DEFAULT_CHARSET, "Change the default character encoding") { char *cs; wc_ces charset; cs = searchKeyData(); if (cs == NULL || *cs == '\0') /* FIXME: gettextize? */ cs = inputStr("Default document charset: ", wc_ces_to_charset(DocumentCharset)); charset = wc_guess_charset_short(cs, 0); if (charset != 0) DocumentCharset = charset; displayBuffer(Currentbuf, B_NORMAL); } #endif /* mark URL-like patterns as anchors */ void chkURLBuffer(Buffer *buf) { static char *url_like_pat[] = { "https?://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./?=~_\\&+@#,\\$;]*[a-zA-Z0-9_/=\\-]", "file:/[a-zA-Z0-9:%\\-\\./=_\\+@#,\\$;]*", #ifdef USE_GOPHER "gopher://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./_]*", #endif /* USE_GOPHER */ "ftp://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./=_+@#,\\$]*[a-zA-Z0-9_/]", #ifdef USE_NNTP "news:[^<> ][^<> ]*", "nntp://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./_]*", #endif /* USE_NNTP */ #ifndef USE_W3MMAILER /* see also chkExternalURIBuffer() */ "mailto:[^<> ][^<> ]*@[a-zA-Z0-9][a-zA-Z0-9\\-\\._]*[a-zA-Z0-9]", #endif #ifdef INET6 "https?://[a-zA-Z0-9:%\\-\\./_@]*\\[[a-fA-F0-9:][a-fA-F0-9:\\.]*\\][a-zA-Z0-9:%\\-\\./?=~_\\&+@#,\\$;]*", "ftp://[a-zA-Z0-9:%\\-\\./_@]*\\[[a-fA-F0-9:][a-fA-F0-9:\\.]*\\][a-zA-Z0-9:%\\-\\./=_+@#,\\$]*", #endif /* INET6 */ NULL }; int i; for (i = 0; url_like_pat[i]; i++) { reAnchor(buf, url_like_pat[i]); } #ifdef USE_EXTERNAL_URI_LOADER chkExternalURIBuffer(buf); #endif buf->check_url |= CHK_URL; } DEFUN(chkURL, MARK_URL, "Turn URL-like strings into hyperlinks") { chkURLBuffer(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(chkWORD, MARK_WORD, "Turn current word into hyperlink") { char *p; int spos, epos; p = getCurWord(Currentbuf, &spos, &epos); if (p == NULL) return; reAnchorWord(Currentbuf, Currentbuf->currentLine, spos, epos); displayBuffer(Currentbuf, B_FORCE_REDRAW); } #ifdef USE_NNTP /* mark Message-ID-like patterns as NEWS anchors */ void chkNMIDBuffer(Buffer *buf) { static char *url_like_pat[] = { "<[!-;=?-~]+@[a-zA-Z0-9\\.\\-_]+>", NULL, }; int i; for (i = 0; url_like_pat[i]; i++) { reAnchorNews(buf, url_like_pat[i]); } buf->check_url |= CHK_NMID; } DEFUN(chkNMID, MARK_MID, "Turn Message-ID-like strings into hyperlinks") { chkNMIDBuffer(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); } #endif /* USE_NNTP */ /* render frames */ DEFUN(rFrame, FRAME, "Toggle rendering HTML frames") { Buffer *buf; if ((buf = Currentbuf->linkBuffer[LB_FRAME]) != NULL) { Currentbuf = buf; displayBuffer(Currentbuf, B_NORMAL); return; } if (Currentbuf->frameset == NULL) { if ((buf = Currentbuf->linkBuffer[LB_N_FRAME]) != NULL) { Currentbuf = buf; displayBuffer(Currentbuf, B_NORMAL); } return; } if (fmInitialized) { message("Rendering frame", 0, 0); refresh(); } buf = renderFrame(Currentbuf, 0); if (buf == NULL) { displayBuffer(Currentbuf, B_NORMAL); return; } buf->linkBuffer[LB_N_FRAME] = Currentbuf; Currentbuf->linkBuffer[LB_FRAME] = buf; pushBuffer(buf); if (fmInitialized && display_ok) displayBuffer(Currentbuf, B_FORCE_REDRAW); } /* spawn external browser */ static void invoke_browser(char *url) { Str cmd; char *browser = NULL; int bg = 0, len; CurrentKeyData = NULL; /* not allowed in w3m-control: */ browser = searchKeyData(); if (browser == NULL || *browser == '\0') { switch (prec_num) { case 0: case 1: browser = ExtBrowser; break; case 2: browser = ExtBrowser2; break; case 3: browser = ExtBrowser3; break; case 4: browser = ExtBrowser4; break; case 5: browser = ExtBrowser5; break; case 6: browser = ExtBrowser6; break; case 7: browser = ExtBrowser7; break; case 8: browser = ExtBrowser8; break; case 9: browser = ExtBrowser9; break; } if (browser == NULL || *browser == '\0') { browser = inputStr("Browse command: ", NULL); if (browser != NULL) browser = conv_to_system(browser); } } else { browser = conv_to_system(browser); } if (browser == NULL || *browser == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } if ((len = strlen(browser)) >= 2 && browser[len - 1] == '&' && browser[len - 2] != '\\') { browser = allocStr(browser, len - 2); bg = 1; } cmd = myExtCommand(browser, shell_quote(url), FALSE); Strremovetrailingspaces(cmd); fmTerm(); mySystem(cmd->ptr, bg); fmInit(); displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(extbrz, EXTERN, "Display using an external browser") { if (Currentbuf->bufferprop & BP_INTERNAL) { /* FIXME: gettextize? */ disp_err_message("Can't browse...", TRUE); return; } if (Currentbuf->currentURL.scheme == SCM_LOCAL && !strcmp(Currentbuf->currentURL.file, "-")) { /* file is std input */ /* FIXME: gettextize? */ disp_err_message("Can't browse stdin", TRUE); return; } invoke_browser(parsedURL2Str(&Currentbuf->currentURL)->ptr); } DEFUN(linkbrz, EXTERN_LINK, "Display target using an external browser") { Anchor *a; ParsedURL pu; if (Currentbuf->firstLine == NULL) return; a = retrieveCurrentAnchor(Currentbuf); if (a == NULL) return; parseURL2(a->url, &pu, baseURL(Currentbuf)); invoke_browser(parsedURL2Str(&pu)->ptr); } /* show current line number and number of lines in the entire document */ DEFUN(curlno, LINE_INFO, "Display current position in document") { Line *l = Currentbuf->currentLine; Str tmp; int cur = 0, all = 0, col = 0, len = 0; if (l != NULL) { cur = l->real_linenumber; col = l->bwidth + Currentbuf->currentColumn + Currentbuf->cursorX + 1; while (l->next && l->next->bpos) l = l->next; if (l->width < 0) l->width = COLPOS(l, l->len); len = l->bwidth + l->width; } if (Currentbuf->lastLine) all = Currentbuf->lastLine->real_linenumber; if (Currentbuf->pagerSource && !(Currentbuf->bufferprop & BP_CLOSE)) tmp = Sprintf("line %d col %d/%d", cur, col, len); else tmp = Sprintf("line %d/%d (%d%%) col %d/%d", cur, all, (int)((double)cur * 100.0 / (double)(all ? all : 1) + 0.5), col, len); #ifdef USE_M17N Strcat_charp(tmp, " "); Strcat_charp(tmp, wc_ces_to_charset_desc(Currentbuf->document_charset)); #endif disp_message(tmp->ptr, FALSE); } #ifdef USE_IMAGE DEFUN(dispI, DISPLAY_IMAGE, "Restart loading and drawing of images") { if (!displayImage) initImage(); if (!activeImage) return; displayImage = TRUE; /* * if (!(Currentbuf->type && is_html_type(Currentbuf->type))) * return; */ Currentbuf->image_flag = IMG_FLAG_AUTO; Currentbuf->need_reshape = TRUE; displayBuffer(Currentbuf, B_REDRAW_IMAGE); } DEFUN(stopI, STOP_IMAGE, "Stop loading and drawing of images") { if (!activeImage) return; /* * if (!(Currentbuf->type && is_html_type(Currentbuf->type))) * return; */ Currentbuf->image_flag = IMG_FLAG_SKIP; displayBuffer(Currentbuf, B_REDRAW_IMAGE); } #endif #ifdef USE_MOUSE static int mouse_scroll_line(void) { if (relative_wheel_scroll) return (relative_wheel_scroll_ratio * LASTLINE + 99) / 100; else return fixed_wheel_scroll_count; } static TabBuffer * posTab(int x, int y) { TabBuffer *tab; if (mouse_action.menu_str && x < mouse_action.menu_width && y == 0) return NO_TABBUFFER; if (y > LastTab->y) return NULL; for (tab = FirstTab; tab; tab = tab->nextTab) { if (tab->x1 <= x && x <= tab->x2 && tab->y == y) return tab; } return NULL; } static void do_mouse_action(int btn, int x, int y) { MouseActionMap *map = NULL; int ny = -1; if (nTab > 1 || mouse_action.menu_str) ny = LastTab->y + 1; switch (btn) { case MOUSE_BTN1_DOWN: btn = 0; break; case MOUSE_BTN2_DOWN: btn = 1; break; case MOUSE_BTN3_DOWN: btn = 2; break; default: return; } if (y < ny) { if (mouse_action.menu_str && x >= 0 && x < mouse_action.menu_width) { if (mouse_action.menu_map[btn]) map = &mouse_action.menu_map[btn][x]; } else map = &mouse_action.tab_map[btn]; } else if (y == LASTLINE) { if (mouse_action.lastline_str && x >= 0 && x < mouse_action.lastline_width) { if (mouse_action.lastline_map[btn]) map = &mouse_action.lastline_map[btn][x]; } } else if (y > ny) { if (y == Currentbuf->cursorY + Currentbuf->rootY && (x == Currentbuf->cursorX + Currentbuf->rootX #ifdef USE_M17N || (WcOption.use_wide && Currentbuf->currentLine != NULL && (CharType(Currentbuf->currentLine->propBuf[Currentbuf->pos]) == PC_KANJI1) && x == Currentbuf->cursorX + Currentbuf->rootX + 1) #endif )) { if (retrieveCurrentAnchor(Currentbuf) || retrieveCurrentForm(Currentbuf)) { map = &mouse_action.active_map[btn]; if (!(map && map->func)) map = &mouse_action.anchor_map[btn]; } } else { int cx = Currentbuf->cursorX, cy = Currentbuf->cursorY; cursorXY(Currentbuf, x - Currentbuf->rootX, y - Currentbuf->rootY); if (y == Currentbuf->cursorY + Currentbuf->rootY && (x == Currentbuf->cursorX + Currentbuf->rootX #ifdef USE_M17N || (WcOption.use_wide && Currentbuf->currentLine != NULL && (CharType(Currentbuf->currentLine-> propBuf[Currentbuf->pos]) == PC_KANJI1) && x == Currentbuf->cursorX + Currentbuf->rootX + 1) #endif ) && (retrieveCurrentAnchor(Currentbuf) || retrieveCurrentForm(Currentbuf))) map = &mouse_action.anchor_map[btn]; cursorXY(Currentbuf, cx, cy); } } else { return; } if (!(map && map->func)) map = &mouse_action.default_map[btn]; if (map && map->func) { mouse_action.in_action = TRUE; mouse_action.cursorX = x; mouse_action.cursorY = y; CurrentKey = -1; CurrentKeyData = NULL; CurrentCmdData = map->data; (*map->func) (); CurrentCmdData = NULL; } } static void process_mouse(int btn, int x, int y) { int delta_x, delta_y, i; static int press_btn = MOUSE_BTN_RESET, press_x, press_y; TabBuffer *t; int ny = -1; if (nTab > 1 || mouse_action.menu_str) ny = LastTab->y + 1; if (btn == MOUSE_BTN_UP) { switch (press_btn) { case MOUSE_BTN1_DOWN: if (press_y == y && press_x == x) do_mouse_action(press_btn, x, y); else if (ny > 0 && y < ny) { if (press_y < ny) { moveTab(posTab(press_x, press_y), posTab(x, y), (press_y == y) ? (press_x < x) : (press_y < y)); return; } else if (press_x >= Currentbuf->rootX) { Buffer *buf = Currentbuf; int cx = Currentbuf->cursorX, cy = Currentbuf->cursorY; t = posTab(x, y); if (t == NULL) return; if (t == NO_TABBUFFER) t = NULL; /* open new tab */ cursorXY(Currentbuf, press_x - Currentbuf->rootX, press_y - Currentbuf->rootY); if (Currentbuf->cursorY == press_y - Currentbuf->rootY && (Currentbuf->cursorX == press_x - Currentbuf->rootX #ifdef USE_M17N || (WcOption.use_wide && Currentbuf->currentLine != NULL && (CharType(Currentbuf->currentLine-> propBuf[Currentbuf->pos]) == PC_KANJI1) && Currentbuf->cursorX == press_x - Currentbuf->rootX - 1) #endif )) { displayBuffer(Currentbuf, B_NORMAL); followTab(t); } if (buf == Currentbuf) cursorXY(Currentbuf, cx, cy); } return; } else { delta_x = x - press_x; delta_y = y - press_y; if (abs(delta_x) < abs(delta_y) / 3) delta_x = 0; if (abs(delta_y) < abs(delta_x) / 3) delta_y = 0; if (reverse_mouse) { delta_y = -delta_y; delta_x = -delta_x; } if (delta_y > 0) { prec_num = delta_y; ldown1(); } else if (delta_y < 0) { prec_num = -delta_y; lup1(); } if (delta_x > 0) { prec_num = delta_x; col1L(); } else if (delta_x < 0) { prec_num = -delta_x; col1R(); } } break; case MOUSE_BTN2_DOWN: case MOUSE_BTN3_DOWN: if (press_y == y && press_x == x) do_mouse_action(press_btn, x, y); break; case MOUSE_BTN4_DOWN_RXVT: for (i = 0; i < mouse_scroll_line(); i++) ldown1(); break; case MOUSE_BTN5_DOWN_RXVT: for (i = 0; i < mouse_scroll_line(); i++) lup1(); break; } } else if (btn == MOUSE_BTN4_DOWN_XTERM) { for (i = 0; i < mouse_scroll_line(); i++) ldown1(); } else if (btn == MOUSE_BTN5_DOWN_XTERM) { for (i = 0; i < mouse_scroll_line(); i++) lup1(); } if (btn != MOUSE_BTN4_DOWN_RXVT || press_btn == MOUSE_BTN_RESET) { press_btn = btn; press_x = x; press_y = y; } else { press_btn = MOUSE_BTN_RESET; } } DEFUN(msToggle, MOUSE_TOGGLE, "Toggle mouse support") { if (use_mouse) { use_mouse = FALSE; } else { use_mouse = TRUE; } displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(mouse, MOUSE, "mouse operation") { int btn, x, y; btn = (unsigned char)getch() - 32; #if defined(__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005 if (cygwin_mouse_btn_swapped) { if (btn == MOUSE_BTN2_DOWN) btn = MOUSE_BTN3_DOWN; else if (btn == MOUSE_BTN3_DOWN) btn = MOUSE_BTN2_DOWN; } #endif x = (unsigned char)getch() - 33; if (x < 0) x += 0x100; y = (unsigned char)getch() - 33; if (y < 0) y += 0x100; if (x < 0 || x >= COLS || y < 0 || y > LASTLINE) return; process_mouse(btn, x, y); } DEFUN(sgrmouse, SGRMOUSE, "SGR 1006 mouse operation") { int btn = 0, x = 0, y = 0; unsigned char c; do { c = getch(); if (IS_DIGIT(c)) btn = btn * 10 + c - '0'; else if (c == ';') break; else return; } while (1); #if defined(__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005 if (cygwin_mouse_btn_swapped) { if (btn == MOUSE_BTN2_DOWN) btn = MOUSE_BTN3_DOWN; else if (btn == MOUSE_BTN3_DOWN) btn = MOUSE_BTN2_DOWN; }; #endif do { c = getch(); if (IS_DIGIT(c)) x = x * 10 + c - '0'; else if (c == ';') break; else return; } while (1); if (x>0) x--; do { c = getch(); if (IS_DIGIT(c)) y = y * 10 + c - '0'; else if (c == 'M') break; else if (c == 'm') { btn |= 3; break; } else return; } while (1); if (y>0) y--; if (x < 0 || x >= COLS || y < 0 || y > LASTLINE) return; process_mouse(btn, x, y); } #ifdef USE_GPM int gpm_process_mouse(Gpm_Event * event, void *data) { int btn = MOUSE_BTN_RESET, x, y; if (event->type & GPM_UP) btn = MOUSE_BTN_UP; else if (event->type & GPM_DOWN) { switch (event->buttons) { case GPM_B_LEFT: btn = MOUSE_BTN1_DOWN; break; case GPM_B_MIDDLE: btn = MOUSE_BTN2_DOWN; break; case GPM_B_RIGHT: btn = MOUSE_BTN3_DOWN; break; } } else { GPM_DRAWPOINTER(event); return 0; } x = event->x; y = event->y; process_mouse(btn, x - 1, y - 1); return 0; } #endif /* USE_GPM */ #ifdef USE_SYSMOUSE int sysm_process_mouse(int x, int y, int nbs, int obs) { int btn; int bits; if (obs & ~nbs) btn = MOUSE_BTN_UP; else if (nbs & ~obs) { bits = nbs & ~obs; btn = bits & 0x1 ? MOUSE_BTN1_DOWN : (bits & 0x2 ? MOUSE_BTN2_DOWN : (bits & 0x4 ? MOUSE_BTN3_DOWN : 0)); } else /* nbs == obs */ return 0; process_mouse(btn, x, y); return 0; } #endif /* USE_SYSMOUSE */ DEFUN(movMs, MOVE_MOUSE, "Move cursor to mouse pointer") { if (!mouse_action.in_action) return; if ((nTab > 1 || mouse_action.menu_str) && mouse_action.cursorY < LastTab->y + 1) return; else if (mouse_action.cursorX >= Currentbuf->rootX && mouse_action.cursorY < LASTLINE) { cursorXY(Currentbuf, mouse_action.cursorX - Currentbuf->rootX, mouse_action.cursorY - Currentbuf->rootY); } displayBuffer(Currentbuf, B_NORMAL); } #ifdef USE_MENU #ifdef KANJI_SYMBOLS #define FRAME_WIDTH 2 #else #define FRAME_WIDTH 1 #endif DEFUN(menuMs, MENU_MOUSE, "Pop up menu at mouse pointer") { if (!mouse_action.in_action) return; if ((nTab > 1 || mouse_action.menu_str) && mouse_action.cursorY < LastTab->y + 1) mouse_action.cursorX -= FRAME_WIDTH + 1; else if (mouse_action.cursorX >= Currentbuf->rootX && mouse_action.cursorY < LASTLINE) { cursorXY(Currentbuf, mouse_action.cursorX - Currentbuf->rootX, mouse_action.cursorY - Currentbuf->rootY); displayBuffer(Currentbuf, B_NORMAL); } mainMn(); } #endif DEFUN(tabMs, TAB_MOUSE, "Select tab by mouse action") { TabBuffer *tab; if (!mouse_action.in_action) return; tab = posTab(mouse_action.cursorX, mouse_action.cursorY); if (!tab || tab == NO_TABBUFFER) return; CurrentTab = tab; displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(closeTMs, CLOSE_TAB_MOUSE, "Close tab at mouse pointer") { TabBuffer *tab; if (!mouse_action.in_action) return; tab = posTab(mouse_action.cursorX, mouse_action.cursorY); if (!tab || tab == NO_TABBUFFER) return; deleteTab(tab); displayBuffer(Currentbuf, B_FORCE_REDRAW); } #endif /* USE_MOUSE */ DEFUN(dispVer, VERSION, "Display the version of w3m") { disp_message(Sprintf("w3m version %s", w3m_version)->ptr, TRUE); } DEFUN(wrapToggle, WRAP_TOGGLE, "Toggle wrapping mode in searches") { if (WrapSearch) { WrapSearch = FALSE; /* FIXME: gettextize? */ disp_message("Wrap search off", TRUE); } else { WrapSearch = TRUE; /* FIXME: gettextize? */ disp_message("Wrap search on", TRUE); } } static char * getCurWord(Buffer *buf, int *spos, int *epos) { char *p; Line *l = buf->currentLine; int b, e; *spos = 0; *epos = 0; if (l == NULL) return NULL; p = l->lineBuf; e = buf->pos; while (e > 0 && !is_wordchar(getChar(&p[e]))) prevChar(e, l); if (!is_wordchar(getChar(&p[e]))) return NULL; b = e; while (b > 0) { int tmp = b; prevChar(tmp, l); if (!is_wordchar(getChar(&p[tmp]))) break; b = tmp; } while (e < l->len && is_wordchar(getChar(&p[e]))) nextChar(e, l); *spos = b; *epos = e; return &p[b]; } static char * GetWord(Buffer *buf) { int b, e; char *p; if ((p = getCurWord(buf, &b, &e)) != NULL) { return Strnew_charp_n(p, e - b)->ptr; } return NULL; } #ifdef USE_DICT static void execdict(char *word) { char *w, *dictcmd; Buffer *buf; if (!UseDictCommand || word == NULL || *word == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } w = conv_to_system(word); if (*w == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } dictcmd = Sprintf("%s?%s", DictCommand, Str_form_quote(Strnew_charp(w))->ptr)->ptr; buf = loadGeneralFile(dictcmd, NULL, NO_REFERER, 0, NULL); if (buf == NULL) { disp_message("Execution failed", TRUE); return; } else if (buf != NO_BUFFER) { buf->filename = w; buf->buffername = Sprintf("%s %s", DICTBUFFERNAME, word)->ptr; if (buf->type == NULL) buf->type = "text/plain"; pushBuffer(buf); } displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(dictword, DICT_WORD, "Execute dictionary command (see README.dict)") { execdict(inputStr("(dictionary)!", "")); } DEFUN(dictwordat, DICT_WORD_AT, "Execute dictionary command for word at cursor") { execdict(GetWord(Currentbuf)); } #endif /* USE_DICT */ void set_buffer_environ(Buffer *buf) { static Buffer *prev_buf = NULL; static Line *prev_line = NULL; static int prev_pos = -1; Line *l; if (buf == NULL) return; if (buf != prev_buf) { set_environ("W3M_SOURCEFILE", buf->sourcefile); set_environ("W3M_FILENAME", buf->filename); set_environ("W3M_TITLE", buf->buffername); set_environ("W3M_URL", parsedURL2Str(&buf->currentURL)->ptr); set_environ("W3M_TYPE", buf->real_type ? buf->real_type : "unknown"); #ifdef USE_M17N set_environ("W3M_CHARSET", wc_ces_to_charset(buf->document_charset)); #endif } l = buf->currentLine; if (l && (buf != prev_buf || l != prev_line || buf->pos != prev_pos)) { Anchor *a; ParsedURL pu; char *s = GetWord(buf); set_environ("W3M_CURRENT_WORD", s ? s : ""); a = retrieveCurrentAnchor(buf); if (a) { parseURL2(a->url, &pu, baseURL(buf)); set_environ("W3M_CURRENT_LINK", parsedURL2Str(&pu)->ptr); } else set_environ("W3M_CURRENT_LINK", ""); a = retrieveCurrentImg(buf); if (a) { parseURL2(a->url, &pu, baseURL(buf)); set_environ("W3M_CURRENT_IMG", parsedURL2Str(&pu)->ptr); } else set_environ("W3M_CURRENT_IMG", ""); a = retrieveCurrentForm(buf); if (a) set_environ("W3M_CURRENT_FORM", form2str((FormItemList *)a->url)); else set_environ("W3M_CURRENT_FORM", ""); set_environ("W3M_CURRENT_LINE", Sprintf("%ld", l->real_linenumber)->ptr); set_environ("W3M_CURRENT_COLUMN", Sprintf("%d", buf->currentColumn + buf->cursorX + 1)->ptr); } else if (!l) { set_environ("W3M_CURRENT_WORD", ""); set_environ("W3M_CURRENT_LINK", ""); set_environ("W3M_CURRENT_IMG", ""); set_environ("W3M_CURRENT_FORM", ""); set_environ("W3M_CURRENT_LINE", "0"); set_environ("W3M_CURRENT_COLUMN", "0"); } prev_buf = buf; prev_line = l; prev_pos = buf->pos; } char * searchKeyData(void) { char *data = NULL; if (CurrentKeyData != NULL && *CurrentKeyData != '\0') data = CurrentKeyData; else if (CurrentCmdData != NULL && *CurrentCmdData != '\0') data = CurrentCmdData; else if (CurrentKey >= 0) data = getKeyData(CurrentKey); CurrentKeyData = NULL; CurrentCmdData = NULL; if (data == NULL || *data == '\0') return NULL; return allocStr(data, -1); } static int searchKeyNum(void) { char *d; int n = 1; d = searchKeyData(); if (d != NULL) n = atoi(d); return n * PREC_NUM; } #ifdef __EMX__ #ifdef USE_M17N static char * getCodePage(void) { unsigned long CpList[8], CpSize; if (!getenv("WINDOWID") && !DosQueryCp(sizeof(CpList), CpList, &CpSize)) return Sprintf("CP%d", *CpList)->ptr; return NULL; } #endif #endif void deleteFiles() { Buffer *buf; char *f; for (CurrentTab = FirstTab; CurrentTab; CurrentTab = CurrentTab->nextTab) { while (Firstbuf && Firstbuf != NO_BUFFER) { buf = Firstbuf->nextBuffer; discardBuffer(Firstbuf); Firstbuf = buf; } } while ((f = popText(fileToDelete)) != NULL) { unlink(f); if (enable_inline_image == 2 && strcmp(f+strlen(f)-4, ".gif") == 0) { Str firstframe = Strnew_charp(f); Strcat_charp(firstframe, "-1"); unlink(firstframe->ptr); } } } void w3m_exit(int i) { #ifdef USE_MIGEMO init_migemo(); /* close pipe to migemo */ #endif stopDownload(); deleteFiles(); #ifdef USE_SSL free_ssl_ctx(); #endif disconnectFTP(); #ifdef USE_NNTP disconnectNews(); #endif #ifdef __MINGW32_VERSION WSACleanup(); #endif #ifdef HAVE_MKDTEMP if (no_rc_dir && tmp_dir != rc_dir) if (rmdir(tmp_dir) != 0) { fprintf(stderr, "Can't remove temporary directory (%s)!\n", tmp_dir); exit(1); } #endif exit(i); } DEFUN(execCmd, COMMAND, "Invoke w3m function(s)") { char *data, *p; int cmd; CurrentKeyData = NULL; /* not allowed in w3m-control: */ data = searchKeyData(); if (data == NULL || *data == '\0') { data = inputStrHist("command [; ...]: ", "", TextHist); if (data == NULL) { displayBuffer(Currentbuf, B_NORMAL); return; } } /* data: FUNC [DATA] [; FUNC [DATA] ...] */ while (*data) { SKIP_BLANKS(data); if (*data == ';') { data++; continue; } p = getWord(&data); cmd = getFuncList(p); if (cmd < 0) break; p = getQWord(&data); CurrentKey = -1; CurrentKeyData = NULL; CurrentCmdData = *p ? p : NULL; #ifdef USE_MOUSE if (use_mouse) mouse_inactive(); #endif w3mFuncList[cmd].func(); #ifdef USE_MOUSE if (use_mouse) mouse_active(); #endif CurrentCmdData = NULL; } displayBuffer(Currentbuf, B_NORMAL); } #ifdef USE_ALARM static MySignalHandler SigAlarm(SIGNAL_ARG) { char *data; if (CurrentAlarm->sec > 0) { CurrentKey = -1; CurrentKeyData = NULL; CurrentCmdData = data = (char *)CurrentAlarm->data; #ifdef USE_MOUSE if (use_mouse) mouse_inactive(); #endif w3mFuncList[CurrentAlarm->cmd].func(); #ifdef USE_MOUSE if (use_mouse) mouse_active(); #endif CurrentCmdData = NULL; if (CurrentAlarm->status == AL_IMPLICIT_ONCE) { CurrentAlarm->sec = 0; CurrentAlarm->status = AL_UNSET; } if (Currentbuf->event) { if (Currentbuf->event->status != AL_UNSET) CurrentAlarm = Currentbuf->event; else Currentbuf->event = NULL; } if (!Currentbuf->event) CurrentAlarm = &DefaultAlarm; if (CurrentAlarm->sec > 0) { mySignal(SIGALRM, SigAlarm); alarm(CurrentAlarm->sec); } } SIGNAL_RETURN; } DEFUN(setAlarm, ALARM, "Set alarm") { char *data; int sec = 0, cmd = -1; CurrentKeyData = NULL; /* not allowed in w3m-control: */ data = searchKeyData(); if (data == NULL || *data == '\0') { data = inputStrHist("(Alarm)sec command: ", "", TextHist); if (data == NULL) { displayBuffer(Currentbuf, B_NORMAL); return; } } if (*data != '\0') { sec = atoi(getWord(&data)); if (sec > 0) cmd = getFuncList(getWord(&data)); } if (cmd >= 0) { data = getQWord(&data); setAlarmEvent(&DefaultAlarm, sec, AL_EXPLICIT, cmd, data); disp_message_nsec(Sprintf("%dsec %s %s", sec, w3mFuncList[cmd].id, data)->ptr, FALSE, 1, FALSE, TRUE); } else { setAlarmEvent(&DefaultAlarm, 0, AL_UNSET, FUNCNAME_nulcmd, NULL); } displayBuffer(Currentbuf, B_NORMAL); } AlarmEvent * setAlarmEvent(AlarmEvent * event, int sec, short status, int cmd, void *data) { if (event == NULL) event = New(AlarmEvent); event->sec = sec; event->status = status; event->cmd = cmd; event->data = data; return event; } #endif DEFUN(reinit, REINIT, "Reload configuration file") { char *resource = searchKeyData(); if (resource == NULL) { init_rc(); sync_with_option(); #ifdef USE_COOKIE initCookie(); #endif displayBuffer(Currentbuf, B_REDRAW_IMAGE); return; } if (!strcasecmp(resource, "CONFIG") || !strcasecmp(resource, "RC")) { init_rc(); sync_with_option(); displayBuffer(Currentbuf, B_REDRAW_IMAGE); return; } #ifdef USE_COOKIE if (!strcasecmp(resource, "COOKIE")) { initCookie(); return; } #endif if (!strcasecmp(resource, "KEYMAP")) { initKeymap(TRUE); return; } if (!strcasecmp(resource, "MAILCAP")) { initMailcap(); return; } #ifdef USE_MOUSE if (!strcasecmp(resource, "MOUSE")) { initMouseAction(); displayBuffer(Currentbuf, B_REDRAW_IMAGE); return; } #endif #ifdef USE_MENU if (!strcasecmp(resource, "MENU")) { initMenu(); return; } #endif if (!strcasecmp(resource, "MIMETYPES")) { initMimeTypes(); return; } #ifdef USE_EXTERNAL_URI_LOADER if (!strcasecmp(resource, "URIMETHODS")) { initURIMethods(); return; } #endif disp_err_message(Sprintf("Don't know how to reinitialize '%s'", resource)-> ptr, FALSE); } DEFUN(defKey, DEFINE_KEY, "Define a binding between a key stroke combination and a command") { char *data; CurrentKeyData = NULL; /* not allowed in w3m-control: */ data = searchKeyData(); if (data == NULL || *data == '\0') { data = inputStrHist("Key definition: ", "", TextHist); if (data == NULL || *data == '\0') { displayBuffer(Currentbuf, B_NORMAL); return; } } setKeymap(allocStr(data, -1), -1, TRUE); displayBuffer(Currentbuf, B_NORMAL); } TabBuffer * newTab(void) { TabBuffer *n; n = New(TabBuffer); if (n == NULL) return NULL; n->nextTab = NULL; n->currentBuffer = NULL; n->firstBuffer = NULL; return n; } static void _newT(void) { TabBuffer *tag; Buffer *buf; int i; tag = newTab(); if (!tag) return; buf = newBuffer(Currentbuf->width); copyBuffer(buf, Currentbuf); buf->nextBuffer = NULL; for (i = 0; i < MAX_LB; i++) buf->linkBuffer[i] = NULL; (*buf->clone)++; tag->firstBuffer = tag->currentBuffer = buf; tag->nextTab = CurrentTab->nextTab; tag->prevTab = CurrentTab; if (CurrentTab->nextTab) CurrentTab->nextTab->prevTab = tag; else LastTab = tag; CurrentTab->nextTab = tag; CurrentTab = tag; nTab++; } DEFUN(newT, NEW_TAB, "Open a new tab (with current document)") { _newT(); displayBuffer(Currentbuf, B_REDRAW_IMAGE); } static TabBuffer * numTab(int n) { TabBuffer *tab; int i; if (n == 0) return CurrentTab; if (n == 1) return FirstTab; if (nTab <= 1) return NULL; for (tab = FirstTab, i = 1; tab && i < n; tab = tab->nextTab, i++) ; return tab; } void calcTabPos(void) { TabBuffer *tab; #if 0 int lcol = 0, rcol = 2, col; #else int lcol = 0, rcol = 0, col; #endif int n1, n2, na, nx, ny, ix, iy; #ifdef USE_MOUSE lcol = mouse_action.menu_str ? mouse_action.menu_width : 0; #endif if (nTab <= 0) return; n1 = (COLS - rcol - lcol) / TabCols; if (n1 >= nTab) { n2 = 1; ny = 1; } else { if (n1 < 0) n1 = 0; n2 = COLS / TabCols; if (n2 == 0) n2 = 1; ny = (nTab - n1 - 1) / n2 + 2; } na = n1 + n2 * (ny - 1); n1 -= (na - nTab) / ny; if (n1 < 0) n1 = 0; na = n1 + n2 * (ny - 1); tab = FirstTab; for (iy = 0; iy < ny && tab; iy++) { if (iy == 0) { nx = n1; col = COLS - rcol - lcol; } else { nx = n2 - (na - nTab + (iy - 1)) / (ny - 1); col = COLS; } for (ix = 0; ix < nx && tab; ix++, tab = tab->nextTab) { tab->x1 = col * ix / nx; tab->x2 = col * (ix + 1) / nx - 1; tab->y = iy; if (iy == 0) { tab->x1 += lcol; tab->x2 += lcol; } } } } TabBuffer * deleteTab(TabBuffer * tab) { Buffer *buf, *next; if (nTab <= 1) return FirstTab; if (tab->prevTab) { if (tab->nextTab) tab->nextTab->prevTab = tab->prevTab; else LastTab = tab->prevTab; tab->prevTab->nextTab = tab->nextTab; if (tab == CurrentTab) CurrentTab = tab->prevTab; } else { /* tab == FirstTab */ tab->nextTab->prevTab = NULL; FirstTab = tab->nextTab; if (tab == CurrentTab) CurrentTab = tab->nextTab; } nTab--; buf = tab->firstBuffer; while (buf && buf != NO_BUFFER) { next = buf->nextBuffer; discardBuffer(buf); buf = next; } return FirstTab; } DEFUN(closeT, CLOSE_TAB, "Close tab") { TabBuffer *tab; if (nTab <= 1) return; if (prec_num) tab = numTab(PREC_NUM); else tab = CurrentTab; if (tab) deleteTab(tab); displayBuffer(Currentbuf, B_REDRAW_IMAGE); } DEFUN(nextT, NEXT_TAB, "Switch to the next tab") { int i; if (nTab <= 1) return; for (i = 0; i < PREC_NUM; i++) { if (CurrentTab->nextTab) CurrentTab = CurrentTab->nextTab; else CurrentTab = FirstTab; } displayBuffer(Currentbuf, B_REDRAW_IMAGE); } DEFUN(prevT, PREV_TAB, "Switch to the previous tab") { int i; if (nTab <= 1) return; for (i = 0; i < PREC_NUM; i++) { if (CurrentTab->prevTab) CurrentTab = CurrentTab->prevTab; else CurrentTab = LastTab; } displayBuffer(Currentbuf, B_REDRAW_IMAGE); } static void followTab(TabBuffer * tab) { Buffer *buf; Anchor *a; #ifdef USE_IMAGE a = retrieveCurrentImg(Currentbuf); if (!(a && a->image && a->image->map)) #endif a = retrieveCurrentAnchor(Currentbuf); if (a == NULL) return; if (tab == CurrentTab) { check_target = FALSE; followA(); check_target = TRUE; return; } _newT(); buf = Currentbuf; check_target = FALSE; followA(); check_target = TRUE; if (tab == NULL) { if (buf != Currentbuf) delBuffer(buf); else deleteTab(CurrentTab); } else if (buf != Currentbuf) { /* buf <- p <- ... <- Currentbuf = c */ Buffer *c, *p; c = Currentbuf; p = prevBuffer(c, buf); p->nextBuffer = NULL; Firstbuf = buf; deleteTab(CurrentTab); CurrentTab = tab; for (buf = p; buf; buf = p) { p = prevBuffer(c, buf); pushBuffer(buf); } } displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(tabA, TAB_LINK, "Follow current hyperlink in a new tab") { followTab(prec_num ? numTab(PREC_NUM) : NULL); } static void tabURL0(TabBuffer * tab, char *prompt, int relative) { Buffer *buf; if (tab == CurrentTab) { goURL0(prompt, relative); return; } _newT(); buf = Currentbuf; goURL0(prompt, relative); if (tab == NULL) { if (buf != Currentbuf) delBuffer(buf); else deleteTab(CurrentTab); } else if (buf != Currentbuf) { /* buf <- p <- ... <- Currentbuf = c */ Buffer *c, *p; c = Currentbuf; p = prevBuffer(c, buf); p->nextBuffer = NULL; Firstbuf = buf; deleteTab(CurrentTab); CurrentTab = tab; for (buf = p; buf; buf = p) { p = prevBuffer(c, buf); pushBuffer(buf); } } displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(tabURL, TAB_GOTO, "Open specified document in a new tab") { tabURL0(prec_num ? numTab(PREC_NUM) : NULL, "Goto URL on new tab: ", FALSE); } DEFUN(tabrURL, TAB_GOTO_RELATIVE, "Open relative address in a new tab") { tabURL0(prec_num ? numTab(PREC_NUM) : NULL, "Goto relative URL on new tab: ", TRUE); } static void moveTab(TabBuffer * t, TabBuffer * t2, int right) { if (t2 == NO_TABBUFFER) t2 = FirstTab; if (!t || !t2 || t == t2 || t == NO_TABBUFFER) return; if (t->prevTab) { if (t->nextTab) t->nextTab->prevTab = t->prevTab; else LastTab = t->prevTab; t->prevTab->nextTab = t->nextTab; } else { t->nextTab->prevTab = NULL; FirstTab = t->nextTab; } if (right) { t->nextTab = t2->nextTab; t->prevTab = t2; if (t2->nextTab) t2->nextTab->prevTab = t; else LastTab = t; t2->nextTab = t; } else { t->prevTab = t2->prevTab; t->nextTab = t2; if (t2->prevTab) t2->prevTab->nextTab = t; else FirstTab = t; t2->prevTab = t; } displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(tabR, TAB_RIGHT, "Move right along the tab bar") { TabBuffer *tab; int i; for (tab = CurrentTab, i = 0; tab && i < PREC_NUM; tab = tab->nextTab, i++) ; moveTab(CurrentTab, tab ? tab : LastTab, TRUE); } DEFUN(tabL, TAB_LEFT, "Move left along the tab bar") { TabBuffer *tab; int i; for (tab = CurrentTab, i = 0; tab && i < PREC_NUM; tab = tab->prevTab, i++) ; moveTab(CurrentTab, tab ? tab : FirstTab, FALSE); } void addDownloadList(pid_t pid, char *url, char *save, char *lock, clen_t size) { DownloadList *d; d = New(DownloadList); d->pid = pid; d->url = url; if (save[0] != '/' && save[0] != '~') save = Strnew_m_charp(CurrentDir, "/", save, NULL)->ptr; d->save = expandPath(save); d->lock = lock; d->size = size; d->time = time(0); d->running = TRUE; d->err = 0; d->next = NULL; d->prev = LastDL; if (LastDL) LastDL->next = d; else FirstDL = d; LastDL = d; add_download_list = TRUE; } int checkDownloadList(void) { DownloadList *d; struct stat st; if (!FirstDL) return FALSE; for (d = FirstDL; d != NULL; d = d->next) { if (d->running && !lstat(d->lock, &st)) return TRUE; } return FALSE; } static char * convert_size3(clen_t size) { Str tmp = Strnew(); int n; do { n = size % 1000; size /= 1000; tmp = Sprintf(size ? ",%.3d%s" : "%d%s", n, tmp->ptr); } while (size); return tmp->ptr; } static Buffer * DownloadListBuffer(void) { DownloadList *d; Str src = NULL; struct stat st; time_t cur_time; int duration, rate, eta; size_t size; if (!FirstDL) return NULL; cur_time = time(0); /* FIXME: gettextize? */ src = Strnew_charp("" DOWNLOAD_LIST_TITLE "\n

" DOWNLOAD_LIST_TITLE "

\n" "

\n"); for (d = LastDL; d != NULL; d = d->prev) { if (lstat(d->lock, &st)) d->running = FALSE; Strcat_charp(src, "
\n");
	Strcat(src, Sprintf("%s\n  --> %s\n  ", html_quote(d->url),
			    html_quote(conv_from_system(d->save))));
	duration = cur_time - d->time;
	if (!stat(d->save, &st)) {
	    size = st.st_size;
	    if (!d->running) {
		if (!d->err)
		    d->size = size;
		duration = st.st_mtime - d->time;
	    }
	}
	else
	    size = 0;
	if (d->size) {
	    int i, l = COLS - 6;
	    if (size < d->size)
		i = 1.0 * l * size / d->size;
	    else
		i = l;
	    l -= i;
	    while (i-- > 0)
		Strcat_char(src, '#');
	    while (l-- > 0)
		Strcat_char(src, '_');
	    Strcat_char(src, '\n');
	}
	if ((d->running || d->err) && size < d->size)
	    Strcat(src, Sprintf("  %s / %s bytes (%d%%)",
				convert_size3(size), convert_size3(d->size),
				(int)(100.0 * size / d->size)));
	else
	    Strcat(src, Sprintf("  %s bytes loaded", convert_size3(size)));
	if (duration > 0) {
	    rate = size / duration;
	    Strcat(src, Sprintf("  %02d:%02d:%02d  rate %s/sec",
				duration / (60 * 60), (duration / 60) % 60,
				duration % 60, convert_size(rate, 1)));
	    if (d->running && size < d->size && rate) {
		eta = (d->size - size) / rate;
		Strcat(src, Sprintf("  eta %02d:%02d:%02d", eta / (60 * 60),
				    (eta / 60) % 60, eta % 60));
	    }
	}
	Strcat_char(src, '\n');
	if (!d->running) {
	    Strcat(src, Sprintf("",
				d->pid));
	    switch (d->err) {
	    case 0: if (size < d->size)
			Strcat_charp(src, " Download ended but probably not complete");
		    else
			Strcat_charp(src, " Download complete");
		    break;
	    case 1: Strcat_charp(src, " Error: could not open destination file");
		    break;
	    case 2: Strcat_charp(src, " Error: could not write to file (disk full)");
		    break;
	    default: Strcat_charp(src, " Error: unknown reason");
	    }
	}
	else
	    Strcat(src, Sprintf("",
				d->pid));
	Strcat_charp(src, "\n

\n"); } Strcat_charp(src, "
"); return loadHTMLString(src); } void download_action(struct parsed_tagarg *arg) { DownloadList *d; pid_t pid; for (; arg; arg = arg->next) { if (!strncmp(arg->arg, "stop", 4)) { pid = (pid_t) atoi(&arg->arg[4]); #ifndef __MINGW32_VERSION kill(pid, SIGKILL); #endif } else if (!strncmp(arg->arg, "ok", 2)) pid = (pid_t) atoi(&arg->arg[2]); else continue; for (d = FirstDL; d; d = d->next) { if (d->pid == pid) { unlink(d->lock); if (d->prev) d->prev->next = d->next; else FirstDL = d->next; if (d->next) d->next->prev = d->prev; else LastDL = d->prev; break; } } } ldDL(); } void stopDownload(void) { DownloadList *d; if (!FirstDL) return; for (d = FirstDL; d != NULL; d = d->next) { if (!d->running) continue; #ifndef __MINGW32_VERSION kill(d->pid, SIGKILL); #endif unlink(d->lock); } } /* download panel */ DEFUN(ldDL, DOWNLOAD_LIST, "Display downloads panel") { Buffer *buf; int replace = FALSE, new_tab = FALSE; #ifdef USE_ALARM int reload; #endif if (Currentbuf->bufferprop & BP_INTERNAL && !strcmp(Currentbuf->buffername, DOWNLOAD_LIST_TITLE)) replace = TRUE; if (!FirstDL) { if (replace) { if (Currentbuf == Firstbuf && Currentbuf->nextBuffer == NULL) { if (nTab > 1) deleteTab(CurrentTab); } else delBuffer(Currentbuf); displayBuffer(Currentbuf, B_FORCE_REDRAW); } return; } #ifdef USE_ALARM reload = checkDownloadList(); #endif buf = DownloadListBuffer(); if (!buf) { displayBuffer(Currentbuf, B_NORMAL); return; } buf->bufferprop |= (BP_INTERNAL | BP_NO_URL); if (replace) { COPY_BUFROOT(buf, Currentbuf); restorePosition(buf, Currentbuf); } if (!replace && open_tab_dl_list) { _newT(); new_tab = TRUE; } pushBuffer(buf); if (replace || new_tab) deletePrevBuf(); #ifdef USE_ALARM if (reload) Currentbuf->event = setAlarmEvent(Currentbuf->event, 1, AL_IMPLICIT, FUNCNAME_reload, NULL); #endif displayBuffer(Currentbuf, B_FORCE_REDRAW); } static void save_buffer_position(Buffer *buf) { BufferPos *b = buf->undo; if (!buf->firstLine) return; if (b && b->top_linenumber == TOP_LINENUMBER(buf) && b->cur_linenumber == CUR_LINENUMBER(buf) && b->currentColumn == buf->currentColumn && b->pos == buf->pos) return; b = New(BufferPos); b->top_linenumber = TOP_LINENUMBER(buf); b->cur_linenumber = CUR_LINENUMBER(buf); b->currentColumn = buf->currentColumn; b->pos = buf->pos; b->bpos = buf->currentLine ? buf->currentLine->bpos : 0; b->next = NULL; b->prev = buf->undo; if (buf->undo) buf->undo->next = b; buf->undo = b; } static void resetPos(BufferPos * b) { Buffer buf; Line top, cur; top.linenumber = b->top_linenumber; cur.linenumber = b->cur_linenumber; cur.bpos = b->bpos; buf.topLine = ⊤ buf.currentLine = &cur; buf.pos = b->pos; buf.currentColumn = b->currentColumn; restorePosition(Currentbuf, &buf); Currentbuf->undo = b; displayBuffer(Currentbuf, B_FORCE_REDRAW); } DEFUN(undoPos, UNDO, "Cancel the last cursor movement") { BufferPos *b = Currentbuf->undo; int i; if (!Currentbuf->firstLine) return; if (!b || !b->prev) return; for (i = 0; i < PREC_NUM && b->prev; i++, b = b->prev) ; resetPos(b); } DEFUN(redoPos, REDO, "Cancel the last undo") { BufferPos *b = Currentbuf->undo; int i; if (!Currentbuf->firstLine) return; if (!b || !b->next) return; for (i = 0; i < PREC_NUM && b->next; i++, b = b->next) ; resetPos(b); } DEFUN(cursorTop, CURSOR_TOP, "Move cursor to the top of the screen") { if (Currentbuf->firstLine == NULL) return; Currentbuf->currentLine = lineSkip(Currentbuf, Currentbuf->topLine, 0, FALSE); arrangeLine(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } DEFUN(cursorMiddle, CURSOR_MIDDLE, "Move cursor to the middle of the screen") { int offsety; if (Currentbuf->firstLine == NULL) return; offsety = (Currentbuf->LINES - 1) / 2; Currentbuf->currentLine = currentLineSkip(Currentbuf, Currentbuf->topLine, offsety, FALSE); arrangeLine(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); } DEFUN(cursorBottom, CURSOR_BOTTOM, "Move cursor to the bottom of the screen") { int offsety; if (Currentbuf->firstLine == NULL) return; offsety = Currentbuf->LINES - 1; Currentbuf->currentLine = currentLineSkip(Currentbuf, Currentbuf->topLine, offsety, FALSE); arrangeLine(Currentbuf); displayBuffer(Currentbuf, B_NORMAL); }