"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.

    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 }