home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 186_01 / view151.c < prev    next >
Text File  |  1985-08-21  |  15KB  |  484 lines

  1. /* VIEW:  Displays text files. CR advances by line, SPACE by screen.
  2.  * BS goes backwards by line, ESC by screen.  ^B returns to beginning,
  3.  * ^E goes to end.  ^C to abort.
  4.  * Syntax:  VIEW [-t] [n/][d:]filename.typ {more filenames . . .}
  5.  * "t" = tab size (defaults to 8 spaces)
  6.  * Multiple filenames on command line allowed.  Ambiguous filenames allowed
  7.  * (see WILDEXP.C documentation).
  8.  *
  9.  * Version 1.5 -- 10/10/85
  10.  * Version 1.51 (with slight changes for portability) -- 12/09/85
  11.  *
  12.  * James Pritchett
  13.  */
  14.  
  15. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16.  
  17. /* Compiling instructions:
  18.  *
  19.  * VIEW was originally written to use memory-mapping for all video output
  20.  * via an enhanced version of the BDS "txtplot" function.  The source for
  21.  * txtplot() (version for the NEC PC-8801A computer) is given in the file 
  22.  * TXTPLOT.CSM, and can easily be adapted for other systems supporting
  23.  * memory-mapped video.  The file TXTPLOT.C contains a version of the same
  24.  * function, written in C, that does NOT use memory-mapping.  See the 
  25.  * file VIEW151.DOC for more info on these functions.
  26.  * 
  27.  * The commands to compile/link VIEW:
  28.  *
  29.  * WITH memory-mapping:
  30.  *    SUBMIT CASM TXTPLOT
  31.  *    CC VIEW 
  32.  *    L2 VIEW TXTPLOT -L WILDEXP
  33.  *
  34.  * WITHOUT memory-mapping:
  35.  *    CC TXTPLOT
  36.  *    CC VIEW 
  37.  *    L2 VIEW TXTPLOT -L WILDEXP
  38.  *
  39.  */ 
  40.  
  41. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  42.  
  43. #include <bdscio.h>
  44.  
  45. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  46.  
  47.                     /* * * * * * * * * * * * * * *
  48.                      * NON-USER DEFINED SYMBOLS  *
  49.                      * * * * * * * * * * * * * * */
  50.  
  51. /* None of these symbols should need revision for porting to other systems */
  52.  
  53. /* For opening message */
  54.  
  55. #define VERSION   "1.51"
  56. #define DATE      "10/10/85 (12/09/85)"
  57.  
  58. /* File buffer definitions */
  59.  
  60. /* NOTE:  If your TPA is too small to handle a 32K buffer, or
  61.  * if your TPA is really big and can handle more, then you
  62.  * should reset SEGBLKS to an appropriate number.
  63.  */
  64.  
  65. #define SEGBLKS   128                   /* 128 recs per segment */
  66. #define SEGSIZE   (SEGBLKS * SECSIZ)    /* segment = 16K */
  67. #define FBLKS     (2 * SEGBLKS)         /* 2 segments at a time */
  68. #define FSIZE     (2 * SEGSIZE)         /* 2 segments in buffer */
  69. #define xseg      buffer                /* xseg at top of buffer */
  70.  
  71. /* Macros for buffer-handling */
  72.  
  73. #define atend() (*botptr == CPMEOF)
  74. #define attop() ((topptr == xseg) && !curxseg)
  75. #define topfault(p)  ((p < (xseg+2)) && curxseg)
  76. #define botfault(p)  ((p == bufend) && !lastseg)
  77.  
  78. /* ASCII defines */
  79.  
  80. #define CNTLB   0x02
  81. #define CNTLC   0x03
  82. #define CNTLE   0x05
  83. #define BS      0x08
  84. #define LF      0x0a
  85. #define CR      0x0d
  86. #define CNTLN   0x0e
  87. #define ESC     0x1b
  88. #define MASK    0x7f                    /* for parity-strip */
  89.  
  90. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  91.  
  92.                 /* * * * * * * * * * * * *
  93.                  * USER-DEFINED SYMBOLS  *
  94.                  * * * * * * * * * * * * */
  95.  
  96. /* The following should be customized for individual systems.  The 
  97.  * values given here are for an NEC PC-8801A computer.
  98.  */
  99.  
  100. /* Screen size: */
  101.  
  102. #define MAXROW      24          /* Number of rows on screen */
  103. #define LASTROW     23          /* MAXROW-1 */
  104.  
  105. /* Memory-mapped video parameters: */
  106.  
  107. #define BASE        0x0f300     /* Video memory base address */
  108. #define XSIZE       24          /* Number of lines in display */
  109. #define YSIZE       120         /* Characters per line */
  110.  
  111. /* Macros for screen routines:
  112.  * 
  113.  * The following four functions are defined as macros: clear screen,
  114.  * home cursor, move cursor to bottom right corner of screen, insert
  115.  * blank line at cursor location.  These will probably have to be
  116.  * customized for the proper escape/control sequences for a particular
  117.  * terminal/computer.  If any of these are not available as simple
  118.  * escape/control sequences, you may want to write functions to perform
  119.  * the same actions.  Also, if you use the non-memory-mapped version of
  120.  * TXTPLOT, you may want to define "cursbot" as a call to the "gotoxy"
  121.  * function given in TXTPLOT.C.  Otherwise, this is the only "gotoxy"
  122.  * call in the program, so a separate function is unnecessary.
  123.  */
  124.  
  125. #define clear()     putch(CNTLZ)
  126. #define home()      putch(0x01e)
  127. #define cursbot()   putch(ESC); putch('='); putch('7'); putch('m')
  128. #define lnins()     putch(ESC); putch('E')
  129.  
  130. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  131.  
  132. /* global variables */
  133.  
  134. int     tabsiz;             /* Size of tabs (= 8 or given on command line) */
  135. int     curxseg;            /* Number of first segment in memory */
  136. int     lastseg;            /* = TRUE if last segment of file is in
  137.                              * memory, FALSE if not.
  138.                              */
  139. int     fd;
  140. int     lastrow;            /* Last row plotted on screen */
  141. char    *topptr, *botptr;   /* Pointers into text buffer.  These point
  142.                              * to the lines of text at top and bottom of
  143.                              * screen.
  144.                              */
  145. char    *yseg;              /* Pointer to second buffer segment */
  146. char    *bufend;            /* Pointer to end of buffer */
  147. char    buffer[FSIZE];
  148.  
  149. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  150.  
  151. main(argc,argv)
  152. int  argc;
  153. char **argv;
  154. {
  155.     char c;
  156.  
  157.     wildexp(&argc, &argv);
  158.     printf("VIEW -- Version %s   James Pritchett, %s\n\n",VERSION,DATE);
  159.  
  160.  
  161. /* If too few arguments, give a usage summary */
  162.  
  163.     if (argc < 2) {
  164.         printf("USAGE: VIEW [-t] <list of files>\n");
  165.         printf("       t = tab size (defaults to 8 spaces)\n");
  166.         printf("       Ambiguous filenames allowed\n");
  167.         exit();
  168.     }
  169.  
  170.  
  171. /* Tabsize argument must be first argument */
  172.  
  173.     if (*(argv[1]) == '-') {
  174.         tabsiz = atoi(argv[1]+1);
  175.         if (!tabsiz)                /* If error on atoi, set to default */
  176.             tabsiz = 8;
  177.         argc--;
  178.         argv++;                     /* Point past the tab argument */
  179.     }
  180.     else
  181.         tabsiz = 8;
  182.  
  183.     printf("\t<RET> = Forward line   <SPACE> = Forward screen\n");
  184.     printf("\t<BS>  = Backward line  <ESC>   = Backward screen\n");
  185.     printf("\t^B    = Top of file    ^E      = End of file\n");
  186.     printf("\t^N    = Next file      ^C      = Exit program\n");
  187.  
  188.  
  189. /* Initialize memory-mapped video */
  190.  
  191.     setplot(BASE,XSIZE,YSIZE);
  192.  
  193. /* Set up buffer pointers */
  194.  
  195.     bufend = buffer + FSIZE - 1;
  196.     yseg = buffer + SEGSIZE;
  197.  
  198.  
  199. /* Main event:  Get files and process commands */
  200.  
  201.     while (--argc) {
  202.         if (getfile(*(++argv)) == ERROR)
  203.             continue;       /* just skip bad filenames */
  204.         while ((c = getchar()) != CNTLN) {
  205.             switch (c) {
  206.                 case CR:     nextln();
  207.                              break;
  208.                 case ' ':    nextscn();
  209.                              break;
  210.                 case BS:     backln();
  211.                              break;
  212.                 case ESC:    backscn();
  213.                              break;
  214.                 case CNTLB:  tobegin();
  215.                              break;
  216.                 case CNTLE:  toend();
  217.                              break;
  218.                 case CNTLC:  exit();
  219.             }
  220.             cursbot();          /* Re-locate cursor after all commands */
  221.         }
  222.     close(fd);
  223.     }
  224. }
  225.  
  226. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  227.  
  228. int  getfile(fname)             /* Read in a file */
  229. char *fname;
  230. {
  231.  
  232.     topptr = 0;     /* reset this pointer when opening new file */
  233.     if ((fd = open(fname,0)) == ERROR) {
  234.         printf("\nERROR: Can't open file.\n");
  235.         return(ERROR);  
  236.     }
  237.     printf("\nLoading %s . . .",fname);
  238.     curxseg = 1;        /* this causes tobegin() to load the file */
  239.     tobegin();          /* Load and display first screen */
  240.     cursbot();          /* Locate cursor out of the way */
  241.     return(0);          /* Return OK */
  242. }
  243.  
  244. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  245.  
  246. void fillbuff(seg)      /* Fill the buffer with two file segments, starting
  247.                          * with "seg".
  248.                          */
  249. int seg;
  250. {
  251.     int     numread;
  252.  
  253.     lastseg = FALSE;    /* Start from this assumption */
  254.     curxseg = seg;      /* First segment = seg */
  255.     seek(fd,(seg * SEGBLKS),0);     /* find it */
  256.     if ((numread = read(fd,buffer,FBLKS)) == ERROR) {
  257.         printf("\nERROR: Disk read error.\n");
  258.         exit();     /* all read errors crash the program */
  259.     }
  260.  
  261. /* If we didn't fill the buffer, or if the last char is an EOF, then
  262.  * this must be all there is, and the last segment of the file is
  263.  * in memory.  So set the flag TRUE.
  264.  */
  265.  
  266.     if ((numread != FBLKS) || (*bufend == CPMEOF))
  267.         lastseg = TRUE;
  268. }
  269.  
  270. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  271.  
  272. void nextln()           /* Go forward one line */
  273. {
  274.     char    *temp;
  275.  
  276.     if (atend())
  277.         return;
  278.     putch(LF);      /* this causes a scroll up one line */
  279.     temp = ptrdown(botptr);    /* be sure segfault is taken care of first */
  280.     topptr = ptrdown(topptr);
  281.     txtplot(botptr,LASTROW,0,tabsiz);  /* if there was a segfault,  */
  282.     botptr = temp;               /* botptr was revised */
  283. }
  284.  
  285. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  286.  
  287. void nextscn()      /* Go forward one screen */
  288. {
  289.     if (atend())
  290.         return;
  291.     topptr = botptr;    /* botptr => next topline */
  292.     dispscn();
  293. }
  294.  
  295. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  296.  
  297. void backln()           /* Go back one line */
  298. {
  299.     if (attop())
  300.         return;
  301.     home();
  302.     lnins();        /* a scroll down */
  303.     topptr = ptrup(topptr);
  304.     if (lastrow < MAXROW)  /* bug fix: if last screen has < 24 lines, botptr */
  305.         lastrow++;     /*          should remain unchanged               */
  306.     else
  307.         botptr = ptrup(botptr);
  308.     txtplot(topptr,0,0,tabsiz);
  309. }
  310.  
  311. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  312.  
  313. void backscn()          /* Go backward one screen */
  314. {
  315.     int x;
  316.  
  317.     if (attop())
  318.         return;
  319.     for (x = 0; x < MAXROW && !attop(); x++)
  320.         topptr = ptrup(topptr);     /* move back 24 lines or to beginning */
  321.     dispscn();
  322. }
  323.  
  324. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  325.  
  326. void tobegin()          /* Go to beginning of file */
  327. {
  328.     if (attop())
  329.         return;
  330.     if (curxseg)        /* seek to beginning if segment 0 is not in memory */
  331.         fillbuff(0);
  332.     topptr = buffer;
  333.     dispscn();
  334. }
  335.  
  336. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  337.  
  338. void toend()            /* Go to end of file */
  339. {
  340.     int x, lastxseg;
  341.  
  342.     if (atend())
  343.         return;
  344.     if (!lastseg) {     /* seek to end if not in memory */
  345.         lastxseg = ((cfsize(fd) - 1)/SEGBLKS) - 1;
  346.         fillbuff(lastxseg);
  347.         botptr = yseg;
  348.     }
  349.     while (!atend())        /* find the bottom of file first */
  350.         botptr = ptrdown(botptr);
  351.     topptr = botptr;
  352.     for (x = 0; x < MAXROW && !attop(); x++)
  353.         topptr = ptrup(topptr);    /* then figure topline from there */
  354.     dispscn();
  355. }
  356.  
  357. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  358.  
  359. char *ptrdown(ptr)          /* Move a pointer down one line in buffer */
  360. char *ptr;
  361. {
  362.     while (*ptr != CPMEOF) {
  363.         if (botfault(ptr)) {    /* if we have more to read, then do so */
  364.             ptr = bufup(ptr);
  365.             readseg(yseg);
  366.         }
  367.         if (((*ptr++) & MASK) == LF)  /* strip parity */
  368.             break;
  369.     }
  370.     return ptr;
  371. }
  372.  
  373. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  374.  
  375. char *ptrup(ptr)        /* Move a pointer up one line in buffer */
  376. char *ptr;
  377. {
  378.     if (topfault(ptr)) {   /* we have to check before skipping back */
  379.         ptr = bufdn(ptr);  /* over LF   */
  380.         readseg(xseg);
  381.     }
  382.     ptr--;          /* go back past LF */
  383.     while ((*(ptr - 1) & MASK) != LF && (ptr != buffer)) {
  384.         if (topfault(ptr)) {    /* and check while going back */
  385.             ptr = bufdn(ptr);
  386.             readseg(xseg);
  387.         }
  388.         ptr--;
  389.     }
  390.     return ptr; 
  391. }
  392.  
  393. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  394.  
  395. void dispscn()      /* Fill the screen, starting from *topptr */
  396. {
  397.     char *temp;
  398.  
  399. /* note: this routine displays MAXROW lines, or as many as remain in 
  400.  * file, whichever is less, starting with the line pointed to by
  401.  * topptr.  It locates the next line, THEN displays the current
  402.  * line, so as to force any segment faults before displaying the
  403.  * line in which that fault occurred.  temp points to the next line,
  404.  * botptr to the current line.  If a segfault occurs, botptr will
  405.  * be adjusted as necessary by bufup(), thus assuring the proper
  406.  * current line will be displayed.  At the conclusion of this
  407.  * routine, botptr is pointing to the next line in the file, or
  408.  * to the end of file, and lastrow = the number of lines currently
  409.  * on the screen (botptr should not be moved up until MAXROW lines are
  410.  * on the screen).
  411.  */
  412.  
  413.     clear();
  414.     for (lastrow = 0, botptr = topptr; lastrow < MAXROW && !atend();
  415.                  lastrow++, botptr = temp) {
  416.         temp = ptrdown(botptr);
  417.         txtplot(botptr,lastrow,0,tabsiz);
  418.     }
  419. }
  420.  
  421. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  422.  
  423. char getchar()   /* gets a char with no echo */
  424. {
  425.     char c;
  426.  
  427.     while (!(c = bdos(6,-1)))
  428.         ;
  429.     return c;
  430. }
  431.  
  432. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  433.  
  434. char *bufup(p)      /* Move yseg into xseg position */
  435. char *p;
  436. {
  437.     movmem(yseg,xseg,SEGSIZE);
  438.     p -= SEGSIZE;       /* revise all pointers */
  439.     topptr -= SEGSIZE;
  440.     botptr -= SEGSIZE;
  441.     return(p);
  442. }
  443.  
  444. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  445.  
  446. char *bufdn(p)      /* Move xseg into yseg position */
  447. char *p;
  448. {
  449.     movmem(xseg,yseg,SEGSIZE);
  450.     p += SEGSIZE;       /* revise all pointers */
  451.     topptr += SEGSIZE;
  452.     botptr += SEGSIZE;
  453.     return(p);
  454. }
  455.  
  456. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  457.  
  458. void readseg(segstart)  /* routine to read in a new segment */
  459. char *segstart;     /* segstart is where the segment is to go */
  460. {
  461.     int firstrec, numread;
  462.  
  463.     if (segstart == xseg) {  /* if we're reading in a new xseg, */
  464.         curxseg--;           /* then we're scrolling backwards */
  465.         firstrec = curxseg * SEGBLKS;
  466.     }
  467.     else {      /* if we're reading a yseg, then we're scrolling forwards */
  468.         curxseg++;
  469.         firstrec = (curxseg + 1) * SEGBLKS;
  470.     }
  471.  
  472.     seek(fd,firstrec,0);
  473.     if ((numread = read(fd,segstart,SEGBLKS)) == ERROR) {
  474.         printf("\nERROR: Disk read error.\n");
  475.         exit();     /* all read errors crash the program */
  476.     }
  477.     if ((numread != SEGBLKS) || (*bufend == CPMEOF))
  478.         lastseg = TRUE;
  479. }
  480.  
  481. /* end */
  482.  
  483.   movmem(xseg,yseg,SEGSIZE);
  484.     p +=