home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / VIEW.C < prev    next >
C/C++ Source or Header  |  1992-06-01  |  7KB  |  325 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "session.h"
  4. #include "tty.h"
  5. #include "commands.h"
  6. #include "socket.h"
  7.  
  8. #include <dos.h>
  9.  
  10. static long lineseek __ARGS((FILE *fp,long offset,int nlines,int width));
  11. static int ctlproc __ARGS((int c));
  12.  
  13. #define    ESC    27
  14. #define    CTLD    4
  15. #define    CTLU    21
  16. #define    FF    CTLL
  17. #define    CTLL    12
  18. #define    CTLN    14
  19. #define    CTLP    16
  20. #define    CTLV    22
  21.  
  22. int
  23. doview(argc,argv,p)
  24. int argc;
  25. char *argv[];
  26. void *p;
  27. {
  28.     FILE *fp;
  29.  
  30.     if((fp = fopen(argv[1],READ_TEXT)) == NULLFILE){
  31.         printf("Can't read %s\n",argv[1]);
  32.         return 1;
  33.     }
  34.     newproc("view",512,view,0,(void *)fp,NULL,0);
  35.     return 0;    
  36. }
  37. /* Random-access file display program. Used both to read local
  38.  * files with the "view" command, and by the FTP client to view
  39.  * directory listings, temporary copies of read files, etc.
  40.  *
  41.  */
  42. void
  43. view(s,p1,p2)
  44. int s;        /* If non-zero, poll interval for a changing file */
  45. void *p1;    /* Open file pointer to read from */
  46. void *p2;    /* If non-null, name to give to session. We free it */
  47. {
  48.     struct session *sp;
  49.     FILE *fp;
  50.     char *name;
  51.     int c;
  52.     long offset = 0;
  53.     int row,col;
  54.     int cols = 80;
  55.     int rows = 25;
  56.     int32 polldelay = 0;
  57.  
  58.     fp = (FILE *)p1;
  59.     if(p2 != NULL)
  60.         name = (char *)p2;
  61.     else
  62.         name = fpname(fp);
  63.  
  64.     if((sp = newsession(name,VIEW,1)) == NULLSESSION)
  65.         return;
  66.  
  67.     if(p2 != NULL)
  68.         free(name);
  69.  
  70.     if(s != 0)
  71.         polldelay = s;
  72.     sp->ctlproc = ctlproc;
  73.     /* Put tty into raw mode so single-char responses will work */
  74.     sp->ttystate.echo = sp->ttystate.edit = 0;
  75.     for(;;){
  76.         fseek(fp,offset,SEEK_SET);
  77.         putchar(FF);    /* Clear screen */
  78.         /* Display a screen's worth of data, keeping track of
  79.          * cursor location so we know when the screen is full
  80.          */
  81.         col = row = 0;
  82.         while((c = getc(fp)),c != EOF){
  83.             switch(c){
  84.             case '\n':
  85.                 row++;
  86.                 col = 0;
  87.                 break;
  88.             case '\t':
  89.                 if(col < cols - 8)
  90.                     col = (col + 8) & ~7;
  91.                 break;
  92.             default:
  93.                 col++;
  94.                 break;
  95.             }
  96.             if(col >= cols){
  97.                 /* Virtual newline caused by wraparound */
  98.                 col = 0;
  99.                 row++;
  100.             }
  101.             if(row >= rows)
  102.                 break;    /* Screen now full */
  103.             putchar(c);
  104.         }
  105. #ifdef    notdef
  106.         if(feof(fp) && offset != 0){
  107.             /* Hit end of file. Back up proper number of
  108.              * lines and try again.
  109.              */
  110.             offset = lineseek(fp,offset,row-rows,cols);
  111.             continue;
  112.         }
  113. #endif
  114.         fflush(stdout);
  115.         /* If we hit the end of the file and the file may be
  116.          * growing, then set an alarm to time out the getchar()
  117.          */
  118.         do {
  119.             if(feof(fp) && polldelay != 0){
  120.                 alarm(polldelay);
  121.             }
  122.             c = getchar();    /* Wait for user keystroke */
  123.             alarm(0L);    /* Cancel alarm */
  124.             if(c != -1 || errno != EALARM)
  125.                 break;    /* User hit key */
  126.             /* Alarm timeout; see if more data arrived by
  127.              * clearing the EOF flag, trying to read
  128.              * another byte, and then testing EOF again
  129.              */
  130.             clearerr(fp);
  131.             (void)getc(fp);
  132.             c = ' ';    /* Simulate a no-op keypress */
  133.         } while(feof(fp));
  134.         switch(c){
  135.         case 'h':    /* Home */
  136.         case 'H':
  137.         case '<':    /* For emacs users */
  138.             offset = 0;
  139.             break;
  140.         case 'e':    /* End */
  141.         case '>':    /* For emacs users */
  142.             fseek(fp,0L,SEEK_END);
  143.             offset = lineseek(fp,ftell(fp),-rows,cols);
  144.             break;
  145.         case CTLD:    /* Down one half screen (for VI users) */
  146.             if(!feof(fp))
  147.                 offset = lineseek(fp,offset,rows/2,cols);
  148.             break;
  149.         case CTLU:    /* Up one half screen (for VI users) */
  150.             offset = lineseek(fp,offset,-rows/2,cols);
  151.             break;
  152.         case 'd':    /* down line */
  153.         case CTLN:    /* For emacs users */
  154.         case 'j':    /* For vi users */
  155.             if(!feof(fp))
  156.                 offset = lineseek(fp,offset,1,cols);
  157.             break;
  158.         case 'D':    /* Down page */
  159.         case CTLV:    /* For emacs users */
  160.             if(!feof(fp))
  161.                 offset = lineseek(fp,offset,rows,cols);
  162.             break;
  163.         case 'u':    /* up line */
  164.         case CTLP:    /* for emacs users */
  165.         case 'k':    /* for vi users */
  166.             offset = lineseek(fp,offset,-1,cols);
  167.             break;
  168.         case 'U':    /* Up page */
  169.         case 'v':    /* for emacs users */
  170.             offset = lineseek(fp,offset,-rows,cols);
  171.             break;
  172.         case 'q':
  173.         case 'Q':
  174.         case ESC:
  175.             goto done;
  176.         default:
  177.             break;    /* Redisplay screen */
  178.         }
  179.     }
  180. done:    fclose(fp);
  181.     freesession(sp);
  182. }
  183. /* Given a starting offset into an open file stream, scan forwards
  184.  * or backwards the specified number of lines and return a pointer to the
  185.  * new offset.
  186.  */
  187. static long
  188. lineseek(fp,start,nlines,width)
  189. FILE *fp;    /* Open file stream */
  190. long start;    /* Offset to start searching backwards from */
  191. int nlines;    /* Number of lines to move forward (+) or back (-) */
  192. int width;    /* Screen width (max line size) */
  193. {
  194.     long offset;
  195.     long *pointers;
  196.     int col = 0;
  197.     int c;
  198.     int newlines = 0;
  199.  
  200.     if(nlines == 0)
  201.         return start;    /* Nothing to do */
  202.  
  203.     if(nlines > 0){        /* Look forward requested # of lines */
  204.         fseek(fp,start,SEEK_SET);
  205.         col = 0;
  206.         while((c = getc(fp)),c != EOF){
  207.             switch(c){
  208.             case '\n':
  209.                 newlines++;
  210.                 col = 0;
  211.                 break;
  212.             case '\t':
  213.                 if(col < width - 8)
  214.                     col = (col + 8) & ~7;
  215.                 break;
  216.             default:
  217.                 col++;
  218.                 break;
  219.             }
  220.             if(col >= width){
  221.                 /* Virtual newline caused by wraparound */
  222.                 col = 0;
  223.                 newlines++;
  224.             }
  225.             if(newlines >= nlines)
  226.                 break;    /* Found requested count */
  227.         }
  228.         return ftell(fp);    /* Could be EOF */
  229.     }
  230.     /* Backwards scan (the hardest)
  231.      * Start back up at most (width + 2) chars/line from the start.
  232.      * This handles full lines followed by expanded newline
  233.      * sequences
  234.      */
  235.     nlines = -nlines;
  236.     offset = (width + 2)*(nlines + 1);
  237.     if(offset > start)
  238.         offset = 0;    /* Go to the start of the file */
  239.     else
  240.         offset = start - offset;
  241.     fseek(fp,offset,SEEK_SET);
  242.  
  243.     /* Keep a circular list of the last 'nlines' worth of offsets to
  244.      * each line, starting with the first
  245.      */
  246.     pointers = (int32 *)calloc(sizeof(long),nlines);
  247.     pointers[newlines++ % nlines] = offset;
  248.  
  249.     /* Now count newlines up but not including the original
  250.      * starting point
  251.      */
  252.     col = 0;
  253.     for(;;){
  254.         c = getc(fp);
  255.         switch(c){
  256.         case EOF:
  257.             goto done;
  258.         case '\n':
  259.             col = 0;
  260.             offset = ftell(fp);
  261.             if(offset >= start)
  262.                 goto done;
  263.             pointers[newlines++ % nlines] = offset;
  264.             break;
  265.         case '\t':
  266.             if(col < width - 8)
  267.                 col = (col + 8) & ~7;
  268.             break;
  269.         default:
  270.             col++;
  271.             break;
  272.         }
  273.         if(col >= width){
  274.             /* Virtual newline caused by wraparound */
  275.             col = 0;
  276.             offset = ftell(fp);
  277.             if(offset >= start)
  278.                 goto done;
  279.             pointers[newlines++ % nlines] = offset;
  280.         }
  281.     }
  282.     done:;
  283.     if(newlines >= nlines){
  284.         /* Select offset pointer nlines back */
  285.         offset = pointers[newlines % nlines];
  286.     } else {
  287.         /* The specified number of newlines wasn't seen, so
  288.          * go to the start of the file
  289.          */
  290.         offset = 0;
  291.     }
  292.     free(pointers);
  293.     return offset;
  294. }
  295.  
  296. /* Handle special keystrokes */
  297. static int
  298. ctlproc(c)
  299. int c;
  300. {
  301.     switch(c){
  302.     case 256 + 71:    /* HOME */
  303.         putc('h',Current->input);
  304.         break;
  305.     case 256 + 72:    /* Cursor up */
  306.         putc('u',Current->input);
  307.         break;
  308.     case 256 + 73:    /* Page up */
  309.         putc('U',Current->input);
  310.         break;
  311.     case 256 + 79:    /* End */
  312.         putc('e',Current->input);
  313.         break;
  314.     case 256 + 80:    /* Cursor down */
  315.         putc('d',Current->input);
  316.         break;
  317.     case 256 + 81:    /* Page down */
  318.         putc('D',Current->input);
  319.         break;
  320.     }
  321.     fflush(Current->input);
  322.     return 0;
  323. }
  324.  
  325.