X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=test%2Fview.c;h=4c1344cb5d3737f2ce3543fd4ec4334c78f9ac8d;hp=ad6bb2e1858c4256977b0a0457e93676e78a5fc2;hb=c633e5103a29a38532cf1925257b91cea33fd090;hpb=661078ddbde3ce0f3b06e95642fbb9b5fef7dca1 diff --git a/test/view.c b/test/view.c index ad6bb2e1..4c1344cb 100644 --- a/test/view.c +++ b/test/view.c @@ -5,7 +5,8 @@ * to test the scrolling code in ncurses. * * modified by Thomas Dickey July 1995 to demonstrate - * the use of 'resizeterm()'. + * the use of 'resizeterm()', and May 2000 to illustrate wide-character + * handling. * * Takes a filename argument. It's a simple file-viewer with various * scroll-up and scroll-down commands. @@ -22,7 +23,7 @@ * scroll operation worked, and the refresh() code only had to do a * partial repaint. * - * $Id: view.c,v 1.26 1997/11/15 22:36:41 tom Exp $ + * $Id: view.c,v 1.31 2000/09/02 18:14:52 tom Exp $ */ #include @@ -52,7 +53,7 @@ static RETSIGTYPE finish(int sig) GCC_NORETURN; static void show_all(void); -#if defined(SIGWINCH) && defined(TIOCGWINSZ) && defined(NCURSES_VERSION) +#if defined(SIGWINCH) && defined(TIOCGWINSZ) && HAVE_RESIZETERM #define CAN_RESIZE 1 #else #define CAN_RESIZE 0 @@ -60,33 +61,23 @@ static void show_all(void); #if CAN_RESIZE static RETSIGTYPE adjust(int sig); -static int interrupted; +static int interrupted; #endif -static int waiting; -static int shift; +static int waiting; +static int shift; +static int utf8_mode = FALSE; -static char *fname; -static char **lines; -static char **lptr; +static char *fname; +static chtype **lines; +static chtype **lptr; -#if !HAVE_STRDUP -#define strdup my_strdup -static char *strdup (char *s) +static void +usage(void) { - char *p; - - p = malloc(strlen(s)+1); - if (p) - strcpy(p,s); - return(p); -} -#endif /* not HAVE_STRDUP */ - -static void usage(void) -{ - static const char *msg[] = { - "Usage: view [options] file" + static const char *msg[] = + { + "Usage: view [options] file" ,"" ,"Options:" ," -n NUM specify maximum number of lines (default 1000)" @@ -97,27 +88,117 @@ static void usage(void) ," -t trace screen updates" ," -T NUM specify trace mask" #endif + ," -u translate UTF-8 data" }; size_t n; for (n = 0; n < SIZEOF(msg); n++) fprintf(stderr, "%s\n", msg[n]); - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); +} + +static int +ch_len(chtype * src) +{ + int result = 0; + while (*src++) + result++; + return result; +} + +/* + * Allocate a string into an array of chtype's. If UTF-8 mode is + * active, translate the string accordingly. + */ +static chtype * +ch_dup(char *src) +{ + unsigned len = strlen(src); + chtype *dst = typeMalloc(chtype, len + 1); + unsigned j, k; + unsigned utf_count = 0; + unsigned utf_char = 0; + +#define UCS_REPL 0xfffd + + for (j = k = 0; j < len; j++) { + if (utf8_mode) { + unsigned c = src[j] & 0xff; + /* Combine UTF-8 into Unicode */ + if (c < 0x80) { + /* We received an ASCII character */ + if (utf_count > 0) + dst[k++] = UCS_REPL; /* prev. sequence incomplete */ + dst[k++] = c; + utf_count = 0; + } else if (c < 0xc0) { + /* We received a continuation byte */ + if (utf_count < 1) { + dst[k++] = UCS_REPL; /* ... unexpectedly */ + } else { + if (!utf_char && !((c & 0x7f) >> (7 - utf_count))) { + utf_char = UCS_REPL; + } + /* characters outside UCS-2 become UCS_REPL */ + if (utf_char > 0x03ff) { + /* value would be >0xffff */ + utf_char = UCS_REPL; + } else { + utf_char <<= 6; + utf_char |= (c & 0x3f); + } + utf_count--; + if (utf_count == 0) + dst[k++] = utf_char; + } + } else { + /* We received a sequence start byte */ + if (utf_count > 0) + dst[k++] = UCS_REPL; /* prev. sequence incomplete */ + if (c < 0xe0) { + utf_count = 1; + utf_char = (c & 0x1f); + if (!(c & 0x1e)) + utf_char = UCS_REPL; /* overlong sequence */ + } else if (c < 0xf0) { + utf_count = 2; + utf_char = (c & 0x0f); + } else if (c < 0xf8) { + utf_count = 3; + utf_char = (c & 0x07); + } else if (c < 0xfc) { + utf_count = 4; + utf_char = (c & 0x03); + } else if (c < 0xfe) { + utf_count = 5; + utf_char = (c & 0x01); + } else { + dst[k++] = UCS_REPL; + utf_count = 0; + } + } + } else { + dst[k++] = src[j]; + } + } + dst[k] = 0; + return dst; } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { -int MAXLINES = 1000; -FILE *fp; -char buf[BUFSIZ]; -int i; -char **olptr; -int done = FALSE; -int length = 0; + int MAXLINES = 1000; + FILE *fp; + char buf[BUFSIZ]; + int i; + chtype **olptr; + int done = FALSE; + int length = 0; #if CAN_RESIZE -bool use_resize = TRUE; + bool use_resize = TRUE; #endif - while ((i = getopt(argc, argv, "n:rtT:")) != EOF) { + while ((i = getopt(argc, argv, "n:rtT:u")) != EOF) { switch (i) { case 'n': if ((MAXLINES = atoi(optarg)) < 1) @@ -136,6 +217,9 @@ bool use_resize = TRUE; trace(TRACE_CALLS); break; #endif + case 'u': + utf8_mode = TRUE; + break; default: usage(); } @@ -143,7 +227,7 @@ bool use_resize = TRUE; if (optind + 1 != argc) usage(); - if ((lines = (char **)calloc(MAXLINES+2, sizeof(*lines))) == 0) + if ((lines = typeMalloc(chtype *, MAXLINES + 2)) == 0) usage(); fname = argv[optind]; @@ -152,16 +236,16 @@ bool use_resize = TRUE; return EXIT_FAILURE; } - (void) signal(SIGINT, finish); /* arrange interrupts to terminate */ + (void) signal(SIGINT, finish); /* arrange interrupts to terminate */ #if CAN_RESIZE if (use_resize) - (void) signal(SIGWINCH, adjust); /* arrange interrupts to resize */ + (void) signal(SIGWINCH, adjust); /* arrange interrupts to resize */ #endif /* slurp the file */ for (lptr = &lines[0]; (lptr - lines) < MAXLINES; lptr++) { char temp[BUFSIZ], *s, *d; - int col; + int col; if (fgets(buf, sizeof(buf), fp) == 0) break; @@ -173,9 +257,9 @@ bool use_resize = TRUE; break; } else if (*d == '\t') { col = (col | 7) + 1; - while ((d-temp) != col) + while ((d - temp) != col) *d++ = ' '; - } else if (isprint(*d)) { + } else if (isprint(*d) || utf8_mode) { col++; d++; } else { @@ -184,17 +268,17 @@ bool use_resize = TRUE; col = (d - temp); } } - *lptr = strdup(temp); + *lptr = ch_dup(temp); } (void) fclose(fp); length = lptr - lines; - (void) initscr(); /* initialize the curses library */ - keypad(stdscr, TRUE); /* enable keyboard mapping */ - (void) nonl(); /* tell curses not to do NL->CR/NL on output */ - (void) cbreak(); /* take input chars one at a time, no wait for \n */ - (void) noecho(); /* don't echo input */ - idlok(stdscr, TRUE); /* allow use of insert/delete line */ + (void) initscr(); /* initialize the curses library */ + keypad(stdscr, TRUE); /* enable keyboard mapping */ + (void) nonl(); /* tell curses not to do NL->CR/NL on output */ + (void) cbreak(); /* take input chars one at a time, no wait for \n */ + (void) noecho(); /* don't echo input */ + idlok(stdscr, TRUE); /* allow use of insert/delete line */ lptr = lines; while (!done) { @@ -205,7 +289,7 @@ bool use_resize = TRUE; got_number = FALSE; n = 0; - for (;;) { + for (;;) { #if CAN_RESIZE if (interrupted) adjust(0); @@ -215,20 +299,19 @@ bool use_resize = TRUE; waiting = FALSE; if ((c < 127) && isdigit(c)) { if (!got_number) { - mvprintw(0,0, "Count: "); + mvprintw(0, 0, "Count: "); clrtoeol(); } addch(c); n = 10 * n + (c - '0'); got_number = TRUE; - } - else + } else break; } if (!got_number && n == 0) n = 1; - switch(c) { + switch (c) { case KEY_DOWN: case 'n': olptr = lptr; @@ -282,7 +365,7 @@ bool use_resize = TRUE; break; #ifdef KEY_RESIZE - case KEY_RESIZE: /* ignore this; ncurses will repaint */ + case KEY_RESIZE: /* ignore this; ncurses will repaint */ break; #endif #if CAN_RESIZE @@ -297,7 +380,8 @@ bool use_resize = TRUE; finish(0); /* we're done */ } -static RETSIGTYPE finish(int sig) +static RETSIGTYPE +finish(int sig) { endwin(); exit(sig != 0 ? EXIT_FAILURE : EXIT_SUCCESS); @@ -309,54 +393,55 @@ static RETSIGTYPE finish(int sig) * Linux. The 'wrefresh(curscr)' is needed to force the refresh to start from * the top of the screen -- some xterms mangle the bitmap while resizing. */ -static RETSIGTYPE adjust(int sig) +static RETSIGTYPE +adjust(int sig) { - if (waiting || sig == 0) { + if (waiting || sig == 0) { struct winsize size; - if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) { - resizeterm(size.ws_row, size.ws_col); - wrefresh(curscr); /* Linux needs this */ - show_all(); - } - interrupted = FALSE; - } else { - interrupted = TRUE; + if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) { + resizeterm(size.ws_row, size.ws_col); + wrefresh(curscr); /* Linux needs this */ + show_all(); } - (void) signal(SIGWINCH, adjust); /* some systems need this */ + interrupted = FALSE; + } else { + interrupted = TRUE; + } + (void) signal(SIGWINCH, adjust); /* some systems need this */ } -#endif /* CAN_RESIZE */ +#endif /* CAN_RESIZE */ -static void show_all(void) +static void +show_all(void) { - int i; - char temp[BUFSIZ]; - char *s; + int i; + char temp[BUFSIZ]; + chtype *s; #if CAN_RESIZE - sprintf(temp, "(%3dx%3d) col %d ", LINES, COLS, shift); - i = strlen(temp); - sprintf(temp+i, "view %.*s", (int)(sizeof(temp)-7-i), fname); + sprintf(temp, "(%3dx%3d) col %d ", LINES, COLS, shift); + i = strlen(temp); + sprintf(temp + i, "view %.*s", (int) (sizeof(temp) - 7 - i), fname); #else - sprintf(temp, "view %.*s", (int)sizeof(temp)-7, fname); + sprintf(temp, "view %.*s", (int) sizeof(temp) - 7, fname); #endif - move(0,0); - printw("%.*s", COLS, temp); + move(0, 0); + printw("%.*s", COLS, temp); + clrtoeol(); + + scrollok(stdscr, FALSE); /* prevent screen from moving */ + for (i = 1; i < LINES; i++) { + move(i, 0); + printw("%3ld:", (long) (lptr + i - lines)); clrtoeol(); - - scrollok(stdscr, FALSE); /* prevent screen from moving */ - for (i = 1; i < LINES; i++) { - move(i, 0); - if ((s = lptr[i-1]) != 0 && (int)strlen(s) > shift) - printw("%3d:%.*s", lptr+i-lines, COLS-4, s + shift); - else - printw("%3d:", lptr+i-lines); - clrtoeol(); + if ((s = lptr[i - 1]) != 0) { + int len = ch_len(s); + if (len > shift) + addchstr(s + shift); } - setscrreg(1, LINES-1); - scrollok(stdscr, TRUE); - refresh(); + } + setscrreg(1, LINES - 1); + scrollok(stdscr, TRUE); + refresh(); } - -/* view.c ends here */ -