home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_10_12 / brow.c < prev    next >
C/C++ Source or Header  |  1992-07-13  |  16KB  |  604 lines

  1. /*
  2.  * brow.c - file browser, virtual display output
  3.  * Bob Bybee, 3/22/91
  4.  */
  5. #include <ssdef.h>
  6. #include <stdio.h>
  7. #include <descrip.h>
  8. #include <smgdef.h>
  9. #include <stat.h>
  10. #include <time.h>
  11. #include "vaxkeys.h"
  12.  
  13. int kb_id, pb_id, output_device, pb_rows, pb_cols;
  14. int top_disp_id, bot_disp_id, main_disp_id;
  15. int vid_attr, main_size;
  16. int one = 1, two = 2, ins_dir;
  17. int top_line = 0;
  18. int tabsize = 8;
  19. int found_line = -1;
  20. char ftimebuf[80];
  21. FILE *fp;
  22. char filename[80];
  23.  
  24. #define INPUT_BUFSIZE 60
  25. char inputbuf[INPUT_BUFSIZE + 1];
  26. char searchbuf[INPUT_BUFSIZE + 1];
  27. int input_bufsize = INPUT_BUFSIZE;
  28. int inputlen, searchlen;
  29.  
  30. #define MAX_LINES 10000
  31. #define MAX_LINE_LENGTH 150
  32. char *pointers[MAX_LINES];
  33. int lastline;
  34.  
  35.  
  36. /* prototypes
  37.  */
  38. void help_info( void );
  39. void repaint_page( void );
  40. void show_lineno( void );
  41. void bottom_line( char *msg );
  42. void get_line( int lineno, char *buf );
  43. void testret( int where, int ret );
  44. int getkey( void );
  45. void getline( char *prompt );
  46. void string_to_des( char *buf, struct dsc$descriptor *dp );
  47. void snuff_nl( char *buf );
  48. void filetime( FILE *fp, char *buf );
  49. void tabex( char *buf );
  50. void get_pointers( void );
  51. void strupr( char *s );
  52.  
  53. int main( int argc, char **argv )
  54.     {
  55.     int c, i = 0, ret, row, col, how_far_in, how_far_down;
  56.     int found_it, rendition, first_search, case_insens = 0;
  57.     struct dsc$descriptor des;
  58.     char buf[MAX_LINE_LENGTH], orig_buf[MAX_LINE_LENGTH], *p;
  59.  
  60.     --argc, ++argv;
  61.     if (argc != 1)
  62.         {
  63.         printf("Usage: brow <filename>\n");
  64.         exit(1);
  65.         }
  66.         
  67.     if ((fp = fopen(*argv, "r")) == NULL)
  68.         {
  69.         printf("Can't open file: %s\n", *argv);
  70.         exit(1);
  71.         }
  72.  
  73.     filetime(fp, ftimebuf);
  74.     strcpy(filename, *argv);
  75.     filename[sizeof(filename) - 1] = '\0';
  76.     get_pointers();
  77.  
  78.     testret(1, SMG$CREATE_VIRTUAL_KEYBOARD(&kb_id));
  79.     testret(2, SMG$CREATE_PASTEBOARD(&pb_id,
  80.                 NULL, &pb_rows, &pb_cols));
  81.     vid_attr = SMG$M_REVERSE;
  82.     testret(3, SMG$CREATE_VIRTUAL_DISPLAY(&one, &pb_cols,
  83.         &top_disp_id, 0, &vid_attr));
  84.     testret(4, SMG$CREATE_VIRTUAL_DISPLAY(&one, &pb_cols,
  85.         &bot_disp_id, 0, &vid_attr));
  86.     vid_attr = 0;
  87.     main_size = pb_rows - 2;
  88.     testret(5, SMG$CREATE_VIRTUAL_DISPLAY(&main_size, &pb_cols,
  89.         &main_disp_id, 0, &vid_attr));
  90.     testret(6, SMG$PASTE_VIRTUAL_DISPLAY(&top_disp_id,
  91.         &pb_id, &one, &one));
  92.     testret(7, SMG$PASTE_VIRTUAL_DISPLAY(&bot_disp_id,
  93.         &pb_id, &pb_rows, &one));
  94.     testret(8, SMG$PASTE_VIRTUAL_DISPLAY(&main_disp_id,
  95.         &pb_id, &two, &one));
  96.  
  97.     top_line = 0;
  98.     repaint_page();
  99.     while (1)
  100.         {
  101.         c = getkey();
  102.         switch (c)
  103.             {
  104.             case '?':
  105.                 help_info();
  106.                 getkey();
  107.                 repaint_page();
  108.                 break;
  109.  
  110.             case DOWN_KEY:
  111.             case 'D':
  112.             case 'd':
  113.                 if (top_line + main_size - 1 < lastline)
  114.                     {
  115.                     ++top_line;
  116.                     strcpy(buf, pointers[top_line + main_size - 1]);
  117.                     tabex(buf);
  118.                     string_to_des(buf, &des);
  119.                     ins_dir = SMG$M_UP;
  120.                     testret(10, SMG$INSERT_LINE(&main_disp_id, &main_size, 
  121.                         &des, &ins_dir));
  122.                     show_lineno();
  123.                     }
  124.                 break;
  125.  
  126.             case NEXT_SCREEN_KEY:
  127.             case 'N':
  128.             case 'n':
  129.             case 'N' - '@':
  130.                 top_line += main_size - 1;
  131.                 repaint_page();
  132.                 break;
  133.  
  134.             case UP_KEY:
  135.             case 'U':
  136.             case 'u':
  137.                 if (top_line > 0)
  138.                     {
  139.                     --top_line;
  140.                     strcpy(buf, pointers[top_line]);
  141.                     tabex(buf);
  142.                     string_to_des(buf, &des);
  143.                     ins_dir = SMG$M_DOWN;
  144.                     testret(10, SMG$INSERT_LINE(&main_disp_id, &one, 
  145.                         &des, &ins_dir));
  146.                     show_lineno();
  147.                     }
  148.                 break;
  149.  
  150.             case PREV_SCREEN_KEY:
  151.             case 'P':
  152.             case 'p':
  153.             case 'P' - '@':
  154.                 top_line -= main_size - 1;
  155.                 repaint_page();
  156.                 break;
  157.  
  158.             case 'H':
  159.             case 'h':
  160.             case 'H' - '@':
  161.                 top_line = 0;
  162.                 repaint_page();
  163.                 break;
  164.  
  165.             case 'E':
  166.             case 'e':
  167.             case 'E' - '@':
  168.                 top_line = lastline - (main_size - 1);
  169.                 repaint_page();
  170.                 break;
  171.  
  172.             case 'L' - '@':
  173.                 testret(15, SMG$REPAINT_SCREEN(&pb_id));
  174.                 break;
  175.  
  176.             case '#':
  177.                 getline("Go to line: ");
  178.                 if (sscanf(inputbuf, "%d", &top_line) == 1)
  179.                     {
  180.                     --top_line;         /* make it 0-based */
  181.                     repaint_page();
  182.                     }
  183.                 break;
  184.  
  185.             case 'I' - '@':
  186.                 getline("New tab size: ");
  187.                 if (sscanf(inputbuf, "%d", &tabsize) == 1)
  188.                     repaint_page();
  189.                 break;
  190.  
  191.  
  192.             case PF3_KEY:
  193.                 if (found_line < 0)
  194.                     bottom_line("No previous search string.");
  195.                 else
  196.                     {
  197.                     first_search = found_line + 1;
  198.                     goto continue_search;
  199.                     }
  200.                 break;
  201.  
  202.             case '\\':
  203.                 case_insens = 1;
  204.                 goto ask_search;
  205.  
  206.             case '/':
  207.             case FIND_KEY:
  208.                 case_insens = 0;
  209.  
  210.         ask_search:
  211.                 getline("Search for: ");
  212.                 if (inputlen == 0)
  213.                     break;
  214.                 strcpy(searchbuf, inputbuf);
  215.                 if (case_insens)
  216.                     strupr(searchbuf);
  217.                 searchlen = inputlen;
  218.                 first_search = top_line;
  219.  
  220.         continue_search:
  221.                 found_it = 0;
  222.                 for (i = first_search; !found_it && i <= lastline; ++i)
  223.                     {
  224.                     strcpy(buf, pointers[i]);
  225.                     tabex(buf);
  226.                     if (case_insens)
  227.                         {
  228.                         strcpy(orig_buf, buf);
  229.                         strupr(buf);
  230.                         }
  231.  
  232.                     if ((p = strstr(buf, searchbuf)) != NULL)
  233.                         {
  234.                         /* found it.  center the display on that string.
  235.                          * make how_far_in, how_far_down the 1-based
  236.                          * screen coords of the string on the screen.
  237.                          */
  238.                         how_far_in = p - buf + 1;
  239.                         top_line = i - main_size / 2;
  240.                         repaint_page();
  241.                         how_far_down = i - top_line + 1;
  242.                         rendition = SMG$M_REVERSE;
  243.  
  244.                         if (case_insens)
  245.                             strcpy(buf, orig_buf);  /* replace orig buffer */
  246.  
  247.                         p[searchlen] = '\0';
  248.                         string_to_des(p, &des);
  249.                         testret(14, SMG$PUT_CHARS(&main_disp_id, &des,
  250.                             &how_far_down, &how_far_in,
  251.                             0, &rendition));
  252.                         show_lineno();  /* move cursor to bottom line */
  253.                         found_it = 1;
  254.                         found_line = i;
  255.                         }
  256.                     }
  257.                 if (!found_it)
  258.                     bottom_line("Not found.");
  259.                 break;
  260.  
  261.             case 'Q':
  262.             case 'q':
  263.             case 'Q' - '@':
  264.             case 'X':
  265.             case 'x':
  266.             case 'X' - '@':
  267.                 show_lineno();          /* put cursor on bottom line */
  268.                 printf("\n\n");
  269.                 exit(0);
  270.                 break;
  271.  
  272.             default:
  273.                 break;
  274.             }
  275.         }
  276.  
  277.     return (1);
  278.     }
  279.  
  280.  
  281. /*
  282.  * Display help-screen.
  283.  */
  284. void help_info( void )
  285.     {
  286.     int i, y;
  287.     char **pp;
  288.     struct dsc$descriptor des;
  289.  
  290.     static char *help_msgs[] =
  291.         {
  292. " ",
  293. "  BROWSE version 1.0    3/26/91",
  294. " ",
  295. "  H:  home (top of file)            /, FIND:  locate text string",
  296. "  E:  end (bottom of file)                \\:  locate (case insensitive)",
  297. "  U, up-arrow:    up one line           PF3:  continue search",
  298. "  P, prev-screen: up one screen",
  299. "  D, down-arrow:  down one line",
  300. "  N, next-screen: down one screen",
  301. " ",
  302. "  #:     go to a line #                  ^L:  repaint screen",
  303. "  TAB:   change tab-size setting",
  304. "  Q, X:  quit",
  305. " ",
  306. "           hit any key to continue...",
  307.         NULL
  308.         };
  309.  
  310.     /* batch up the following stuff.
  311.      */
  312.     SMG$BEGIN_PASTEBOARD_UPDATE(&pb_id);
  313.  
  314.     SMG$SET_CURSOR_ABS(&main_disp_id, &one, &one);
  315.     for (pp = help_msgs, y = 1, i = 0; i < main_size; ++i, ++y)
  316.         {
  317.         if (*pp != NULL)
  318.             {
  319.             string_to_des(*pp, &des);
  320.             ++pp;
  321.             }
  322.         else
  323.             string_to_des(" ", &des);
  324.  
  325.         testret(11, SMG$PUT_LINE(&main_disp_id, &des));
  326.         }
  327.  
  328.     /* end batching.
  329.      */
  330.     SMG$END_PASTEBOARD_UPDATE(&pb_id);
  331.     }
  332.  
  333.  
  334. /*
  335.  * Get an input line, prompting on the bottom line of the screen.
  336.  * Put result in inputbuf, length in inputlen.
  337.  */
  338. void getline( char *prompt )
  339.     {
  340.     struct dsc$descriptor result_des, prompt_des;
  341.     int modifiers = 0;
  342.     short result_len;
  343.  
  344.     string_to_des(prompt, &prompt_des);
  345.  
  346.     result_des.dsc$w_length = INPUT_BUFSIZE;
  347.     result_des.dsc$a_pointer = inputbuf;
  348.     result_des.dsc$b_class = DSC$K_CLASS_S;
  349.     result_des.dsc$b_dtype = DSC$K_DTYPE_T;
  350.  
  351.     SMG$READ_STRING(&kb_id, 
  352.         &result_des, 
  353.         &prompt_des, 
  354.         &input_bufsize,
  355.         &modifiers, 
  356.         0,              /* timeout */
  357.         0,              /* terminator set */
  358.         &result_len,
  359.         0,              /* word terminator code */
  360.         &bot_disp_id);
  361.  
  362.     inputbuf[result_len] = '\0';
  363.     inputlen = result_len;
  364.     show_lineno();      /* fix the bottom line of the screen */
  365.     }
  366.  
  367.  
  368. /*
  369.  * Repaint the screen, given the current value of top_line.
  370.  */
  371. void repaint_page( void )
  372.     {
  373.     int i, y, bot_line;
  374.     struct dsc$descriptor des;
  375.     char buf[MAX_LINE_LENGTH];
  376.  
  377.     /* sanity-check the top_line variable.
  378.      */
  379.     if (top_line + main_size - 1 > lastline)
  380.         top_line = lastline - (main_size - 1);
  381.     if (top_line < 0)
  382.         top_line = 0;
  383.  
  384.     /* batch up the following stuff.
  385.      */
  386.     SMG$BEGIN_PASTEBOARD_UPDATE(&pb_id);
  387.  
  388.     /* label the top line with the file time/date.
  389.      */
  390.     sprintf(buf, " File: %s       %s", filename, ftimebuf);
  391.     string_to_des(buf, &des);
  392.     testret(9, SMG$PUT_LINE(&top_disp_id, &des));
  393.  
  394.     SMG$SET_CURSOR_ABS(&main_disp_id, &one, &one);
  395.  
  396.     /* put N lines in the main viewing area
  397.      */
  398.     bot_line = top_line + main_size - 1;
  399.     for (y = 1, i = top_line; i <= bot_line; ++i, ++y)
  400.         {
  401.         get_line(i, buf);
  402.         string_to_des(buf, &des);
  403.         testret(11, SMG$PUT_LINE(&main_disp_id, &des));
  404.         }
  405.  
  406.     show_lineno();
  407.  
  408.     /* end batching, flush this update to the screen.
  409.      */
  410.     SMG$END_PASTEBOARD_UPDATE(&pb_id);
  411.     }
  412.  
  413.  
  414. /* 
  415.  * Label the bottom line with current line # and max lines in file.
  416.  */
  417. void show_lineno( void )
  418.     {
  419.     char buf[80];
  420.     struct dsc$descriptor des;
  421.     int last_shown;
  422.  
  423.     last_shown = top_line + main_size;
  424.     if (last_shown > lastline + 1)
  425.         last_shown = lastline + 1;
  426.     sprintf(buf, "  lines %5d  - %5d  (of %5d)       BROWSE v1.0       ?=help", 
  427.         top_line + 1, last_shown, lastline + 1);
  428.     string_to_des(buf, &des);
  429.     testret(12, SMG$PUT_LINE(&bot_disp_id, &des));
  430.     }
  431.  
  432.  
  433. /* 
  434.  * Put a message on bottom line of the screen.
  435.  */
  436. void bottom_line( char *msg )
  437.     {
  438.     struct dsc$descriptor des;
  439.  
  440.     string_to_des(msg, &des);
  441.     testret(12, SMG$PUT_LINE(&bot_disp_id, &des));
  442.     }
  443.  
  444.  
  445. /*
  446.  * Get the strings of all lines in the file.
  447.  * Set lastline to the last used entry in pointers[].
  448.  */
  449. void get_pointers( void )
  450.     {
  451.     char *p, buf[MAX_LINE_LENGTH];
  452.  
  453.     while (lastline < MAX_LINES && fgets(buf, MAX_LINE_LENGTH, fp) != NULL)
  454.         {
  455.         if ((p = malloc(strlen(buf) + 1)) == NULL)
  456.             {
  457.             printf("Out of memory!\n");
  458.             exit(1);
  459.             }
  460.         strcpy(p, buf);
  461.         pointers[lastline++] = p;
  462.         }
  463.  
  464.     --lastline;
  465.     }
  466.  
  467.  
  468. /*
  469.  * Return the text corresponding to lineno of the file.
  470.  * Tab-expand the text and put it in buf.
  471.  */
  472. void get_line( int lineno, char *buf )
  473.     {
  474.     int i;
  475.  
  476.     /* if past EOF, return a blank line
  477.      */
  478.     if (lineno > lastline)
  479.         {
  480.         *buf = '\0';
  481.         return;
  482.         }
  483.  
  484.     strcpy(buf, pointers[lineno]);
  485.     tabex(buf);
  486.     }
  487.  
  488.  
  489. /*
  490.  * Tab-expand a buffer, in place.
  491.  */
  492. void tabex( char *buf )
  493.     {
  494.     char buf2[200], c;
  495.     int i = 0, j = 0;
  496.  
  497.     while ((c = buf[i++]) != '\0' && c != '\n')
  498.         {
  499.         if (c == '\t')
  500.             {
  501.             do  {
  502.                 buf2[j++] = ' ';
  503.                 } while (j % tabsize != 0);
  504.             }
  505.         else
  506.             buf2[j++] = c;
  507.         }
  508.     buf2[j] = '\0';
  509.     strcpy(buf, buf2);
  510.     }
  511.  
  512.  
  513. /*
  514.  * Test the return value from a system call,
  515.  * error out if not success.
  516.  */
  517. void testret( int where, int ret )
  518.     {
  519.     if (ret != SS$_NORMAL)
  520.         {
  521.         printf("Error: where= %d  code= %d\n", where, ret);
  522.         exit(0);
  523.         }
  524.     }
  525.  
  526.  
  527. /*
  528.  * Get one keystroke from kb_id
  529.  */
  530. int getkey( void )
  531.     {
  532.     short termcode;
  533.  
  534.     SMG$READ_KEYSTROKE(&kb_id, &termcode);
  535.     return (termcode);
  536.     }
  537.  
  538.  
  539. /*
  540.  * install character string in a descriptor
  541.  */
  542. void string_to_des( char *buf, struct dsc$descriptor *dp )
  543.     {
  544.     dp->dsc$w_length = strlen(buf);
  545.     dp->dsc$a_pointer = buf;
  546.     dp->dsc$b_class = DSC$K_CLASS_S;
  547.     dp->dsc$b_dtype = DSC$K_DTYPE_T;
  548.     }
  549.  
  550.  
  551. /*
  552.  * Insert NUL at first control-char in a buffer.
  553.  */
  554. void snuff_nl( char *buf )
  555.     {
  556.     while (*buf >= ' ')
  557.         ++buf;
  558.     *buf = '\0';
  559.     }
  560.  
  561.  
  562. /*
  563.  * Get file time/date into a string buffer.
  564.  */
  565. void filetime( FILE *fp, char *buf )
  566.     {
  567.     int fd, r;
  568.     time_t bintim;
  569.     stat_t statbuf;
  570.     struct dsc$descriptor des;
  571.  
  572.     des.dsc$w_length = 23;
  573.     des.dsc$a_pointer = buf;
  574.     des.dsc$b_class = DSC$K_CLASS_S;
  575.     des.dsc$b_dtype = DSC$K_DTYPE_T;
  576.  
  577.     fd = fileno(fp);
  578.     if ((r = fstat(fd, &statbuf)) != 0)
  579.         {
  580.         printf("fstat returned %d\n", r);
  581.         exit(1);
  582.         }
  583.  
  584.     bintim = statbuf.st_mtime;
  585.     strcpy(buf, ctime(&bintim));
  586.     snuff_nl(buf);
  587.     }
  588.  
  589.  
  590. /*
  591.  * Convert a string to upper case.
  592.  */
  593. void strupr( char *s )
  594.     {
  595.     char c;
  596.  
  597.     while ((c = *s) != '\0')
  598.         {
  599.         if ('a' <= c && c <= 'z')
  600.             *s -= 'a' - 'A';
  601.         ++s;
  602.         }
  603.     }
  604.