To: vim_dev@googlegroups.com Subject: Patch 8.1.2374 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.2374 Problem: Unused parts of libvterm are included. Solution: Delete the unused files. Files: Filelist, src/libvterm/bin/vterm-ctrl.c, src/libvterm/bin/unterm.c, src/libvterm/bin/vterm-dump.c *** ../vim-8.1.2373/Filelist 2019-11-29 20:26:09.179592194 +0100 --- Filelist 2019-12-01 15:28:39.346844011 +0100 *************** *** 285,293 **** src/libvterm/README \ src/libvterm/tbl2inc_c.pl \ src/libvterm/vterm.pc.in \ - src/libvterm/bin/unterm.c \ - src/libvterm/bin/vterm-ctrl.c \ - src/libvterm/bin/vterm-dump.c \ src/libvterm/doc/URLs \ src/libvterm/doc/seqs.txt \ src/libvterm/include/vterm.h \ --- 285,290 ---- *** ../vim-8.1.2373/src/libvterm/bin/vterm-ctrl.c 2019-08-18 20:41:10.692526067 +0200 --- src/libvterm/bin/vterm-ctrl.c 1970-01-01 01:00:00.000000000 +0100 *************** *** 1,366 **** - #define _XOPEN_SOURCE 500 // strdup - - #include - #include - #include - #define streq(a,b) (strcmp(a,b)==0) - #define TRUE 1 - #define FALSE 0 - - #include - - static char *getvalue(int *argip, int argc, char *argv[]) - { - if(*argip >= argc) { - fprintf(stderr, "Expected an option value\n"); - exit(1); - } - - return argv[(*argip)++]; - } - - static int getchoice(int *argip, int argc, char *argv[], const char *options[]) - { - const char *arg = getvalue(argip, argc, argv); - - int value = -1; - while(options[++value]) - if(streq(arg, options[value])) - return value; - - fprintf(stderr, "Unrecognised option value %s\n", arg); - exit(1); - } - - typedef enum { - OFF, - ON, - QUERY, - } BoolQuery; - - static BoolQuery getboolq(int *argip, int argc, char *argv[]) - { - const char *choices[] = {"off", "on", "query", NULL}; - return getchoice(argip, argc, argv, choices); - } - - static char *helptext[] = { - "reset", - "s8c1t [off|on]", - "keypad [app|num]", - "screen [off|on|query]", - "cursor [off|on|query]", - "curblink [off|on|query]", - "curshape [block|under|bar|query]", - "mouse [off|click|clickdrag|motion]", - "reportfocus [off|on|query]", - "altscreen [off|on|query]", - "bracketpaste [off|on|query]", - "icontitle [STR]", - "icon [STR]", - "title [STR]", - NULL - }; - - static int seticanon(int icanon, int echo) - { - struct termios termios; - int ret; - - tcgetattr(0, &termios); - - ret = (termios.c_lflag & ICANON); - - if(icanon) termios.c_lflag |= ICANON; - else termios.c_lflag &= ~ICANON; - - if(echo) termios.c_lflag |= ECHO; - else termios.c_lflag &= ~ECHO; - - tcsetattr(0, TCSANOW, &termios); - - return ret; - } - - static void await_c1(unsigned char c1) - { - unsigned char c; - - // await CSI - 8bit or 2byte 7bit form - int in_esc = FALSE; - while((c = getchar())) { - if(c == c1) - break; - if(in_esc && c == (char)(c1 - 0x40)) - break; - if(!in_esc && c == 0x1b) - in_esc = TRUE; - else - in_esc = FALSE; - } - } - - static char *read_csi() - { - unsigned char csi[32]; - int i = 0; - - await_c1(0x9B); // CSI - - // TODO: This really should be a more robust CSI parser - for(; i < sizeof(csi)-1; i++) { - int c = csi[i] = getchar(); - if(c >= 0x40 && c <= 0x7e) - break; - } - csi[++i] = 0; - - // TODO: returns longer than 32? - - return strdup((char *)csi); - } - - static char *read_dcs() - { - unsigned char dcs[32]; - int in_esc = FALSE; - int i; - - await_c1(0x90); - - for(i = 0; i < sizeof(dcs)-1; ) { - char c = getchar(); - if(c == 0x9c) // ST - break; - if(in_esc && c == 0x5c) - break; - if(!in_esc && c == 0x1b) - in_esc = TRUE; - else { - dcs[i++] = c; - in_esc = FALSE; - } - } - dcs[++i] = 0; - - return strdup((char *)dcs); - } - - static void usage(int exitcode) - { - char **p; - - fprintf(stderr, "Control a libvterm-based terminal\n" - "\n" - "Options:\n"); - - for(p = helptext; *p; p++) - fprintf(stderr, " %s\n", *p); - - exit(exitcode); - } - - static int query_dec_mode(int mode) - { - char *s = NULL; - - printf("\x1b[?%d$p", mode); - - do { - int reply_mode, reply_value; - char reply_cmd; - - if(s) - free(s); - s = read_csi(); - - // expect "?" mode ";" value "$y" - - // If the sscanf format string ends in a literal, we can't tell from - // its return value if it matches. Hence we'll %c the cmd and check it - // explicitly - if(sscanf(s, "?%d;%d$%c", &reply_mode, &reply_value, &reply_cmd) < 3) - continue; - if(reply_cmd != 'y') - continue; - - if(reply_mode != mode) - continue; - - free(s); - - if(reply_value == 1 || reply_value == 3) - return TRUE; - if(reply_value == 2 || reply_value == 4) - return FALSE; - - printf("Unrecognised reply to DECRQM: %d\n", reply_value); - return FALSE; - } while(1); - } - - static void do_dec_mode(int mode, BoolQuery val, const char *name) - { - switch(val) { - case OFF: - case ON: - printf("\x1b[?%d%c", mode, val == ON ? 'h' : 'l'); - break; - - case QUERY: - if(query_dec_mode(mode)) - printf("%s on\n", name); - else - printf("%s off\n", name); - break; - } - } - - static int query_rqss_numeric(char *cmd) - { - char *s = NULL; - - printf("\x1bP$q%s\x1b\\", cmd); - - do { - int num; - - if(s) - free(s); - s = read_dcs(); - - if(!s) - return -1; - if(strlen(s) < strlen(cmd)) - return -1; - if(strcmp(s + strlen(s) - strlen(cmd), cmd) != 0) { - printf("No match\n"); - continue; - } - - if(s[0] != '1' || s[1] != '$' || s[2] != 'r') - return -1; - - if(sscanf(s + 3, "%d", &num) != 1) - return -1; - - return num; - } while(1); - } - - int wasicanon; - - void restoreicanon(void) - { - seticanon(wasicanon, TRUE); - } - - int main(int argc, char *argv[]) - { - int argi = 1; - - if(argc == 1) - usage(0); - - wasicanon = seticanon(FALSE, FALSE); - atexit(restoreicanon); - - while(argi < argc) { - const char *arg = argv[argi++]; - - if(streq(arg, "reset")) { - printf("\x1b" "c"); - } - else if(streq(arg, "s8c1t")) { - const char *choices[] = {"off", "on", NULL}; - switch(getchoice(&argi, argc, argv, choices)) { - case 0: - printf("\x1b F"); break; - case 1: - printf("\x1b G"); break; - } - } - else if(streq(arg, "keypad")) { - const char *choices[] = {"app", "num", NULL}; - switch(getchoice(&argi, argc, argv, choices)) { - case 0: - printf("\x1b="); break; - case 1: - printf("\x1b>"); break; - } - } - else if(streq(arg, "screen")) { - do_dec_mode(5, getboolq(&argi, argc, argv), "screen"); - } - else if(streq(arg, "cursor")) { - do_dec_mode(25, getboolq(&argi, argc, argv), "cursor"); - } - else if(streq(arg, "curblink")) { - do_dec_mode(12, getboolq(&argi, argc, argv), "curblink"); - } - else if(streq(arg, "curshape")) { - // TODO: This ought to query the current value of DECSCUSR because it - // may need blinking on or off - const char *choices[] = {"block", "under", "bar", "query", NULL}; - int shape = getchoice(&argi, argc, argv, choices); - switch(shape) { - case 3: // query - shape = query_rqss_numeric(" q"); - switch(shape) { - case 1: case 2: - printf("curshape block\n"); - break; - case 3: case 4: - printf("curshape under\n"); - break; - case 5: case 6: - printf("curshape bar\n"); - break; - } - break; - - case 0: - case 1: - case 2: - printf("\x1b[%d q", 1 + (shape * 2)); - break; - } - } - else if(streq(arg, "mouse")) { - const char *choices[] = {"off", "click", "clickdrag", "motion", NULL}; - switch(getchoice(&argi, argc, argv, choices)) { - case 0: - printf("\x1b[?1000l"); break; - case 1: - printf("\x1b[?1000h"); break; - case 2: - printf("\x1b[?1002h"); break; - case 3: - printf("\x1b[?1003h"); break; - } - } - else if(streq(arg, "reportfocus")) { - do_dec_mode(1004, getboolq(&argi, argc, argv), "reportfocus"); - } - else if(streq(arg, "altscreen")) { - do_dec_mode(1049, getboolq(&argi, argc, argv), "altscreen"); - } - else if(streq(arg, "bracketpaste")) { - do_dec_mode(2004, getboolq(&argi, argc, argv), "bracketpaste"); - } - else if(streq(arg, "icontitle")) { - printf("\x1b]0;%s\a", getvalue(&argi, argc, argv)); - } - else if(streq(arg, "icon")) { - printf("\x1b]1;%s\a", getvalue(&argi, argc, argv)); - } - else if(streq(arg, "title")) { - printf("\x1b]2;%s\a", getvalue(&argi, argc, argv)); - } - else { - fprintf(stderr, "Unrecognised command %s\n", arg); - exit(1); - } - } - return 0; - } --- 0 ---- *** ../vim-8.1.2373/src/libvterm/bin/unterm.c 2019-08-18 20:41:10.692526067 +0200 --- src/libvterm/bin/unterm.c 1970-01-01 01:00:00.000000000 +0100 *************** *** 1,288 **** - #include - #include - - #include - #include - #include - #include - - #include "vterm.h" - - #define DEFINE_INLINES - #include "../src/utf8.h" // fill_utf8 - - #define streq(a,b) (!strcmp(a,b)) - - static VTerm *vt; - static VTermScreen *vts; - - static int cols; - static int rows; - - static enum { - FORMAT_PLAIN, - FORMAT_SGR, - } format = FORMAT_PLAIN; - - static int col2index(VTermColor target) - { - int index; - - for(index = 0; index < 256; index++) { - VTermColor col; - vterm_state_get_palette_color(NULL, index, &col); - if(col.red == target.red && col.green == target.green && col.blue == target.blue) - return index; - } - return -1; - } - - static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell) - { - switch(format) { - case FORMAT_PLAIN: - break; - case FORMAT_SGR: - { - // If all 7 attributes change, that means 7 SGRs max - // Each colour could consume up to 3 - int sgr[7 + 2*3]; int sgri = 0; - - if(!prevcell->attrs.bold && cell->attrs.bold) - sgr[sgri++] = 1; - if(prevcell->attrs.bold && !cell->attrs.bold) - sgr[sgri++] = 22; - - if(!prevcell->attrs.underline && cell->attrs.underline) - sgr[sgri++] = 4; - if(prevcell->attrs.underline && !cell->attrs.underline) - sgr[sgri++] = 24; - - if(!prevcell->attrs.italic && cell->attrs.italic) - sgr[sgri++] = 3; - if(prevcell->attrs.italic && !cell->attrs.italic) - sgr[sgri++] = 23; - - if(!prevcell->attrs.blink && cell->attrs.blink) - sgr[sgri++] = 5; - if(prevcell->attrs.blink && !cell->attrs.blink) - sgr[sgri++] = 25; - - if(!prevcell->attrs.reverse && cell->attrs.reverse) - sgr[sgri++] = 7; - if(prevcell->attrs.reverse && !cell->attrs.reverse) - sgr[sgri++] = 27; - - if(!prevcell->attrs.strike && cell->attrs.strike) - sgr[sgri++] = 9; - if(prevcell->attrs.strike && !cell->attrs.strike) - sgr[sgri++] = 29; - - if(!prevcell->attrs.font && cell->attrs.font) - sgr[sgri++] = 10 + cell->attrs.font; - if(prevcell->attrs.font && !cell->attrs.font) - sgr[sgri++] = 10; - - if(prevcell->fg.red != cell->fg.red || - prevcell->fg.green != cell->fg.green || - prevcell->fg.blue != cell->fg.blue) { - int index = col2index(cell->fg); - if(index == -1) - sgr[sgri++] = 39; - else if(index < 8) - sgr[sgri++] = 30 + index; - else if(index < 16) - sgr[sgri++] = 90 + (index - 8); - else { - sgr[sgri++] = 38; - sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE; - sgr[sgri++] = index | CSI_ARG_FLAG_MORE; - } - } - - if(prevcell->bg.red != cell->bg.red || - prevcell->bg.green != cell->bg.green || - prevcell->bg.blue != cell->bg.blue) { - int index = col2index(cell->bg); - if(index == -1) - sgr[sgri++] = 49; - else if(index < 8) - sgr[sgri++] = 40 + index; - else if(index < 16) - sgr[sgri++] = 100 + (index - 8); - else { - sgr[sgri++] = 48; - sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE; - sgr[sgri++] = index | CSI_ARG_FLAG_MORE; - } - } - - if(!sgri) - break; - - printf("\x1b["); - { - int i; - for(i = 0; i < sgri; i++) - printf(!i ? "%d" : - CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" : - ";%d", - CSI_ARG(sgr[i])); - } - printf("m"); - } - break; - } - - { - int i; - for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { - char bytes[6]; - bytes[fill_utf8(cell->chars[i], bytes)] = 0; - printf("%s", bytes); - } - } - } - - static void dump_eol(const VTermScreenCell *prevcell) - { - switch(format) { - case FORMAT_PLAIN: - break; - case FORMAT_SGR: - if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic || - prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike || - prevcell->attrs.font) - printf("\x1b[m"); - break; - } - - printf("\n"); - } - - void dump_row(int row) - { - VTermPos pos; - VTermScreenCell prevcell; - pos.row = row; - pos.col = 0; - memset(&prevcell, 0, sizeof(prevcell)); - vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg); - - while(pos.col < cols) { - VTermScreenCell cell; - vterm_screen_get_cell(vts, pos, &cell); - - dump_cell(&cell, &prevcell); - - pos.col += cell.width; - prevcell = cell; - } - - dump_eol(&prevcell); - } - - static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user) - { - VTermScreenCell prevcell; - int col; - - memset(&prevcell, 0, sizeof(prevcell)); - vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg); - - for(col = 0; col < cols; col++) { - dump_cell(cells + col, &prevcell); - prevcell = cells[col]; - } - - dump_eol(&prevcell); - - return 1; - } - - static int screen_resize(int new_rows, int new_cols, void *user) - { - rows = new_rows; - cols = new_cols; - return 1; - } - - static VTermScreenCallbacks cb_screen = { - NULL, // damage - NULL, // moverect - NULL, // movecursor - NULL, // settermprop - NULL, // bell - &screen_resize, // resize - &screen_sb_pushline, // sb_pushline - NULL, // popline - }; - - int main(int argc, char *argv[]) - { - int opt; - const char *file; - int fd; - int len; - char buffer[1024]; - int row; - - rows = 25; - cols = 80; - - while((opt = getopt(argc, argv, "f:l:c:")) != -1) { - switch(opt) { - case 'f': - if(streq(optarg, "plain")) - format = FORMAT_PLAIN; - else if(streq(optarg, "sgr")) - format = FORMAT_SGR; - else { - fprintf(stderr, "Unrecognised format '%s'\n", optarg); - exit(1); - } - break; - - case 'l': - rows = atoi(optarg); - if(!rows) - rows = 25; - break; - - case 'c': - cols = atoi(optarg); - if(!cols) - cols = 80; - break; - } - } - - file = argv[optind++]; - fd = open(file, O_RDONLY); - if(fd == -1) { - fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno)); - exit(1); - } - - vt = vterm_new(rows, cols); - vterm_set_utf8(vt, TRUE); - - vts = vterm_obtain_screen(vt); - vterm_screen_set_callbacks(vts, &cb_screen, NULL); - - vterm_screen_reset(vts, 1); - - while((len = read(fd, buffer, sizeof(buffer))) > 0) { - vterm_input_write(vt, buffer, len); - } - - for(row = 0; row < rows; row++) { - dump_row(row); - } - - close(fd); - - vterm_free(vt); - - return 0; - } --- 0 ---- *** ../vim-8.1.2373/src/libvterm/bin/vterm-dump.c 2019-08-18 20:41:10.692526067 +0200 --- src/libvterm/bin/vterm-dump.c 1970-01-01 01:00:00.000000000 +0100 *************** *** 1,232 **** - // Require getopt(3) - #define _XOPEN_SOURCE - - #include - #include - #define streq(a,b) (strcmp(a,b)==0) - - #include - #include - #include - #include - #include - - #include "vterm.h" - - static const char *special_begin = "{"; - static const char *special_end = "}"; - - static int parser_text(const char bytes[], size_t len, void *user) - { - unsigned char *b = (unsigned char *)bytes; - - int i; - for(i = 0; i < len; ) { - if(b[i] < 0x20) // C0 - break; - else if(b[i] < 0x80) // ASCII - i++; - else if(b[i] < 0xa0) // C1 - break; - else if(b[i] < 0xc0) // UTF-8 continuation - break; - else if(b[i] < 0xe0) { // UTF-8 2-byte - // 2-byte UTF-8 - if(len < i+2) break; - i += 2; - } - else if(b[i] < 0xf0) { // UTF-8 3-byte - if(len < i+3) break; - i += 3; - } - else if(b[i] < 0xf8) { // UTF-8 4-byte - if(len < i+4) break; - i += 4; - } - else // otherwise invalid - break; - } - - printf("%.*s", i, b); - return i; - } - - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - static const char *name_c0[] = { - "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "LS0", "LS1", - "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US", - }; - static const char *name_c1[] = { - NULL, NULL, "BPH", "NBH", NULL, "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3", - "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", NULL, "SCI", "CSI", "ST", "OSC", "PM", "APC", - }; - - static int parser_control(unsigned char control, void *user) - { - if(control < 0x20) - printf("%s%s%s", special_begin, name_c0[control], special_end); - else if(control >= 0x80 && control < 0xa0 && name_c1[control - 0x80]) - printf("%s%s%s", special_begin, name_c1[control - 0x80], special_end); - else - printf("%sCONTROL 0x%02x%s", special_begin, control, special_end); - - if(control == 0x0a) - printf("\n"); - return 1; - } - - static int parser_escape(const char bytes[], size_t len, void *user) - { - if(bytes[0] >= 0x20 && bytes[0] < 0x30) { - if(len < 2) - return -1; - len = 2; - } - else { - len = 1; - } - - printf("%sESC %.*s%s", special_begin, (int)len, bytes, special_end); - - return len; - } - - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - static const char *name_csi_plain[] = { - "ICH", "CUU", "CUD", "CUF", "CUB", "CNL", "CPL", "CHA", "CUP", "CHT", "ED", "EL", "IL", "DL", "EF", "EA", - "DCH", "SSE", "CPR", "SU", "SD", "NP", "PP", "CTC", "ECH", "CVT", "CBT", "SRS", "PTX", "SDS", "SIMD",NULL, - "HPA", "HPR", "REP", "DA", "VPA", "VPR", "HVP", "TBC", "SM", "MC", "HPB", "VPB", "RM", "SGR", "DSR", "DAQ", - }; - - //0 4 8 B - static const int newline_csi_plain[] = { - 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, - }; - - static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) - { - const char *name = NULL; - if(!leader && !intermed && command < 0x70) - name = name_csi_plain[command - 0x40]; - else if(leader && streq(leader, "?") && !intermed) { - // DEC - switch(command) { - case 'h': name = "DECSM"; break; - case 'l': name = "DECRM"; break; - } - if(name) - leader = NULL; - } - - if(!leader && !intermed && command < 0x70 && newline_csi_plain[command - 0x40]) - printf("\n"); - - if(name) - printf("%s%s", special_begin, name); - else - printf("%sCSI", special_begin); - - if(leader && leader[0]) - printf(" %s", leader); - - { - int i; - for(i = 0; i < argcount; i++) { - printf(i ? "," : " "); - } - - if(args[i] == CSI_ARG_MISSING) - printf("*"); - else { - while(CSI_ARG_HAS_MORE(args[i])) - printf("%ld+", CSI_ARG(args[i++])); - printf("%ld", CSI_ARG(args[i])); - } - } - - if(intermed && intermed[0]) - printf(" %s", intermed); - - if(name) - printf("%s", special_end); - else - printf(" %c%s", command, special_end); - - return 1; - } - - static int parser_osc(const char *command, size_t cmdlen, void *user) - { - printf("%sOSC %.*s%s", special_begin, (int)cmdlen, command, special_end); - - return 1; - } - - static int parser_dcs(const char *command, size_t cmdlen, void *user) - { - printf("%sDCS %.*s%s", special_begin, (int)cmdlen, command, special_end); - - return 1; - } - - static VTermParserCallbacks parser_cbs = { - &parser_text, // text - &parser_control, // control - &parser_escape, // escape - &parser_csi, // csi - &parser_osc, // osc - &parser_dcs, // dcs - NULL // resize - }; - - int main(int argc, char *argv[]) - { - int use_colour = isatty(1); - const char *file; - int fd; - VTerm *vt; - int len; - char buffer[1024]; - - int opt; - while((opt = getopt(argc, argv, "c")) != -1) { - switch(opt) { - case 'c': use_colour = 1; break; - } - } - - file = argv[optind++]; - - if(!file || streq(file, "-")) - fd = 0; // stdin - else { - fd = open(file, O_RDONLY); - if(fd == -1) { - fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno)); - exit(1); - } - } - - if(use_colour) { - special_begin = "\x1b[7m{"; - special_end = "}\x1b[m"; - } - - // Size matters not for the parser - vt = vterm_new(25, 80); - vterm_set_utf8(vt, 1); - vterm_parser_set_callbacks(vt, &parser_cbs, NULL); - - while((len = read(fd, buffer, sizeof(buffer))) > 0) { - vterm_input_write(vt, buffer, len); - } - - printf("\n"); - - close(fd); - vterm_free(vt); - - return 0; - } --- 0 ---- *** ../vim-8.1.2373/src/version.c 2019-12-01 15:23:07.472344471 +0100 --- src/version.c 2019-12-01 15:30:19.430392975 +0100 *************** *** 744,745 **** --- 744,747 ---- { /* Add new patch number below this line */ + /**/ + 2374, /**/ -- hundred-and-one symptoms of being an internet addict: 164. You got out to buy software, instead of going out for a beer. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///