home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume7 / dirstack.csh / shdir.c < prev    next >
C/C++ Source or Header  |  1987-01-18  |  24KB  |  909 lines

  1. /**************************************************************************
  2. *
  3. * File name:    shdir.c
  4. *
  5. * Author:    Paul Lew, General Systems Group, Inc. Salem, NH
  6. * Created at:    02/17/86  04:39 PM
  7. *
  8. * Description:    This program will take input argument from C shell directory
  9. *        stack and display on screen.  User can optionally select a
  10. *        directory to connect to.
  11. *    
  12. * Environment:    4.2 BSD Unix (under Pyramid OSx 2.5)
  13. *
  14. * Usage:    shdir [-r] [-sxxx] [-bh] [-br] [-bd] [-v] `dirs` <CR>
  15. *        where:
  16. *            -v    display version number
  17. *            -bh    use highlighted space for box
  18. *            -br    use reverse video space for box
  19. *            -bd    use dash char for box
  20. *            -r    use scroll if terminal support
  21. *            -sxxx    select directory xxx. If xxx not found or
  22. *                not specified, directory stack will be
  23. *                displayed to allow for selection.
  24. *
  25. * Update History:
  26. *
  27. *      Date        Description                    By
  28. *    --------    ------------------------------------------------    ---
  29. *    02/17/86    Ver 1.0, Initial version                Lew
  30. *    02/28/86    Ver 1.1, add h, k for going backwards            Lew
  31. *    07/01/86    Ver 2.0, modify to work with termcap            Lew
  32. *    10/06/86    Ver 2.1, port to VAX BSD 4.2                Lew
  33. *    10/09/86    Ver 3.0, add scrolling capability            Lew
  34. *    10/13/86    Ver 3.1, add different options for different box style    Lew
  35. *    10/14/86    Ver 3.2, add string search feature            Lew
  36. *
  37. * Build:    cc -s -o shdir shdir.c -ltermcap
  38. *
  39. ***************************************************************************/
  40. #include    <stdio.h>
  41. #include    <sgtty.h>
  42. #include    <ctype.h>
  43. #include    <strings.h>
  44. #include    <sys/file.h>
  45.  
  46. #define        YES    1
  47. #define        NO    0
  48. #define        EOS    '\0'            /* end of string */
  49. #define        SPACE    ' '
  50. #define        BS    '\010'
  51. #define        ESC    '\033'
  52. #define        RETURN    '\015'
  53. #define        NEWLINE    '\012'
  54.  
  55. #define    when        break; case
  56. #define    otherwise    break;default
  57.  
  58. char        *Version = "shdir Version 3.2  10/16/86  10:47 AM";
  59. char        *Author =
  60.          "Paul Lew, General Systems Group   UUCP: decvax!gsg!lew";
  61.  
  62. FILE        *Termfp;        /* terminal file pointer */
  63.  
  64. #define        MAXDIR    22        /* not over typical screen size */
  65. int        Maxdir = MAXDIR;    /* max # of directory to display */
  66.  
  67. #define        MAXBAR    200
  68.  
  69. char        Bar [MAXBAR];        /* vanilla bar */
  70. char        Topbar [MAXBAR];    /* top bar string */
  71. char        Botbar [MAXBAR];    /* bottom bar string */
  72. char        Vbar [20];        /* vertical bar string */
  73.  
  74. char        Tab [80];
  75. int        Ntab;
  76. char        Stack [1024];
  77. char        *Dirstack [MAXDIR];    /* pointers to directory entries */
  78. int        Arglen [MAXDIR];    /* lengths of each entry */
  79. int        Dircount = 0;
  80. int        Topsel = 0;        /* start selection index */
  81.  
  82. /* Curpos_query is a string to be sent to VT100 to get current cursor
  83.    position report.  There is no such field in termcap, you have to hack
  84.    the routine for other terminals since they might have different report
  85.    format */
  86.  
  87. char        *Curpos_query = "\033[6n"; /* cursor position query */
  88. int        Line;            /* # of lines per screen */
  89. int        Fst_line = 0;        /* if %i specified Fst_line = 1 */
  90.  
  91. struct    sgttyb    Scd;
  92. int        Sno = 1;        /* first entry start index */
  93.  
  94. int        Select = NO;        /* YES = select entry */
  95. int        Scroll = NO;        /* YES = use scroll feature if exist */
  96. int        Tabstop = 8;        /* default tab-stop */
  97.  
  98. char        *Search_string = NULL;    /* select search string */
  99. int        Schlen = 0;        /* search string length */
  100. int        Str_total = 0;        /* total matched search string */
  101. int        Str_idx [MAXDIR];    /* string index */
  102.  
  103. #define    BOX_REVERSE    1
  104. #define    BOX_HIGHLITE    2
  105. #define    BOX_GRAPH    3
  106. #define    BOX_DASH    4
  107.  
  108. int        Boxstyle = BOX_GRAPH;    /* default box style */
  109.  
  110. struct    tcap    {
  111.     char        tc_id [3];    /* key for capability    */
  112.     unsigned char    tc_delay;    /* # of msec to delay    */
  113.     char        *tc_str;    /* ptr to Tc_str area    */
  114.     unsigned char    tc_len;        /* length of tc_str    */
  115.     };
  116.  
  117. static    char    Termcap [1024];
  118. static    char    Tstr [1024];        /* buffer for real escape sequence */
  119. static    char    *Tsp = Tstr;        /* pointer to be used by tgetstr */
  120. static    int    Tcap_count = 0;        /* # of entries extracted */
  121.  
  122. /*---------------- You may want to modify the following ----------------*/
  123.  
  124. #define        AC    0
  125. #define        AE    1
  126. #define        AS    2
  127. #define        LE    3
  128. #define        ND    4
  129. #define        NL    5
  130. #define        UP    6
  131. #define        SR    7
  132. #define        SC    8
  133. #define        RC    9
  134. #define        CS    10
  135. #define        MR    11
  136. #define        MD    12
  137. #define        ME    13
  138. #define        BAD    14
  139.  
  140. static    struct    tcap Tcap [] = {
  141.         { "ac",    0, NULL, 0 },    /* alternate chars        */
  142.         { "ae",    0, NULL, 0 },    /* exit alternate char set    */
  143.         { "as",    0, NULL, 0 },    /* start alternate char set    */
  144.         { "le", 0, NULL, 0 },    /* cursor left (CTRL H)        */
  145.         { "nd", 0, NULL, 0 },    /* cursor right            */
  146.         { "nl", 0, NULL, 0 },    /* cursor down (new line)    */
  147.         { "up", 0, NULL, 0 },    /* cursor up            */
  148.         { "sr", 0, NULL, 0 },    /* scroll reverse        */
  149.         { "sc", 0, NULL, 0 },    /* save cursor position        */
  150.         { "rc", 0, NULL, 0 },    /* restore cursor position    */
  151.         { "cs", 0, NULL, 0 },    /* set cursor scroll range    */
  152.         { "mr", 0, NULL, 0 },    /* mode reverse video        */
  153.         { "md", 0, NULL, 0 },    /* mode dense (highlight)    */
  154.         { "me", 0, NULL, 0 },    /* mode end (back to normal)    */
  155.         {   "", 0, NULL, 0 }
  156.     };
  157.  
  158. #define    SAVE_CURSOR    fprintf (Termfp, "%s", Tcap[SC].tc_str)
  159. #define    RESTORE_CURSOR    fprintf (Termfp, "%s", Tcap[RC].tc_str)
  160.  
  161. char    *getenv(), *tgetstr(), *tgoto();
  162. char    *cs_define(), get_ac();
  163. char    *malloc();
  164.  
  165. /*------------------------------------------------------------07/13/84--+
  166. |                                    |
  167. |        M a i n    R o u t i n e    S t a r t s    H e r e        |
  168. |                                    |
  169. +----------------------------------------------------------------------*/
  170. main (argc, argv)
  171. int    argc;        /* number of argument passed        */
  172. char    **argv;        /* pointer to argument list        */
  173.     {
  174.     register int    i, j;
  175.     char        *top = "\t";    /* top of stack string */
  176.     int        size;        /* longest string */
  177.  
  178.     Termfp = fopen ("/dev/tty", "r+");
  179.     if (proc_arg (argc, argv) == 1) size = make_argv ();
  180.     else size = cp_ptr (argc, argv);
  181.  
  182.     if (!Dircount) my_exit (0);
  183.     if (Search_string) Topsel = search ();
  184.  
  185.     Ntab = make_bar (size) / 8;
  186.     fprintf (Termfp, "%s\n", Topbar);
  187.  
  188.     if (Scroll) j = Topsel;
  189.     else    {
  190.         top = "   Top->";
  191.         j = 0;
  192.         }
  193.  
  194.     for (i=0; i<Dircount; i++) {
  195.         put_line (j, (j==0) ? top : "\t", "\n");
  196.         if (++j >= Dircount) j = 0;
  197.         }
  198.  
  199.     fprintf (Termfp, "%s\n", Botbar); fflush (Termfp);
  200.  
  201.     if (Select && Dircount > 1) {
  202.         if (Tcap[UP].tc_len) my_exit (get_rdata ());
  203.         else my_exit (get_data ());
  204.         }
  205.  
  206.     my_exit (0);
  207.     }
  208.  
  209. /*-------------------------------------------------------------07/02/86-+
  210. |                                    |
  211. |          make_bar : make all the graphical bar strings        |
  212. |                                    |
  213. +----------------------------------------------------------------------*/
  214. make_bar (size)
  215. int    size;
  216.     {
  217.     register int    i;
  218.     char        *p;
  219.     char        hbar = get_ac('q');
  220.  
  221.     size = ((size + 5)/Tabstop + 1) * Tabstop;
  222.     for (i=0; i<size-1 && i<MAXBAR; i++)
  223.         Bar[i] = hbar;        /* create bar string */
  224.     Bar[i] = EOS;
  225.  
  226.     switch (Boxstyle) {
  227.         case BOX_GRAPH:
  228.         if (Tcap[AC].tc_len) break;
  229.         Boxstyle = BOX_HIGHLITE;
  230.         case BOX_HIGHLITE:
  231.         if (Tcap[MD].tc_len && Tcap[ME].tc_len) break;
  232.         Boxstyle = BOX_REVERSE;
  233.         case BOX_REVERSE:
  234.         if (Tcap[MR].tc_len && Tcap[ME].tc_len) break;
  235.         default:
  236.         Boxstyle = BOX_DASH;
  237.         }
  238.  
  239.     if (Boxstyle == BOX_GRAPH) {
  240.         sprintf (Topbar, "\015\t%s%c%s%c%s", Tcap[AS].tc_str,
  241.              get_ac('l'), Bar, get_ac('k'), Tcap[AE].tc_str);
  242.         sprintf (Vbar, "%s%c%s", Tcap[AS].tc_str, get_ac('x'),
  243.              Tcap[AE].tc_str);
  244.         sprintf (Botbar, "\t%s%c%s%c%s", Tcap[AS].tc_str,
  245.              get_ac('m'), Bar, get_ac('j'), Tcap[AE].tc_str);
  246.         }
  247.     else if (Boxstyle == BOX_REVERSE || Boxstyle == BOX_HIGHLITE) {
  248.         while (--i >= 0) Bar[i] = SPACE;
  249.         p = Tcap [(Boxstyle == BOX_HIGHLITE) ? MD : MR].tc_str;
  250.         sprintf (Topbar, "\015\t%s %s %s",
  251.              p, Bar, Tcap[ME].tc_str);
  252.         sprintf (Vbar, "%s %s", p, Tcap[ME].tc_str);
  253.         strcpy (Botbar, Topbar);
  254.         }
  255.     else    {
  256.         sprintf (Topbar, "\015\t+%s+", Bar);
  257.         sprintf (Vbar, "|");
  258.         strcpy (Botbar, Topbar);
  259.         }
  260.     return (size);
  261.     }
  262.  
  263. /*-------------------------------------------------------------07/01/86-+
  264. |                                    |
  265. |         get_rdata : get raw input and process it        |
  266. |                                    |
  267. +----------------------------------------------------------------------*/
  268. get_rdata ()
  269.     {
  270.     register int    i, j, n;
  271.     int        x;        /* 0-9 index for next position */
  272.     char        c, buf[80];
  273.     int        dir, sel;
  274.     int        fd = fileno (Termfp);
  275.  
  276.     rawio (fd, &Scd);
  277.     fputc (RETURN, Termfp);
  278.  
  279.     if (Scroll) {            /* use scroll region */
  280.         sel = scroll_sel (fd);
  281.         i = 0; goto eos;
  282.         }
  283.     move_many (Dircount+1-Topsel, UP); /* back to top */
  284.     move_many (13, ND);
  285.  
  286.     for (i=Topsel; ;) {        /* selection loop */
  287.         read (fd, &c, 1);
  288.         n = i;  x = 0;
  289.         switch (c & 0x7f) {
  290.             case '9': case '8': case '7': case '6':    case '5':
  291.             case '4': case '3': case '2': case '1': case '0':
  292.                     x = (c & 0x7f) - '0';
  293.                     if (x >= Dircount) continue;
  294.                     i = figure_dir (x, i);
  295.                     break;
  296.             case 'n':    i = find_idx (1, i);    /* next */
  297.                     break;
  298.             case 'p':    i = find_idx (-1, i);    /* prev */
  299.                     break;
  300.             case 'h': case 'H': case 'k': case 'K':
  301.             case BS:    if (--i < 0) i = Dircount-1;
  302.                     break;
  303.             case RETURN:    sel = i; goto eos;
  304.             case SPACE:
  305.             default:    if (++i >= Dircount) i = 0;
  306.                     break;
  307.             }
  308.         if (n == i) continue;
  309.         if (n > i) { n = n - i;  dir = UP; }
  310.         else { n = i - n;  dir = NL; }
  311.  
  312.         /* move to next field */
  313.         strcpy (buf, " \010");
  314.         for (j=0; j<n; j++) strcat (buf, Tcap[dir].tc_str);
  315.         strcat (buf, "-\010");
  316.         fprintf (Termfp, "%s", buf);
  317.         fflush (Termfp);
  318.         }
  319. eos:
  320.     move_many (Dircount-i+1, NL);
  321.     fputc (RETURN, Termfp);
  322.     fflush (Termfp);
  323.     resetio (fd, &Scd);
  324.     return (sel);
  325.     }
  326.  
  327. /*-------------------------------------------------------------10/09/86-+
  328. |                                    |
  329. |        put_line : put a line on screen to scroll        |
  330. |                                    |
  331. +----------------------------------------------------------------------*/
  332. put_line (i, lead, trail)
  333. int    i;                /* index to Dirstack */
  334. char    *lead;                /* leading string */
  335. char    *trail;                /* trailing string */
  336.     {
  337.     register int    n, j;
  338.  
  339.     n = Ntab - (Arglen[i]+5+1)/Tabstop;
  340.     for (j=0; j<n; j++) Tab[j] = '\t'; Tab[j] = EOS;
  341.     fprintf (Termfp, "%s%s %2d: %s%s%s%s",
  342.         lead, Vbar, i, Dirstack[i], Tab, Vbar, trail);
  343.     }
  344.  
  345. /*-------------------------------------------------------------10/09/86-+
  346. |                                    |
  347. |        scroll_sel : scroll to show the selection        |
  348. |                                    |
  349. +----------------------------------------------------------------------*/
  350. scroll_sel (fd)
  351. int    fd;
  352.     {
  353.     register int    idx;        /* index to Dirstack of top element */
  354.     register int    target;        /* target index */
  355.     register int    move_cnt;    /* # of up/down to move */
  356.     int        topline;    /* top line number of the box */
  357.     int        botline;    /* bottom line # of the box */
  358.     int        ld;        /* last digit (0-9) */
  359.     char        c;
  360.  
  361.     /* find out where is the cursor and define the scroll region
  362.        accordingly. Note this should be done AFTER the directory
  363.        stack dislpayed since you do not know where the original
  364.        screen boundaries defined to be. */
  365.  
  366.     botline = get_curline (fd) - 2;
  367.     topline = botline - Dircount + 1;        /* define region */
  368.     fprintf (Termfp, "%s%s%s", Tcap[SC].tc_str,
  369.          cs_define (topline, botline), Tcap[RC].tc_str);
  370.  
  371.     move_many (Dircount+1, UP);
  372.     move_many (13, ND);
  373.  
  374.     for (idx=Topsel, move_cnt=1; ; move_cnt=1) {
  375.         read (fd, &c, 1);    /* get user key stroke */
  376.         c &= 0x7F;
  377.         switch (c) {
  378.             case RETURN:
  379.             goto eofor;
  380.  
  381.             case 'n':
  382.             target = find_idx (1, idx);
  383.             goto move;
  384.             case 'p':
  385.             target = find_idx (-1, idx);
  386.             goto move;
  387.             case '9': case '8': case '7': case '6': case '5':
  388.             case '4': case '3': case '2': case '1': case '0':
  389.             ld = c - '0';
  390.             if (ld >= Dircount) continue;
  391.             target = idx;
  392.             do    {
  393.                 if (++target >= Dircount) target = 0;
  394.                 } while (target % 10 != ld);
  395. move:            move_cnt = target - idx;
  396.             if (move_cnt < 0) move_cnt += Dircount;
  397.             if (move_cnt > Dircount/2) {
  398.                 move_cnt = Dircount - move_cnt;
  399.                 goto up;
  400.                 }
  401.             goto down;
  402.  
  403.             case 'k': case 'K': case 'h': case 'H': case BS:
  404.             /* scroll down one entry */
  405. up:            SAVE_CURSOR;
  406.             while (move_cnt-- > 0) {
  407.                 move_many (1, SR);
  408.                 if (--idx < 0) idx = Dircount - 1;
  409.                 put_line (idx, "\r\t", "\r");
  410.                 }
  411.             RESTORE_CURSOR;
  412.             break;
  413.  
  414.             case 'j': case 'J': case 'l': case 'L': case SPACE:
  415.             default:    /* scroll up one entry */
  416. down:            SAVE_CURSOR;
  417.             move_many (Dircount-1, NL);
  418.             while (move_cnt-- > 0) {
  419.                 move_many (1, NL);
  420.                 put_line (idx, "\r\t", "\r");
  421.                 if (++idx >= Dircount) idx = 0;
  422.                 }
  423.             RESTORE_CURSOR;
  424.             break;
  425.             }
  426.         fflush (Termfp);
  427.         }
  428. eofor:
  429.     /* restore scrolling region to full screen (assumed the
  430.        original state is so) */
  431.     fprintf (Termfp, "%s%s%s", Tcap[SC].tc_str,
  432.           cs_define (Fst_line, Line-1+Fst_line),
  433.          Tcap[RC].tc_str);        /* reset region */
  434.     fflush (Termfp);
  435.     return (idx);
  436.     }
  437.  
  438. /*-------------------------------------------------------------10/09/86-+
  439. |                                    |
  440. | cs_define : return a string contains cursor scroll region definition    |
  441. |                                    |
  442. +----------------------------------------------------------------------*/
  443. char    *
  444. cs_define (from, to)
  445. int    from;                /* start line number */
  446. int    to;                /* end line number */
  447.     {
  448.     static char    cs_buf [20];
  449.     static int    cs_from = 0;
  450.     static int    cs_to = 0;
  451.     static char    tc1, tc2;
  452.     register char    *p;
  453.     register int    i;
  454.  
  455.     if (cs_from == 0) {
  456.         p = Tcap[CS].tc_str;
  457.         i = 0;
  458.         while (*p != EOS) {
  459.             if (strncmp (p, "%i", 2) == 0) {
  460.                 Fst_line = 1;
  461.                 p += 2;
  462.                 continue;
  463.                 }
  464.             if (strncmp (p, "%d", 2) == 0) {
  465.                 if (cs_from == 0) cs_from = i;
  466.                 else cs_to = i;
  467.                 i += 3;        /* 3 digits reserved */
  468.                 p += 2;
  469.                 continue;
  470.                 }
  471.             cs_buf [i++] = *p++;
  472.             }
  473.         cs_buf [i] = EOS;
  474.         tc1 = cs_buf [cs_from + 3];
  475.         tc2 = cs_buf [cs_to + 3];
  476.         }
  477.     sprintf (&cs_buf[cs_from], "%03d", from);
  478.     cs_buf [cs_from + 3] = tc1;
  479.  
  480.     sprintf (&cs_buf[cs_to], "%03d", to);
  481.     cs_buf [cs_to + 3] = tc2;
  482.  
  483.     return (cs_buf);
  484.     }
  485.  
  486. /*-------------------------------------------------------------10/09/86-+
  487. |                                    |
  488. |        get_curline : get current cursor line number        |
  489. |                                    |
  490. +----------------------------------------------------------------------*/
  491. get_curline (fd)
  492. int    fd;
  493.     {
  494.     register int    i, gotesc = NO;
  495.     char        c;
  496.     int        line, column;
  497.     char        buf[80];
  498.  
  499.     /* Ask terminal to report its cursor position */
  500.  
  501.     fprintf (Termfp, "%s", Curpos_query); fflush (Termfp);
  502.     for (i=0; i<80-1; i++) {
  503. loop:        read (fd, &c, 1);
  504.         c &= 0x7F;
  505.         if (gotesc == NO) {
  506.             if (c != ESC) goto loop;
  507.             gotesc = YES;
  508.             }
  509.         if ((buf[i] = c) == 'R') {     /* end of report */
  510.             buf[++i] = EOS;
  511.             break;
  512.             }
  513.         }
  514.     sscanf (buf, "\033[%d;%dR", &line, &column);    /* VT100 only */
  515.     return (line);
  516.     }
  517.  
  518. /*-------------------------------------------------------------10/09/86-+
  519. |                                    |
  520. |     move_many : repeatedly write certain string to output device    |
  521. |                                    |
  522. +----------------------------------------------------------------------*/
  523. move_many (n, code)
  524. int    n;                /* repeat count */
  525. int    code;                /* index to Tcap structure */
  526.     {
  527.     register int    i;
  528.  
  529.     for (i=0; i<n; i++) {
  530.         fprintf (Termfp, "%s", Tcap[code].tc_str);
  531.         }
  532.     fflush (Termfp);
  533.     }
  534.  
  535. /*-------------------------------------------------------------10/14/86-+
  536. |                                    |
  537. |         my_exit : close opened terminal file then exit         |
  538. |                                    |
  539. +----------------------------------------------------------------------*/
  540. my_exit (n)
  541. int    n;
  542.     {
  543.     if (Termfp) fclose (Termfp);
  544.     exit (n);
  545.     }
  546.  
  547. /*-------------------------------------------------------------07/01/86-+
  548. |                                    |
  549. |   get_data : get data for terminal with no cursor addr capability    |
  550. |                                    |
  551. +----------------------------------------------------------------------*/
  552. get_data ()
  553.     {
  554.     char        buf [20];
  555.     register int    i = 0;
  556.  
  557.     printf ("Please Select [0-%d]: ", Dircount-1);
  558.     gets (buf);
  559.     if (strlen (buf)) {
  560.         i = atoi (buf);
  561.         if (i < 0 || i > Dircount-1) i = 0;
  562.         }
  563.     return (i);
  564.     }
  565.  
  566. #define    PADDING    '\200'
  567. /*-------------------------------------------------------------05/10/86-+
  568. |                                    |
  569. |       tcap_init : initialize termcap data structure        |
  570. |                                    |
  571. +----------------------------------------------------------------------*/
  572. tcap_init ()
  573.     {
  574.     register int    i;
  575.     struct    tcap    *p;
  576.     char        *tp;
  577.     unsigned int    delay;
  578.     int        status;
  579.     char        *termtype = getenv ("TERM");
  580.  
  581.     if ((status = tgetent (Termcap, termtype)) != 1) {
  582.         if (status == 0) {
  583.             fprintf (stderr, "No entry for %s in termcap\r\n",
  584.                  termtype);
  585.             }
  586.         else    fprintf (stderr, "Can not open termcap file\r\n");
  587.         my_exit (1);
  588.         }
  589.  
  590.     for (p= &Tcap[0]; strlen (p->tc_id) > 0; p++) {
  591.         tp = tgetstr (p, &Tsp);
  592.         if (tp == NULL) tp = "";     /* no such capability */
  593.         delay = 0;
  594.         while (isdigit (*tp)) {
  595.             delay = delay*10 + (*tp++) - '0';
  596.             }
  597.         p->tc_delay = delay;
  598.         p->tc_len = strlen (tp);
  599.         if (delay) {
  600.             p->tc_str = malloc (p-> tc_len + delay);
  601.             strcpy (p->tc_str, tp);
  602.             tp = p->tc_str + p->tc_len;
  603.             for (i=0; i<delay; i++) *tp++ = PADDING;
  604.             *tp = EOS;
  605.             p->tc_len += delay;
  606.             }
  607.         else    p->tc_str = tp;
  608.         Tcap_count++;
  609.         }
  610.  
  611.     Line = tgetnum ("li");
  612.     tcap_special ();
  613.     }
  614.  
  615. /*-------------------------------------------------------------07/02/86-+
  616. |                                    |
  617. |        tcap_special : special initialization            |
  618. |                                    |
  619. +----------------------------------------------------------------------*/
  620. tcap_special ()
  621.     {
  622.     if (Tcap[NL].tc_len == 0) {
  623.         Tcap[NL].tc_str = "\n";
  624.         Tcap[NL].tc_delay = 0;
  625.         Tcap[NL].tc_len = 1;
  626.         }
  627.     }
  628.  
  629. /*-------------------------------------------------------------07/01/86-+
  630. |                                    |
  631. |  get_ac : get alternate character for a given VT100 alternate char    |
  632. |                                    |
  633. +----------------------------------------------------------------------*/
  634. char
  635. get_ac (c)
  636. char    c;
  637.     {
  638.     register char    *p;
  639.     char        oc;
  640.  
  641.     if (Tcap_count == 0) tcap_init ();
  642.     for (p=Tcap[AC].tc_str; *p != EOS; p += 2) {
  643.         if (*p == c) return *(p+1);
  644.         }
  645.     switch (c) {
  646.         case 'j':        /* lower right corner    */
  647.         case 'k':        /* upper right corner    */
  648.         case 'l':        /* upper left corner    */
  649.         case 'm':  oc = '+';    /* lower left corner    */
  650.                break;
  651.         case 'q':  oc = '-';    /* horizontal bar */
  652.                break;
  653.         case 'x':  oc = '|';    /* vertical bar */
  654.                break;
  655.         default:   oc = '?';    /* bad choice */
  656.         }
  657.     return (oc);
  658.     }
  659.  
  660. /*-------------------------------------------------------------02/18/86-+
  661. |                                    |
  662. |          figure_dir : figure out which direction to go        |
  663. |                                    |
  664. +----------------------------------------------------------------------*/
  665. figure_dir (x, i)
  666. int    x;                /* target index (0-9) */
  667. int    i;                /* curent index (0-Dircount) */
  668.     {
  669.     int    n;
  670.  
  671.     n = i % 10;
  672.     if (x == n) {
  673.         if (i + 10 < Dircount) return (i+10);
  674.         }
  675.     if (x > n) {
  676.         if (i - n + x < Dircount) return (i - n + x);
  677.         }
  678.     else    {
  679.         if (i - n + x + 10 < Dircount) return (i - n + x + 10);
  680.         }
  681.  
  682.     return (x);
  683.     }
  684.  
  685. /*-------------------------------------------------------------02/17/86-+
  686. |                                    |
  687. |         cp_ptr : copy all the argv pointers to Dirstack        |
  688. |                                    |
  689. +----------------------------------------------------------------------*/
  690. cp_ptr (argc, argv)
  691. int    argc;
  692. char    **argv;
  693.     {
  694.     register int    i, j;
  695.     int        n;
  696.     int        size = 0;
  697.  
  698.     for (j=0, i=Sno; i<argc; i++) {
  699.         if (j >= Maxdir) {
  700.             fprintf (stderr, "Max %d entries, extra ignored\n",
  701.                  Maxdir);
  702.             fflush (stderr);
  703.             break;
  704.             }
  705.         Dirstack[j] = argv[i];            /* save start addr */
  706.         Arglen[j++] = n = strlen (argv[i]);    /* and length */
  707.         if (n > size) size = n;
  708.         }
  709.     Dircount = j;
  710.     return (size);            /* return the longest length */
  711.     }
  712.  
  713. /*-------------------------------------------------------------02/17/86-+
  714. |                                    |
  715. |            make_argv : make an argument list            |
  716. |                                    |
  717. +----------------------------------------------------------------------*/
  718. make_argv ()
  719.     {
  720.     char        *p = Stack;
  721.     char        *op = Stack;    /* old pointer */
  722.     char        c;
  723.     register int    i = 0;
  724.     int        size = 0;
  725.     int        n;
  726.  
  727.     gets (Stack);
  728.     while ((c = *p) != NEWLINE && c != EOS) {
  729.         if (c == SPACE) {
  730.             *p = EOS;
  731.             Dirstack[i] = op;
  732.             Arglen[i++] = n = p - op;
  733.             if (n > size) size = n;
  734.             op = p+1;
  735.             }
  736.         p++;
  737.         }
  738.     if (i > Maxdir) {
  739.         fprintf (stderr, "Max %d entries, extra ignored\n", Maxdir);
  740.         fflush (stderr);
  741.         i = Maxdir;
  742.         }
  743.     Dircount = i;
  744.     return (size);
  745.     }
  746. /*-------------------------------------------------------------10/14/86-+
  747. |                                    |
  748. |        find_idx : find next/prev index from Str_idx array        |
  749. |                                    |
  750. +----------------------------------------------------------------------*/
  751. find_idx (dir, n)
  752. int    dir;                /* direction: 1=next, -1=prev */
  753. int    n;                /* current index */
  754.     {
  755.     register int    i;
  756.  
  757.     for (i=0; i<Str_total; i++) {
  758.         if (Str_idx[i] == n) {        /* found current, locate next */
  759.             i += dir;
  760.             if (i == Str_total) i = 0;
  761.             if (i < 0) i = Str_total - 1;
  762.             return (Str_idx[i]);
  763.             }
  764.         }
  765.     return (n);
  766.     }
  767.  
  768. /*------------------------------------------------------------07/12/84--+
  769. |                                    |
  770. |    proc_arg : routine to process command arguments (options)    |
  771. |                                    |
  772. +----------------------------------------------------------------------*/
  773. proc_arg (argc, argv)
  774. int    argc;
  775. char    **argv;
  776.     {
  777.     register int    i;
  778.     register int    n;
  779.     char        *p;
  780.  
  781.     p = getenv ("TABSTOP");
  782.     if (p != NULL) {        /* set tabstop to n (default 8) */
  783.         n = atoi (p);
  784.         if (n > 0) Tabstop = n;
  785.         }
  786.     for (n=i=0; i<argc; i++) {
  787.         if (argv[i][0] != '-') {
  788.             n++;        /* count non-option argument */
  789.             continue;
  790.             }
  791.         Sno++;
  792.         switch (argv[i][1]) {
  793.             when 's':    p = &argv[i][2];
  794.                 if ((Schlen = strlen (p)) == 0) Select = YES;
  795.                 else Search_string = p;
  796.  
  797.             when 'r':    tcap_init ();
  798.                 if (Tcap[SC].tc_len != 0 &&
  799.                     Tcap[RC].tc_len != 0 &&
  800.                     Tcap[CS].tc_len != 0) Scroll = YES;
  801.  
  802.             when 'b':    box_style (argv[i][2]);
  803.  
  804.             when 'v':    printf ("%s\n%s\n", Version, Author);
  805.                 my_exit (0);
  806.  
  807.             otherwise:    Sno--;        /* dont count */
  808.             }
  809.         }
  810.     return (n);
  811.     }
  812.  
  813. /*-------------------------------------------------------------10/14/86-+
  814. |                                    |
  815. |   search : find string in dir stack and exit or return found index    |
  816. |                                    |
  817. +----------------------------------------------------------------------*/
  818. search ()
  819.     {
  820.     register int    i, j;
  821.     register char    *p;
  822.     int        len;
  823.     int        sel;
  824.  
  825.     /* If argument starts with a number, it will be used as index to
  826.        directory stack.  If not, it will be used as string to search */
  827.  
  828.     sel = atoi (Search_string);
  829.     if (0 < sel && sel < Dircount) {     /* number used as index */
  830. match:        puts (Dirstack[sel]);
  831.         my_exit (sel);
  832.         }
  833.     for (Str_total=i=0, sel = -1; i<Dircount; i++) {
  834.         len = Arglen[i];
  835.         p = Dirstack[i];
  836.         for (j=0; j<=len-Schlen; j++) {
  837.             if (strncmp (Search_string, p+j, Schlen) == 0) {
  838.                 Str_idx[Str_total++] = i;
  839.                 if (sel == -1) sel = i;
  840.                 break;
  841.                 }
  842.             }
  843.         }
  844.     if (Str_total == 1) goto match;
  845.     Select = YES;
  846.     return ((sel == -1) ? 0 : sel); /* more than one, stay around */
  847.     }
  848.  
  849. /*-------------------------------------------------------------10/14/86-+
  850. |                                    |
  851. |            box_style : select box style            |
  852. |                                    |
  853. +----------------------------------------------------------------------*/
  854. box_style (style)
  855. char    style;                /* style */
  856.     {
  857.     switch (style) {
  858.         when 'h':    Boxstyle = BOX_HIGHLITE;
  859.         when 'r':    Boxstyle = BOX_REVERSE;
  860.         when 'g':    Boxstyle = BOX_GRAPH;
  861.         otherwise:    Boxstyle = BOX_DASH;
  862.         }
  863.     }
  864.  
  865. int        Old_flags;
  866. int        Pseudo = -1;        /* 0/1 = normal/pseudo terminal */
  867. /*------------------------------------------------------------07/10/84--+
  868. |                                    |
  869. |       rawio : oepn terminal in RAW mode without ECHO        |
  870. |                                    |
  871. +----------------------------------------------------------------------*/
  872. rawio (fd, mp)
  873. int        fd;            /* file descriptor */
  874. struct    sgttyb    *mp;            /* ptr to mode structure */
  875.     {
  876.     char    *tname = (char *) ttyname (fileno(stdout)) + 8;
  877.                     /* /dev/ttypxxx    */
  878.                     /* 012345678    */
  879.  
  880.     if (*tname == 'p' || *tname == 'q' || *tname == 'r') {
  881.         /* pseudo terminal, delay a while so that output will
  882.            drain...   */
  883.         Pseudo = YES;
  884.         sleep (1);
  885.         }
  886.     else    Pseudo = NO;
  887.  
  888.     ioctl (fd, TIOCGETP, mp);
  889.     Old_flags = mp-> sg_flags;    /* save old setting */
  890.     mp-> sg_flags |= RAW;
  891.     mp-> sg_flags &= ~ECHO;
  892.     ioctl (fd, TIOCSETP, mp);
  893.     }
  894.  
  895. /*------------------------------------------------------------07/10/84--+
  896. |                                    |
  897. |    resetio : close terminal and restore original setting        |
  898. |                                    |
  899. +----------------------------------------------------------------------*/
  900. resetio (fd, mp)
  901. int        fd;            /* file descriptor */
  902. struct    sgttyb    *mp;            /* ptr to old setting */
  903.     {
  904.     if (Pseudo) sleep (1);
  905.  
  906.     mp-> sg_flags = Old_flags;
  907.     ioctl (fd, TIOCSETP, mp);    /* restore original setting */
  908.     }
  909.