"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/p/p.c" (20 Aug 2021, 33980 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "p.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes reports: 2021-08-14_vs_2021-09-18 or 2021-07-29_vs_2021-09-18.

    1 /* @(#)p.c  1.75 21/08/20 Copyright 1985-2021 J. Schilling */
    2 #include <schily/mconfig.h>
    3 #ifndef lint
    4 static  UConst char sccsid[] =
    5     "@(#)p.c    1.75 21/08/20 Copyright 1985-2021 J. Schilling";
    6 #endif
    7 /*
    8  *  Print some files on screen
    9  *
   10  *  Copyright (c) 1985-2021 J. Schilling
   11  */
   12 /*
   13  * The contents of this file are subject to the terms of the
   14  * Common Development and Distribution License, Version 1.0 only
   15  * (the "License").  You may not use this file except in compliance
   16  * with the License.
   17  *
   18  * See the file CDDL.Schily.txt in this distribution for details.
   19  * A copy of the CDDL is also available via the Internet at
   20  * http://www.opensource.org/licenses/cddl1.txt
   21  *
   22  * When distributing Covered Code, include this CDDL HEADER in each
   23  * file and include the License file CDDL.Schily.txt from this distribution.
   24  */
   25 
   26 #include <schily/stdio.h>
   27 #include <schily/standard.h>
   28 #include <schily/stdlib.h>
   29 #include <schily/unistd.h>
   30 #include <schily/types.h>
   31 #include <schily/utypes.h>
   32 #include <schily/fcntl.h>
   33 #include <schily/string.h>
   34 #include <schily/signal.h>
   35 #include <schily/sigset.h>
   36 #include <schily/termcap.h>
   37 #include <schily/libport.h>
   38 #include <schily/errno.h>
   39 #define ungetch dos_ungetch /* Avoid DOS/curses ungetch() type clash */
   40 #include <schily/termios.h>
   41 #undef  ungetch         /* Restore our old value */
   42 #include <schily/nlsdefs.h>
   43 #include <schily/limits.h>  /* for  MB_LEN_MAX  */
   44 #include <schily/ctype.h>   /* For isprint()    */
   45 #include <schily/wchar.h>   /* wchar_t      */
   46 #include <schily/wctype.h>  /* For iswprint()   */
   47 #include <schily/patmatch.h>
   48 #define GT_COMERR       /* #define comerr gtcomerr */
   49 #define GT_ERROR        /* #define error gterror   */
   50 #include <schily/schily.h>
   51 
   52 #define SEARCHSIZE  256
   53 #define DEF_PSIZE   24;
   54 #define DEF_LWIDTH  80;
   55 
   56 #if MB_LEN_MAX > 1
   57 /*
   58  * We are on a platform that supports multi byte characters.
   59  */
   60 #define nextc()     nextwc()    /* Read next char */
   61 #define peekc()     peekwc()    /* Peek next char */
   62 #define getnextch() getnextwch()    /* Consume last peeked char */
   63 #define ungetch(c)  ungetwch(c) /* Unread char back to buffer */
   64 #else
   65 #define nextc() (--len >= 0 ? (int) *bp++ : \
   66             (fill_buf() <= 0 ? (len == 0 ? EOF : -2) : \
   67             (len--, (int) *bp++)))
   68 #define peekc() (len > 0 ? (int) *bp : \
   69             (fill_buf() <= 0 ? (len == 0 ? EOF : -2) : \
   70             ((int) *bp)))
   71 #define getnextch() (len--, bp++)
   72 #define __peekc()   (ungetch(nextc()))
   73 #endif
   74 
   75 #   ifdef   USE_V7_TTY
   76 struct sgttyb old;
   77 struct sgttyb new;
   78 
   79 #   else    /* USE_V7_TTY */
   80 
   81 #ifdef  USE_TERMIOS
   82 struct termios  old;
   83 struct termios  new;
   84 #endif
   85 #   endif   /* USE_V7_TTY */
   86 int tty = -1;
   87 
   88 FILE    *f;     /* the file being printed */
   89 off_t   ofpos;      /* saved filepos for searching */
   90 int lineno;     /* current lineno (used for editing) */
   91 int colcnt;     /* column on screen we are going to print */
   92 int linecnt;    /* # of lines actually printed on screen */
   93 int lwidth;     /* length of a line on screen */
   94 int lines;      /* # of lines until we print a more prompt */
   95 int psize;      /* # of lines on a page */
   96 int supressblank;   /* supress multiple blank lines on output */
   97 int clear;      /* clear screen before displaying page */
   98 int dosmode;    /* wether to supress ^M^J sequences */
   99 BOOL    autodos = TRUE; /* whether to automatically detect DOS mode */
  100 int endline;    /* print a $ at each end of line */
  101 int raw;        /* do not expand control characters */
  102 BOOL    raw8;       /* Ausgabe ohne ~ */
  103 int silent;     /* in silent mode there is no more prompt */
  104 int tab;        /* do nut expand tabs to spaces but to ^I */
  105 int visible;    /* _^H sequences are visible */
  106 int underline;  /* do underlining */
  107 int ununderline;    /* remove underlining */
  108 int help;       /* print online help */
  109 int prvers;     /* print version information */
  110 BOOL    debug;      /* misc debug flag */
  111 BOOL    nobeep;     /* be silent on errors */
  112 char    *filename;  /* Filename fuer Ausgabezwecke */
  113 int direction;  /* direction to step through file list */
  114 #define FORWARD 0
  115 char    *editor;
  116 char    *shell;
  117 int searchnext;
  118 #if MB_LEN_MAX > 1
  119 wchar_t searchbuf[SEARCHSIZE];
  120 #else
  121 char    searchbuf[SEARCHSIZE];
  122 #endif
  123 int     alt;
  124 int     *aux;
  125 int     *state;
  126 
  127 char    *so;        /* start standout */
  128 char    *se;        /* end standout */
  129 char    *xso;       /* start abstract bold/standout */
  130 char    *xse;       /* end abstract bold/standout */
  131 char    *us;        /* start underline */
  132 char    *ue;        /* end underline */
  133 char    *md;        /* start bold */
  134 char    *me;        /* end attributes */
  135 char    *ce;        /* clear endline */
  136 char    *cl;        /* clear screen */
  137 int li;     /* lines on screen */
  138 int co;     /* columns on screen */
  139 BOOL    am = TRUE;  /* automatic margins */
  140 BOOL    xn;     /* newline ignored > 80 */
  141 BOOL    has_standout;
  142 BOOL    has_bold;
  143 BOOL    has_ul;
  144 BOOL    has_termcap;
  145 int standout;
  146 int underl;
  147 
  148 /*
  149  * As an incomplete multi byte character after a buffer refill
  150  * is partially before the begin of the buffer, we need to be
  151  * able to store a second character before that. This happens
  152  * when peekc() triggered a buffer refill and then ungetch()
  153  * is called.
  154  */
  155 #define P_BUFSIZE   ((8*1024)+(2*MB_LEN_MAX))
  156 unsigned char mybuf[P_BUFSIZE]; /* Fuer nextc */
  157 unsigned char *bp;      /* ditto */
  158 int len = 0;            /* ditto */
  159 int clen = 0;           /* # of octects in nextwc() multi byte char */
  160 int pclen = 0;          /* # of octects in peekwc() multi byte char */
  161 unsigned char *cp;      /* Beginning of multi byte char in buffer   */
  162 unsigned char *pcp;     /* Beginning of peeked multi byte char in buf */
  163 
  164 #ifdef  BUFSIZ
  165 char    buffer[BUFSIZ];     /* our buffer for stdout */
  166 #endif
  167 char    dcl[] = ":::::::::::::::";
  168 /* BEGIN CSTYLED */
  169 char    options[] =
  170 "help,version,debug,nobeep,length#,l#,width#,w#,blank,b,clear,c,dos,nodos%0,end,e,raw,r,raw8,silent,s,tab,t,unul,visible,v";
  171 /* END CSTYLED */
  172 
  173 BOOL nameprint = FALSE;
  174 
  175 extern  unsigned char   csize[];
  176 extern  unsigned char   *ctab[];
  177 
  178 extern  void    init_charset    __PR((void));
  179 
  180 LOCAL   void    tstp        __PR((int sig));
  181 LOCAL   void    usage       __PR((int exitcode));
  182 EXPORT  int main        __PR((int ac, char **av));
  183 LOCAL   void    page        __PR((void));
  184 LOCAL   int outchar     __PR((int c));
  185 LOCAL   void    moreprompt  __PR((void));
  186 LOCAL   BOOL    more        __PR((void));
  187 LOCAL   int get_action  __PR((void));
  188 LOCAL   void    onlinehelp  __PR((void));
  189 LOCAL   void    redraw      __PR((void));
  190 LOCAL   int inchar      __PR((void));
  191 #if MB_LEN_MAX > 1
  192 LOCAL   int inwchar     __PR((void));
  193 #else
  194 #define inwchar inchar
  195 #endif
  196 #ifndef nextc
  197 LOCAL   int nextc       __PR((void));
  198 #endif
  199 #if MB_LEN_MAX > 1
  200 LOCAL   int nextwc      __PR((void));
  201 LOCAL   int peekwc      __PR((void));
  202 #endif
  203 #ifndef ungetch
  204 LOCAL   int ungetch     __PR((int c));
  205 #endif
  206 #if MB_LEN_MAX > 1
  207 LOCAL   int ungetwch    __PR((int c));
  208 LOCAL   void    getnextwch  __PR((void));
  209 #endif
  210 LOCAL   int fill_buf    __PR((void));
  211 LOCAL   BOOL    read_pattern    __PR((void));
  212 LOCAL   int do_search   __PR((void));
  213 LOCAL   int unul        __PR((Uchar *ob, Uchar *ib, int amt));
  214 LOCAL   void    init_termcap    __PR((void));
  215 LOCAL   int oc      __PR((int c));
  216 LOCAL   void    start_standout  __PR((void));
  217 LOCAL   void    end_standout    __PR((void));
  218 #ifdef  __needed__
  219 LOCAL   void    start_bold  __PR((void));
  220 #endif
  221 LOCAL   void    end_attr    __PR((void));
  222 LOCAL   void    start_xstandout __PR((void));
  223 LOCAL   void    end_xstandout   __PR((void));
  224 LOCAL   void    start_ul    __PR((void));
  225 LOCAL   void    end_ul      __PR((void));
  226 LOCAL   void    clearline   __PR((void));
  227 LOCAL   void    clearscreen __PR((void));
  228 LOCAL   void    init_tty_size   __PR((void));
  229 LOCAL   int get_modes   __PR((void));
  230 LOCAL   void    set_modes   __PR((void));
  231 LOCAL   void    reset_modes __PR((void));
  232 LOCAL   void    fixtty      __PR((int sig));
  233 
  234 #ifdef  SIGTSTP
  235 LOCAL void
  236 tstp(sig)
  237     int sig;
  238 {
  239     /* ignore SIGTTOU so we don't get stopped if the shell modifies pgrp */
  240     signal(SIGTTOU, SIG_IGN);
  241     end_standout();
  242     end_attr();
  243     end_ul();
  244     clearline();
  245     reset_modes();
  246     signal(SIGTTOU, SIG_DFL);
  247 
  248     signal(SIGTSTP, SIG_DFL);
  249 #ifdef  OLD
  250 #ifdef  HAVE_SIGRELSE
  251     sigrelse(SIGTSTP);
  252 #else
  253     (void) sigsetmask(0);
  254 #endif
  255 #else   /* NEW */
  256     unblock_sig(SIGTSTP);
  257 #endif
  258     kill(getpid(), SIGTSTP);
  259 
  260     /* Hier stoppt 'p' */
  261 
  262     set_modes();
  263     moreprompt();
  264 }
  265 #endif
  266 
  267 
  268 LOCAL void
  269 usage(exitcode)
  270     int exitcode;
  271 {
  272     error("Usage:   p [options] [file1...filen]\n");
  273     error("Options:\n");
  274     error("\t-help\t\tprint this online help\n");
  275     error("\t-version\tprint version number\n");
  276     error("\t-debug\t\tprint additional debug output\n");
  277     error("\tlength=#,l=#\tlength of screen (default 24)\n");
  278     error("\twidth=#,w=#\twidth  of screen (default 80)\n");
  279     error("\t-blank,-b\tsupress multiple blank lines on output\n");
  280     error("\t-clear,-c\tclear screen before displaying new page\n");
  281     error("\t-dos\t\tsupress '\\r' in '\\r\\n'\n");
  282     error("\t-nodos\t\tsupress auto detecting the dos mode\n");
  283     error("\t-end,-e\t\tprint a $ at each end of line\n");
  284     error("\t-raw,-r\t\tdo not expand chars\n");
  285     error("\t-raw8\t\tdo not expand 8bit chars\n");
  286     error("\t-silent,-s\tdo not prompt for more stuff\n");
  287     error("\t-tab,-t\t\tdo not expand tabs to spaces but to ^I\n");
  288 #ifdef  __needed__
  289     error("\t-unul\t\tremove underlining and bold sequences\n");
  290 #endif
  291     error("\t-visible,-v\tunderlining/bold sequences become visible\n\n");
  292     error(" When asked for more:  confirm=page, n=no more, h=half page\n");
  293     error("     q=quarter page, l=single line, 1-9=# lines.\n");
  294     error(" When asked for next file:  confirm=yes, n=skip to next\n");
  295     error("     s=stop (exit), h,q,l,1-9=yes with that # lines.\n");
  296     exit(exitcode);
  297 }
  298 
  299 
  300 EXPORT int
  301 main(ac, av)
  302     int ac;
  303     char    *av[];
  304 {
  305     int i;
  306     int cac;
  307     char    *const *cav;
  308     int fac;
  309     char    **fav;
  310 
  311     save_args(ac, av);
  312 
  313     (void) setlocale(LC_ALL, "");
  314 
  315 #ifdef  USE_NLS
  316 #if !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
  317 #define TEXT_DOMAIN "p"     /* Use this only if it weren't */
  318 #endif
  319     { char  *dir;
  320     dir = searchfileinpath("share/locale", F_OK,
  321                     SIP_ANY_FILE|SIP_NO_PATH, NULL);
  322     if (dir)
  323         (void) bindtextdomain(TEXT_DOMAIN, dir);
  324     else
  325 #if defined(PROTOTYPES) && defined(INS_BASE)
  326     (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
  327 #else
  328     (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
  329 #endif
  330     (void) textdomain(TEXT_DOMAIN);
  331     }
  332 #endif  /* USE_NLS */
  333 
  334 
  335     cac = --ac;
  336     cav = ++av;
  337 
  338     if (getallargs(&cac, &cav, options, &help, &prvers, &debug, &nobeep,
  339             &psize, &psize,
  340             &lwidth, &lwidth,
  341             &supressblank, &supressblank,
  342             &clear, &clear,
  343             &dosmode, &autodos,
  344             &endline, &endline,
  345             &raw, &raw,
  346             &raw8,
  347             &silent, &silent,
  348             &tab, &tab,
  349             &ununderline,
  350             &visible, &visible) < 0) {
  351         errmsgno(EX_BAD, "Bad flag: %s.\n", cav[0]);
  352         usage(EX_BAD);
  353     }
  354     if (help) usage(0);
  355     if (prvers) {
  356         /* BEGIN CSTYLED */
  357         gtprintf("p %s %s (%s-%s-%s)\n\n", "2.4", "2021/08/20", HOST_CPU, HOST_VENDOR, HOST_OS);
  358         gtprintf("Copyright (C) 1985, 87-92, 95-99, 2000-2021 %s\n", _("Jörg Schilling"));
  359         gtprintf("This is free software; see the source for copying conditions.  There is NO\n");
  360         gtprintf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
  361         /* END CSTYLED */
  362         exit(0);
  363     }
  364 
  365     shell = getenv("BEEP");
  366     if (shell != NULL && streql(shell, "off"))
  367         nobeep = TRUE;
  368     if ((editor = getenv("EDITOR")) == NULL)
  369         editor = "vi";
  370     if ((shell = getenv("SHELL")) == NULL)
  371         shell = "sh";
  372 
  373     underline = !raw && !visible;
  374 
  375     cac = ac;
  376     cav = av;
  377     for (i = 0; getfiles(&cac, &cav, options) > 0; i++, cac--, cav++);
  378 
  379     if (0 /*fav = (char **)malloc(i*sizeof(char *))*/) {
  380         cac = ac;
  381         cav = av;
  382         fac = i;
  383         for (i = 0; getfiles(&cac, &cav, options) > 0;
  384             i++, cac--, cav++) {
  385             fav[i] = *cav;
  386         }
  387     } else {
  388         cac = ac;
  389         cav = av;
  390         getfiles(&cac, &cav, options);
  391     }
  392 
  393     if (cac == 0 && isatty(fdown(stdin)))
  394         usage(EX_BAD);
  395 
  396     if (get_modes() < 0) {
  397         silent++;
  398         if (!ununderline)
  399             underline = FALSE;
  400     }
  401 
  402 
  403 /*  if (underline || !silent)*/
  404         init_termcap();
  405     init_tty_size();
  406 
  407     if (!silent) {
  408         usleep(150000); /* XXX Hack bis Jobcontrol im bsh geht !!! */
  409         set_modes();
  410     }
  411 
  412     init_charset();
  413 
  414 #ifdef  BUFSIZ          /* XXX #ifdef HAVE_SETBUF ??? */
  415     setbuf(stdout, buffer);
  416 #endif
  417 
  418     /*
  419      * If we evaluate "has_termcap" here, we could avoid to reduce the width
  420      * of the terminal in case that "am" but not "xn" is present. This
  421      * however would result in missing line breaks in files created by the
  422      * screen(1) utility.
  423      */
  424     if (am && !xn && lwidth > 2)
  425         lwidth--;
  426     lines = psize-2;
  427 
  428     fac = cac;
  429 #ifdef  DEBUG
  430     printf("%d\n", cac);
  431     for (i = 0; i < cac; i++)
  432         printf("%s\n", cav[i]);
  433 #endif
  434 
  435     if (cac == 0) {
  436         filename = "";
  437         linecnt = 0;
  438         f = stdin;
  439         page();
  440     } else {
  441         if (cac > 1)
  442             nameprint++;
  443         for (;;) {
  444             if ((f = fileopen(*cav, "r")) == (FILE *) NULL) {
  445                 errmsg("Can not open '%s'.\n", *cav);
  446             } else {
  447                 filename = *cav;
  448                 if (nameprint) {
  449                     printf("%s\n%s\n%s\n",
  450                             dcl, filename, dcl);
  451                     linecnt = 3;
  452                 } else
  453                     linecnt = 0;
  454                 page();
  455                 fclose(f);
  456                 f = (FILE *)0;
  457             }
  458             for (i = 0; ; ) {
  459                 if (direction == FORWARD) {
  460                     cac--, cav++;
  461                     if (cac <= 0)
  462                         reset_modes(), exit(0);
  463                 } else {
  464                     if (cac < fac) {
  465                         cac++, cav--;
  466                     }
  467                 }
  468                 if (silent) break;
  469                 if (i++ == 0) putchar('\n');
  470                 err:
  471 
  472                 start_standout();
  473                 gtprintf("NEXT FILE (%s)?", *cav);
  474                 end_standout();
  475                 fflush(stdout);
  476                 lines = psize-2;
  477 
  478                 switch (get_action()) {
  479 
  480                 case -1:
  481                     goto err;
  482                 case  1:
  483                     continue;
  484                 }
  485                 break;
  486             }
  487             clearline();
  488         }
  489     }
  490     reset_modes();
  491     exit(0);
  492     return (0); /* Keep lint happy */
  493 }
  494 
  495 LOCAL void
  496 page()
  497 {
  498     register int    c;
  499     register int    cnt;
  500     register unsigned char  *s;
  501     register unsigned char  **rctab;
  502         int ocolcnt = -1;
  503 
  504     rctab = ctab;
  505     ofpos = (off_t)0;
  506     len = 0;            /* fill_buf() on next nextc() */
  507     file_raise(f, FALSE);
  508 #ifdef  __nonono__          /* FreeBSD would read single bytes */
  509     setbuf(f, NULL);
  510 #endif
  511     lineno = 0;
  512     colcnt = 0;
  513 
  514     if (searchnext && do_search() < 0) {
  515         if (!more())
  516             return;
  517     }
  518 
  519     while ((c = nextc()) != EOF) {
  520         if (c < 0) {                /* -2 on error */
  521             errmsg("Error reading '%s'.\n", filename);
  522             return;
  523         }
  524         if (c == '_' && underline) {        /* underlining */
  525             if (peekc() != '\b') {
  526                 if (outchar('_'))
  527                     return;
  528                 continue;
  529             }
  530             getnextch();            /* it _is_ a ^H ! */
  531             if (peekc() == '_')
  532                 goto bold;
  533             underl++;
  534 
  535         } else if (c == '+' && underline && peekc() == '\b') {
  536             getnextch();
  537         } else if (c == '\r' &&
  538                 (autodos || dosmode) && peekc() == '\n') {
  539             /* EMPTY */
  540         } else if (c == '\n') {
  541             if (ocolcnt == 0 && colcnt == 0 && supressblank)
  542                 continue;
  543             ocolcnt = colcnt;
  544             lineno++;
  545             if (endline) {
  546                 if (outchar('$'))
  547                     return;
  548             }
  549             if (outchar('\n'))
  550                 return;
  551         } else if (c == '\t' && !tab) {
  552             cnt = 8 - (colcnt&7);
  553             while (--cnt >= 0)
  554                 if (outchar(' '))
  555                     return;
  556         } else if (peekc() == '\b' && underline) {
  557             getnextch();        /* ^H */
  558         bold:
  559             while (peekc() == c) {
  560                 getnextch();
  561                 if (peekc() == '\b')
  562                     getnextch();
  563                 else
  564                     break;
  565             }
  566             ungetch(c);
  567             standout++;
  568         } else {
  569             if (raw || iswprint(c)) {
  570                 if (outchar(c))
  571                     return;
  572             } else {
  573 #if MB_LEN_MAX > 1
  574                 int i = clen;
  575                 while (--i >= 0) {
  576                     s = rctab[*cp++];
  577                     while (*s)
  578                         if (outchar(*s++))
  579                             return;
  580                 }
  581 #else
  582                 s = rctab[c];
  583                 while (*s)
  584                     if (outchar(*s++))
  585                         return;
  586 #endif
  587             }
  588         }
  589     }
  590     fflush(stdout);
  591 }
  592 
  593 LOCAL int
  594 outchar(c)
  595     int c;
  596 {
  597 #if MB_LEN_MAX > 1
  598     unsigned char   b[MB_LEN_MAX];
  599     unsigned char   *p = b;
  600     int     l;
  601 
  602 
  603     l = wctomb((char *)b, c);
  604     if (l < 0) {
  605         l = 1;
  606         b[0] = '?';
  607     }
  608 #endif
  609 
  610     if (c == '\n') {
  611         if (len <= lwidth)
  612             fflush(stdout);
  613         if (++linecnt >= lines) {
  614             if (!more())
  615                 return (1);
  616             clearline();
  617             linecnt = 0;
  618         } else {
  619             putc('\n', stdout);
  620         }
  621         colcnt = 0;
  622         return (0);
  623     } else {
  624         int w = wcwidth(c);
  625 
  626         if (w < 0)
  627             w = 1;
  628         colcnt += w;
  629         if (colcnt > lwidth) {
  630             if (outchar('\n'))
  631                 return (1);
  632             colcnt = 1;
  633         }
  634         if (standout) {
  635             standout--;
  636             if (underl) {
  637                 underl--;
  638                 start_ul();
  639                 start_xstandout();
  640 #if MB_LEN_MAX > 1
  641                 while (--l >= 0)
  642                     putc(*p++, stdout);
  643 #else
  644                 putc(c, stdout);
  645 #endif
  646                 end_xstandout();
  647                 end_ul();
  648             } else {
  649                 start_xstandout();
  650 #if MB_LEN_MAX > 1
  651                 while (--l >= 0)
  652                     putc(*p++, stdout);
  653 #else
  654                 putc(c, stdout);
  655 #endif
  656                 end_xstandout();
  657             }
  658         } else if (underl) {
  659             underl--;
  660             start_ul();
  661 #if MB_LEN_MAX > 1
  662             while (--l >= 0)
  663                 putc(*p++, stdout);
  664 #else
  665             putc(c, stdout);
  666 #endif
  667             end_ul();
  668         } else {
  669 #if MB_LEN_MAX > 1
  670             while (--l >= 0)
  671                 putc(*p++, stdout);
  672 #else
  673             putc(c, stdout);
  674 #endif
  675         }
  676         return (0);
  677     }
  678 }
  679 
  680 LOCAL void
  681 moreprompt()
  682 {
  683     float   percent;
  684     off_t   size    = -1;
  685     off_t   pos = -1;
  686 
  687     lines = psize-2;
  688     if (f) {
  689         size = filesize(f);
  690         pos = filepos(f) - len;
  691     }
  692     start_standout();
  693     if (!*filename || !f || size < 0 || pos < 0)
  694         gtprintf("%s%c MORE?",
  695                 filename,
  696                 *filename ? ':' : '-');
  697     else {
  698         percent = (float)pos;
  699         percent /= (float)size;
  700         percent *= 100.0;
  701         gtprintf("%s%c %.1f %% MORE?",
  702                 filename,
  703                 *filename ? ':' : '-',
  704                 percent);
  705     }
  706     end_standout();
  707     fflush(stdout);
  708 }
  709 
  710 LOCAL BOOL
  711 more()
  712 {
  713     if (silent)
  714         return (TRUE);
  715     putchar('\n');
  716     for (;;) {
  717         moreprompt();
  718         switch (get_action()) {
  719 
  720         case  1:
  721             return (FALSE);
  722         case -1:
  723             continue;
  724         }
  725         ofpos = filepos(f)-len;
  726         break;
  727     }
  728     return (TRUE);
  729 }
  730 
  731 
  732 /*
  733  *  Return:
  734  *      -1  error
  735  *       0  continue this file
  736  *       1  stop on this file
  737  *  EXIT:
  738  *       on demand
  739  */
  740 LOCAL int
  741 get_action()
  742 {
  743     int c;
  744     char    buf[128];
  745 
  746     direction = FORWARD;
  747     searchnext = 0;
  748 
  749     switch (c = inwchar()) {
  750 
  751     case 'p':
  752     case 'P':
  753     case 'n':
  754     case 'N':
  755         direction = (c == 'P' || c == 'p');
  756         clearline();
  757         return (1);
  758     case 's':
  759     case 'S':
  760     case 003 :              /* ^C  */
  761     case 004 :              /* ^D  */
  762     case 034 :              /* ^\  */
  763     case 0177:              /* DEL */
  764     case EOF :
  765         fixtty(0);
  766         /* NOTREACHED */
  767     case 'Y':
  768     case 'y':
  769     case '\r':
  770     case '\n':
  771     case ' ':
  772         if (clear)
  773             clearscreen();
  774         break;
  775     case 'H':
  776     case 'h':
  777         lines = lines/2;
  778         break;
  779     case 'Q':
  780     case 'q':
  781         lines = lines/4;
  782         break;
  783     case 'L':
  784     case 'l':
  785         lines = 1;
  786         break;
  787     case '1':
  788     case '2':
  789     case '3':
  790     case '4':
  791     case '5':
  792     case '6':
  793     case '7':
  794     case '8':
  795     case '9':
  796         lines = c-'0';
  797         break;
  798     case '/':
  799         clearline();
  800         printf("/");
  801         fflush(stdout);
  802         if (!read_pattern())
  803             return (-1);
  804         /* FALLTHRU */
  805     case 'r':
  806     case 'R':
  807         if (f == (FILE *)0)
  808             searchnext = 1;
  809         else if (do_search() < 0)
  810             return (-1);
  811         break;
  812     case '\f':
  813         redraw();   /* XXX eigentlich nicht ?? */
  814         break;
  815     case '?':
  816         clearline();
  817         onlinehelp();
  818         return (-1);
  819     case '!':
  820         clearline();
  821         sprintf(buf, "%s -t", shell);
  822         (void) system(buf);
  823         return (-1);
  824     case 'v':
  825     case 'V':
  826         if (f != stdin) {
  827             clearline();
  828             sprintf(buf, "%s +%d %s", editor, lineno, filename);
  829             printf("%s", buf);
  830             fflush(stdout);
  831             (void) system(buf);
  832             return (-1);
  833         }
  834         /* FALLTHRU */
  835     default:
  836         if (!nobeep)
  837             putchar('\007');
  838         clearline();
  839         return (-1);
  840     }
  841     return (0);
  842 }
  843 
  844 LOCAL void
  845 onlinehelp()
  846 {
  847     /* BEGIN CSTYLED */
  848     gtprintf("\n---------------------------------------------------------------\n");
  849     gtprintf("N, n          Next File\n");
  850     gtprintf("P, p          Previous File\n");
  851     gtprintf("S, s, ^C, ^D, ^\\, DEL    Exit (stop)\n");
  852     gtprintf("Y, y, <return>, <space>   Display next screenfull of text\n");
  853     gtprintf("H, h          Display next half screenfull of text\n");
  854     gtprintf("Q, q          Display next quarter screenfull of text\n");
  855     gtprintf("L, l          Display next line of text\n");
  856     gtprintf("1-9           Display next <n> lines of text\n");
  857     gtprintf("/pattern      Search for <pattern>\n");
  858     gtprintf("R, r          Re-search for <pattern>\n");
  859     gtprintf("^L            Redraw screen\n");
  860     gtprintf("?         Display this message\n");
  861     gtprintf("!         Execute command\n");
  862     gtprintf("V, v          Edit file\n");
  863     gtprintf("---------------------------------------------------------------\n");
  864     /* END CSTYLED */
  865 }
  866 
  867 LOCAL void
  868 redraw()
  869 {
  870     if (f && fileseek(f, ofpos) < 0) {
  871         if (!nobeep)
  872             putchar('\007');
  873         clearline();
  874         return;
  875     }
  876     len = 0;
  877     clearscreen();
  878 }
  879 
  880 LOCAL int
  881 inchar()
  882 {
  883     char    c;
  884     int ret = 0;
  885 
  886     c = '\004';     /* return ^D on EOF */
  887     do {
  888 #   ifdef   USE_GETCH
  889         c = getch();    /* DOS console input    */
  890 #   else
  891         ret = read(tty, &c, 1);
  892 #   endif
  893     } while (ret < 0 && geterrno() == EINTR);
  894     if (ret == 0)
  895         return (EOF);
  896     return (c);
  897 }
  898 
  899 #if MB_LEN_MAX > 1
  900 /*
  901  * Get next wide character from tty
  902  */
  903 LOCAL int
  904 inwchar()
  905 {
  906     register int    cur_max = MB_CUR_MAX;
  907     register int    i;
  908     int     mlen;
  909     wchar_t     c = -1;
  910     char        cstr[MB_LEN_MAX];
  911     char        *csp;
  912     int     ic;
  913 
  914     (void) mbtowc(NULL, NULL, 0);
  915     for (i = 1, csp = cstr; i <= cur_max; i++) {
  916         ic = inchar();
  917         if (ic == EOF)
  918             break;
  919         *csp++ = (char)ic;
  920         mlen = mbtowc(&c, cstr, i);
  921         if (mlen >= 0)
  922             break;
  923         (void) mbtowc(NULL, NULL, 0);
  924     }
  925 #ifdef  _NEXTWC_DEBUG
  926     fprintf(stderr, "C %d %x\n", c, c);
  927 #endif
  928     return ((int)c);
  929 }
  930 #endif
  931 
  932 
  933 #ifndef nextc
  934 LOCAL int
  935 nextc()
  936 {
  937     if (--len >= 0) {
  938         return ((int) *bp++);
  939     } else {
  940         if (fill_buf() <= 0)
  941             return (len == 0 ? EOF : -2);
  942     }
  943     len--;
  944     return ((int) *bp++);
  945 }
  946 #endif
  947 
  948 #if MB_LEN_MAX > 1
  949 /*
  950  * Read the next multi byte character from the buffer.
  951  * If the buffer is empty or if less than a multi byte character is inside,
  952  * it is refilled. When an illegal byte sequence is discovered, a single
  953  * byte is removed from the buffer in hope to be able to resync.
  954  */
  955 LOCAL int
  956 nextwc()
  957 {
  958     BOOL    eof = FALSE;
  959     int mlen;
  960     wchar_t c;
  961 
  962     if (len <= 0) {
  963         int olen;
  964 again:
  965         olen = len;
  966         if (fill_buf() <= 0) {
  967             return (len == 0 ? EOF : -2);
  968         } else if (len > 0 && olen == len) {
  969             eof = TRUE;
  970         }
  971     }
  972     mlen = mbtowc(&c, (char *)bp, len);
  973     if (mlen >= 0) {
  974         if (mlen == 0)
  975             mlen = 1;
  976         clen = mlen;
  977         cp = bp;
  978         bp += mlen;
  979         len -= mlen;
  980         return (c);
  981     } else {
  982         mbtowc(NULL, NULL, 0);
  983         if (len < MB_CUR_MAX && !eof) {
  984             seterrno(0);
  985             goto again;
  986         }
  987         clen = 1;
  988         cp = bp;
  989         bp++;
  990         len--;
  991 #ifdef  EILSEQ
  992         if (geterrno() == EILSEQ) {
  993             return (*cp);
  994         }
  995 #endif
  996     }
  997     return (-2);
  998 }
  999 
 1000 /*
 1001  * The same as nextwc(), but the buffer is untouched.
 1002  */
 1003 LOCAL int
 1004 peekwc()
 1005 {
 1006     BOOL    eof = FALSE;
 1007     int mlen;
 1008     wchar_t c;
 1009 
 1010     if (len <= 0) {
 1011         int olen;
 1012 again:
 1013         olen = len;
 1014         if (fill_buf() <= 0) {
 1015             return (len == 0 ? EOF : -2);
 1016         } else if (len > 0 && olen == len) {
 1017             eof = TRUE;
 1018         }
 1019     }
 1020     mlen = mbtowc(&c, (char *)bp, len);
 1021     if (mlen >= 0) {
 1022         if (mlen == 0)
 1023             mlen = 1;
 1024         pclen = mlen;
 1025         pcp = bp;
 1026         return (c);
 1027     } else {
 1028         mbtowc(NULL, NULL, 0);
 1029         if (len < MB_CUR_MAX && !eof) {
 1030             seterrno(0);
 1031             goto again;
 1032         }
 1033         pclen = 1;
 1034         pcp = bp;
 1035 #ifdef  EILSEQ
 1036         if (geterrno() == EILSEQ) {
 1037             return (*pcp);
 1038         }
 1039 #endif
 1040     }
 1041     return (-2);
 1042 }
 1043 #endif
 1044 
 1045 #ifndef ungetch
 1046 LOCAL int
 1047 ungetch(c)
 1048     int c;
 1049 {
 1050     if (c == EOF)
 1051         return (c);
 1052     /*
 1053      * If bp is at the beginning of the buffer, this may go
 1054      * to one character before the buffer (see below).
 1055      */
 1056     len++;
 1057     return (*--bp = c);
 1058 }
 1059 #endif
 1060 
 1061 #if MB_LEN_MAX > 1
 1062 /*
 1063  * Return the character back to the buffer.
 1064  */
 1065 LOCAL int
 1066 ungetwch(c)
 1067     int c;
 1068 {
 1069     unsigned char   b[MB_LEN_MAX];
 1070     unsigned char   *p;
 1071     int     l;
 1072 
 1073     if (c == EOF)
 1074         return (c);
 1075 
 1076     l = wctomb((char *)b, c);
 1077     if (l < 0) {
 1078         l = 1;
 1079         b[0] = '?';
 1080     }
 1081     len += l;
 1082     p = &b[l];
 1083     while (--l >= 0)
 1084         *--bp = *--p;
 1085 
 1086     return (c);
 1087 }
 1088 
 1089 /*
 1090  * Consume the last character fetched by peekwc()
 1091  */
 1092 LOCAL void
 1093 getnextwch()
 1094 {
 1095     len -= pclen;
 1096     bp += pclen;
 1097     cp = pcp;
 1098     pclen = 0;
 1099 }
 1100 #endif
 1101 
 1102 LOCAL int
 1103 fill_buf()
 1104 {
 1105     int     i;
 1106 
 1107     /*
 1108      * Allow ungetch() to always put back one character.
 1109      * This is done by reserving one char before the normal
 1110      * space in "mybuf".
 1111      */
 1112 
 1113     if (len > 0) {
 1114         unsigned char   *p = bp;
 1115 
 1116         /*
 1117          * Move a partial character left at the end of the buffer
 1118          * to the space before the beginning of the buffer.
 1119          */
 1120         if (len > MB_LEN_MAX)
 1121             len = MB_LEN_MAX;
 1122         p = &mybuf[(2*MB_LEN_MAX) - len];
 1123         for (i = len; --i >= 0; ) {
 1124             *p++ = *bp++;
 1125         }
 1126         bp = &mybuf[(2*MB_LEN_MAX) - len];
 1127     } else {
 1128         len = 0;
 1129         bp = &mybuf[(2*MB_LEN_MAX)];
 1130     }
 1131     i = fileread(f, &mybuf[2*MB_LEN_MAX], sizeof (mybuf) - 2*MB_LEN_MAX);
 1132     if (i < 0)
 1133         return (i);
 1134     return (len += i);
 1135 }
 1136 
 1137 LOCAL BOOL
 1138 read_pattern()
 1139 {
 1140         int patlen;
 1141     register int    c;
 1142     register int    count = 0;
 1143 #if MB_LEN_MAX > 1
 1144     register wchar_t *s = searchbuf;
 1145     unsigned char   b[MB_LEN_MAX];
 1146 #else
 1147     register char   *s = searchbuf;
 1148 #endif
 1149     register unsigned char  *p;
 1150     register int    i;
 1151 
 1152     while ((c = inwchar()) != EOF &&
 1153             count++ < (SEARCHSIZE - 1) &&
 1154             c != '\004' && c != '\r' && c != '\n') {
 1155 
 1156         if (c == 0177) {        /* DEL */
 1157             if (s == searchbuf) {
 1158                 if (!nobeep)
 1159                     putchar('\007');
 1160             } else {
 1161                 --count;
 1162                 --s;
 1163 #if MB_LEN_MAX > 1 && defined(HAVE_WCWIDTH)
 1164                 if (iswprint(*s))
 1165                     i = wcwidth(*s);
 1166                 else
 1167                     i = csize[*s & 0xFF];
 1168 #else
 1169                 i = csize[*s & 0xFF];
 1170 #endif
 1171                 for (; --i >= 0; )
 1172                     printf("\b \b");
 1173             }
 1174             fflush(stdout);
 1175         } else {
 1176 #if MB_LEN_MAX > 1 && defined(HAVE_WCWIDTH)
 1177             int l;
 1178 
 1179             if (iswprint(c)) {
 1180                 l = wctomb((char *)b, c);
 1181                 if (l < 1) {
 1182                     p = ctab[c & 0xFF];
 1183                 } else {
 1184                     p = b;
 1185                     b[l] = '\0';
 1186                 }
 1187             } else {
 1188                 p = ctab[c & 0xFF];
 1189             }
 1190 #else
 1191             p = ctab[c & 0xFF];
 1192 #endif
 1193             *s++ = c;
 1194             while (*p)
 1195                 putchar(*p++);
 1196             fflush(stdout);
 1197         }
 1198     }
 1199     *s = '\0';
 1200     if (aux)
 1201         free((char *)aux);
 1202 #if MB_LEN_MAX > 1
 1203     patlen = wcslen(searchbuf);
 1204 #else
 1205     patlen = strlen(searchbuf);
 1206 #endif
 1207     aux = (int *) malloc(patlen * sizeof (int));
 1208     state = (int *) malloc((patlen+1) * sizeof (int));
 1209 #if MB_LEN_MAX > 1
 1210     alt = patwcompile(searchbuf, patlen, aux);
 1211 #else
 1212     alt = patcompile((unsigned char *)searchbuf, patlen, aux);
 1213 #endif
 1214     if (!alt) {
 1215         gtprintf("Bad Pattern.\r");
 1216         fflush(stdout);
 1217         sleep(1);
 1218         return (FALSE);
 1219     }
 1220     return (TRUE);
 1221 }
 1222 
 1223 LOCAL int
 1224 do_search()
 1225 {
 1226     register unsigned char *lp;
 1227     register unsigned char *rbp;
 1228         unsigned char *sp;
 1229     register int    rest = len;
 1230         off_t   curpos;
 1231         BOOL    skipping = FALSE;
 1232         int newlines = 0;
 1233     unsigned char   sbuf[P_BUFSIZE];
 1234 
 1235     if (!alt) {
 1236         if (!nobeep)
 1237             putchar('\007');
 1238         gtprintf("No previous search.\r");
 1239         fflush(stdout);
 1240 #ifdef  DEBUG
 1241         sleep(1);
 1242 #endif
 1243         return (-1);
 1244     }
 1245     curpos = filepos(f)-len;
 1246 
 1247 #ifdef  DEBUG
 1248     fprintf(stderr,
 1249         "Efilepos: %lld len: %d bp: 0x%X\n",
 1250         (Llong)filepos(f), len, bp);
 1251 #endif
 1252     for (;;) {
 1253         if (rest < MB_LEN_MAX) {
 1254             int olen;
 1255             /*
 1256              * We may be operating on a copy and thus
 1257              * need to set "len" to the remaining characters to
 1258              * tell fill_buf() that it needs to do a refill.
 1259              */
 1260             olen = len = rest;
 1261             if (fill_buf() <= 0 || olen == len) {
 1262                 if (!nobeep)
 1263                     putchar('\007');
 1264                 gtprintf("Pattern not found.\r");
 1265                 fflush(stdout);
 1266                 if (f && fileseek(f, curpos) >= 0)
 1267                     len = 0;
 1268                 return (-1);
 1269             }
 1270             newlines = 0;
 1271         }
 1272         rbp = lp = sp = bp;
 1273         rest = len;
 1274         if (underline &&
 1275             findbytes(lp, rest, '\b') != NULL) {
 1276             rest = unul(sbuf, rbp, len);
 1277             rbp = lp = sp = sbuf;
 1278         }
 1279         for (; rest > 0; rest--) {
 1280 #if MB_LEN_MAX > 1
 1281             if (patmbmatch(searchbuf,
 1282 #else
 1283             if (patmatch((unsigned char *)searchbuf,
 1284 #endif
 1285                     aux, rbp, 0, rest, alt, state)) {
 1286 #ifdef  DEBUG
 1287             fprintf(stderr,
 1288                 "Afilepos: %lld rest: %d rbp: 0x%X lp: 0x%X\n",
 1289                 (Llong)filepos(f), rest, rbp, lp);
 1290 #endif
 1291                 if (skipping) {
 1292                     printf("\n");
 1293                     if (sp == bp) {
 1294                         bp = lp;
 1295                         len = rest + (rbp - lp);
 1296                     } else {
 1297                         lp = bp;
 1298                         rbp = &bp[len];
 1299                         while (--newlines >= 0) {
 1300                             unsigned char *olp = lp;
 1301                             if ((lp = (Uchar *)
 1302                                 findbytes(lp,
 1303                                     rbp - lp,
 1304                                     '\n')) ==
 1305                                     NULL) {
 1306                                 lp = olp;
 1307                                 break;
 1308                             }
 1309                             lp++;
 1310                         }
 1311                         bp = lp;
 1312                         len = rbp - lp;
 1313                     }
 1314                 }
 1315 #ifdef  DEBUG
 1316                 fprintf(stderr,
 1317                     "Afilepos: %lld len: %d bp: 0x%X\n",
 1318                     (Llong)filepos(f), len, bp);
 1319 #endif
 1320                 return (0);
 1321             }
 1322             if (*rbp++ == '\n') {
 1323                 /*
 1324                  * Remember last line start pointer.
 1325                  */
 1326                 lp = rbp;
 1327                 newlines++;
 1328                 if (!skipping) {
 1329                     skipping = TRUE;
 1330                     gtprintf("skipping...\r");
 1331                     fflush(stdout);
 1332                 }
 1333 #ifdef  DEBUG
 1334                 fprintf(stderr, ".");
 1335 #endif
 1336             }
 1337         }
 1338     }
 1339 }
 1340 
 1341 /*
 1342  * Remove underlining and overstriking sequences.
 1343  * Put the result into "ob".
 1344  */
 1345 LOCAL int
 1346 unul(ob, ib, amt)
 1347     register Uchar  *ob;
 1348     register Uchar  *ib;
 1349     register int    amt;
 1350 {
 1351     register Uchar  *oob = ob;
 1352         wchar_t c;
 1353     register ssize_t wclen;
 1354 
 1355     mbtowc(NULL, NULL, 0);
 1356     while (amt > 0) {
 1357         wclen = mbtowc(&c, (char *)ib, amt);
 1358         if (wclen < 1) {
 1359             *ob++ = *ib++;
 1360             amt--;
 1361             continue;
 1362         }
 1363         amt -= wclen;
 1364         ib += wclen;
 1365         if (c == '_') {             /* underlining */
 1366             if (ib[0] != '\b') {
 1367                 ib -= wclen;
 1368                 while (--wclen >= 0)
 1369                     *ob++ = *ib++;
 1370                 continue;
 1371             }
 1372             ib++;               /* eat ^H */
 1373             amt--;
 1374             wclen = mbtowc(&c, (char *)ib, amt);
 1375             if (wclen > 0 && c == '_') {    /* _ ^H _ */
 1376                 goto bold;
 1377             }
 1378         } else if (c == '+' && ib[0] == '\b') { /* overstriking */
 1379             /* + ^H o */
 1380 
 1381             ib++;               /* eat ^H */
 1382             amt--;
 1383         } else if (ib[0] == '\b') {
 1384             wchar_t c2;
 1385             ssize_t wclen2;
 1386             Uchar   *oib;
 1387 
 1388             /* N ^H N ^H N ^H N */
 1389             ib++;               /* eat ^H */
 1390             amt--;
 1391         bold:
 1392             oib = ib - (wclen +1);
 1393             while (amt > 0) {
 1394                 wclen2 = mbtowc(&c2, (char *)ib, amt);
 1395                 if (wclen2 < 1)
 1396                     break;
 1397                 if (c2 != c)
 1398                     break;
 1399                 ib += wclen2;       /* eat c2 */
 1400                 amt -= wclen2;
 1401                 if (ib[0] == '\b') {    /* Check for ^H */
 1402                     ib++;       /* eat ^H */
 1403                     amt--;
 1404                 } else
 1405                     break;
 1406             }
 1407             while (--wclen >= 0)
 1408                 *ob++ = *oib++;
 1409         } else {
 1410             ib -= wclen;
 1411             while (--wclen >= 0)
 1412                 *ob++ = *ib++;
 1413         }
 1414     }
 1415     *ob = '\0';
 1416     return (ob - oob);
 1417 }
 1418 
 1419 char    stbuf[1024];    /* Bufer for termcap array (i.e. so and se) */
 1420 
 1421 LOCAL void
 1422 init_termcap()
 1423 {
 1424     char    *tname;
 1425     char    *sbp;
 1426 
 1427     sbp = stbuf;
 1428 
 1429     if ((tname = getenv("TERM")) && tgetent(NULL, tname) == 1) {
 1430         has_termcap = TRUE;
 1431 
 1432         so = tgetstr("so", &sbp);   /* start standout */
 1433         se = tgetstr("se", &sbp);   /* end standout */
 1434         us = tgetstr("us", &sbp);   /* start underline */
 1435         ue = tgetstr("ue", &sbp);   /* end underline */
 1436         md = tgetstr("md", &sbp);   /* start bold */
 1437         me = tgetstr("me", &sbp);   /* end attributes */
 1438         ce = tgetstr("ce", &sbp);   /* clear endline */
 1439         cl = tgetstr("cl", &sbp);   /* clear screen */
 1440         li = tgetnum("li");     /* lines on screen */
 1441         co = tgetnum("co");     /* columns on screen */
 1442         am = tgetflag("am");        /* automatic margins */
 1443         xn = tgetflag("xn");        /* newline ignored > 80 */
 1444         if (so != NULL && se != NULL) {
 1445             has_standout = TRUE;
 1446         } else {
 1447             so = se = NULL;
 1448         }
 1449         if (md != NULL && me != NULL) {
 1450             has_bold = TRUE;
 1451         } else {
 1452             md = NULL;
 1453         }
 1454         if (us != NULL && ue != NULL) {
 1455             has_ul = TRUE;
 1456         } else {
 1457             us = ue = NULL;
 1458         }
 1459         if (has_bold) {
 1460             xso = md;
 1461             xse = me;
 1462         } else if (has_standout) {
 1463             xso = so;
 1464             xse = se;
 1465         } else {
 1466             xso = xse = NULL;
 1467         }
 1468         if (debug) {
 1469             printf("so: %d bo: %d ul: %d\n",
 1470                 has_standout, has_bold, has_ul);
 1471             sleep(1);
 1472         }
 1473     }
 1474 }
 1475 
 1476 LOCAL int
 1477 oc(c)
 1478     int c;
 1479 {
 1480     return (putchar(c));
 1481 }
 1482 
 1483 LOCAL void
 1484 start_standout()
 1485 {
 1486     tputs(so, 1, oc);
 1487 }
 1488 
 1489 LOCAL void
 1490 end_standout()
 1491 {
 1492     tputs(se, 1, oc);
 1493 }
 1494 
 1495 #ifdef  __needed__
 1496 LOCAL void
 1497 start_bold()
 1498 {
 1499     tputs(md, 1, oc);
 1500 }
 1501 #endif
 1502 
 1503 LOCAL void
 1504 end_attr()
 1505 {
 1506     tputs(me, 1, oc);
 1507 }
 1508 
 1509 LOCAL void
 1510 start_xstandout()
 1511 {
 1512     tputs(xso, 1, oc);
 1513 }
 1514 
 1515 LOCAL void
 1516 end_xstandout()
 1517 {
 1518     tputs(xse, 1, oc);
 1519 }
 1520 
 1521 LOCAL void
 1522 start_ul()
 1523 {
 1524     if (has_ul)
 1525         tputs(us, 1, oc);
 1526 }
 1527 
 1528 LOCAL void
 1529 end_ul()
 1530 {
 1531     if (has_ul)
 1532         tputs(ue, 1, oc);
 1533 }
 1534 
 1535 LOCAL void
 1536 clearline()
 1537 {
 1538     int i;
 1539 
 1540     if (silent) {
 1541         putchar('\n');
 1542         return;
 1543     }
 1544     putchar('\r');
 1545     if (ce) {
 1546         tputs(ce, 1, oc);
 1547     } else {
 1548         for (i = 1; i < lwidth; i++)
 1549             putchar(' ');
 1550         putchar('\r');
 1551     }
 1552     fflush(stdout);
 1553 }
 1554 
 1555 LOCAL void
 1556 clearscreen()
 1557 {
 1558     if (cl)
 1559         tputs(cl, 1, oc);
 1560 }
 1561 
 1562 LOCAL void
 1563 init_tty_size()
 1564 {
 1565 #ifdef no_TIOCGSIZE
 1566 #if defined(TIOCGSIZE) || defined(TIOCGWINSZ)
 1567 #ifdef  TIOCGWINSZ
 1568     struct      winsize ws;
 1569 
 1570     ws.ws_rows = 0;
 1571     if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) >= 0) {
 1572         if (ws.ws_rows) {
 1573             psize = ws.ws_rows;
 1574             lwidth = ws.ws_cols;
 1575         }
 1576     }
 1577 #else
 1578     struct      ttysize ts;
 1579 
 1580     ts.ts_lines = 0;
 1581     if (ioctl(STDOUT_FILENO, TIOCGSIZE, (char *)&ts) >= 0) {
 1582         if (ts.ts_lines) {
 1583             psize = ts.ts_lines;
 1584             lwidth = ts.ts_cols;
 1585         }
 1586     }
 1587 #endif
 1588 #endif
 1589 #else
 1590     if (psize == 0) {
 1591         if (li > 0 && li < 1000)
 1592             psize = li;
 1593         else
 1594             psize = DEF_PSIZE;
 1595     }
 1596     if (lwidth == 0) {
 1597         if (co > 0 && co < 1000)
 1598             lwidth = co;
 1599         else
 1600             lwidth = DEF_LWIDTH;
 1601     }
 1602 #endif
 1603 }
 1604 
 1605 LOCAL int
 1606 get_modes()
 1607 {
 1608 #   ifdef   USE_V7_TTY
 1609     return (ioctl(STDOUT_FILENO, TIOCGETP, &old));
 1610 
 1611 #   else    /* USE_V7_TTY */
 1612 
 1613 #   ifdef   USE_TERMIOS
 1614 #   ifdef   TCSANOW
 1615     return (tcgetattr(STDOUT_FILENO, &old));
 1616 #   else
 1617     return (ioctl(STDOUT_FILENO, TCGETS, &old));
 1618 #   endif
 1619 #   else    /* USE_TERMIOS */
 1620     return (0);
 1621 #   endif   /* USE_TERMIOS */
 1622 #   endif   /* USE_V7_TTY */
 1623 }
 1624 
 1625 LOCAL void
 1626 set_modes()
 1627 {
 1628 #ifdef  HAVE__DEV_TTY
 1629     if (tty < 0 && (tty = open("/dev/tty", O_RDONLY)) < 0)
 1630         errmsg("Can't open '/dev/tty'\n");
 1631 #endif
 1632     if (tty < 0)
 1633         tty = fileno(stderr);
 1634 
 1635     /*
 1636      * Do signal handling only if they are not already
 1637      * ignored.
 1638      */
 1639     if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
 1640         signal(SIGINT, fixtty);
 1641 #ifdef  SIGQUIT
 1642         signal(SIGQUIT, fixtty);
 1643 #endif
 1644 #ifdef  SIGTSTP
 1645         if (signal(SIGTSTP, SIG_IGN) == SIG_DFL)
 1646             signal(SIGTSTP, tstp);
 1647 #endif
 1648     }
 1649 #   ifdef   USE_V7_TTY
 1650     movebytes(&old, &new, sizeof (old));
 1651 #       ifdef   LPASS8
 1652     {
 1653         int lmode;
 1654 
 1655         ioctl(STDOUT_FILENO, TIOCLGET, &lmode);
 1656         if (lmode & LPASS8)
 1657             raw8 = TRUE;
 1658     }
 1659 #       else
 1660     if (old.sg_flags & RAW)
 1661         raw8 = TRUE;
 1662 #       endif
 1663     new.sg_flags |= CBREAK;
 1664     new.sg_flags &= ~ECHO;
 1665     if (ioctl(STDOUT_FILENO, TIOCSETN, &new) < 0)
 1666         comerr("Can not set new modes.\n");
 1667 
 1668 #   else    /* USE_V7_TTY */
 1669 
 1670 #   ifdef   USE_TERMIOS
 1671     movebytes(&old, &new, sizeof (old));
 1672     if (!(old.c_iflag & ISTRIP))
 1673         raw8 = TRUE;
 1674 #ifdef  __never__
 1675     new.c_iflag = ICRNL;
 1676     new.c_oflag = (OPOST|ONLCR);
 1677     new.c_lflag = ISIG;
 1678 #endif
 1679     new.c_lflag &= ~(ICANON|ECHO);
 1680     new.c_cc[VMIN] = 1;
 1681     new.c_cc[VTIME] = 0;
 1682 #   ifdef   TCSANOW
 1683     if (tcsetattr(STDOUT_FILENO, TCSADRAIN, &new) < 0)
 1684 #   else
 1685     if (ioctl(STDOUT_FILENO, TCSETSW, &new) < 0)
 1686 #   endif
 1687         comerr("Can not set new modes.\n");
 1688 #   endif   /* USE_TERMIOS */
 1689 
 1690 #   endif   /* USE_V7_TTY */
 1691 
 1692 #ifdef  CATCH_SIGCONT_here
 1693 #ifdef  SIGCONT
 1694     signal(SIGONT, redraw); /* XXX ??? */
 1695 #endif
 1696 #endif
 1697 }
 1698 
 1699 /*
 1700  * Reset to previous tty modes.
 1701  */
 1702 LOCAL void
 1703 reset_modes()
 1704 {
 1705     if (!silent) {
 1706 #   ifdef   USE_V7_TTY
 1707         if (ioctl(STDOUT_FILENO, TIOCSETN, &old) < 0)
 1708 
 1709 #   else    /* USE_V7_TTY */
 1710 
 1711 #   ifdef   USE_TERMIOS
 1712 #       ifdef   TCSANOW
 1713         if (tcsetattr(STDOUT_FILENO, TCSADRAIN, &old) < 0)
 1714 #       else
 1715         if (ioctl(STDOUT_FILENO, TCSETSW, &old) < 0)
 1716 #       endif
 1717 #   else    /* USE_TERMIOS */
 1718         if (0)
 1719 #   endif   /* USE_TERMIOS */
 1720 #   endif   /* USE_V7_TTY */
 1721             comerr("Can not reset old modes.\n");
 1722     }
 1723 }
 1724 
 1725 /*
 1726  * Fix tty and exit.
 1727  */
 1728 LOCAL void
 1729 fixtty(sig)
 1730     int sig;
 1731 {
 1732     end_standout();
 1733     end_attr();
 1734     end_ul();
 1735     clearline();
 1736     reset_modes();
 1737     exit(0);
 1738 }