home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / communic / pcmail / main / pager.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  13.7 KB  |  532 lines

  1. /*++
  2. /* NAME
  3. /*      pager 3
  4. /* SUMMARY
  5. /*      pager for text files
  6. /* PROJECT
  7. /*      pc-mail
  8. /* PACKAGE
  9. /*      mail
  10. /* SYNOPSIS
  11. /*      #include "pager.h"
  12. /*
  13. /*      File *open_pager()
  14. /*
  15. /*      void close_pager(p)
  16. /*      File *p;
  17. /*
  18. /*      void set_pager(p)
  19. /*      File *p;
  20. /*
  21. /*      void app_pager(p,s)
  22. /*      File *p;
  23. /*      char *s;
  24. /*
  25. /*      void del_pager(p)
  26. /*      File *p;
  27. /*
  28. /*      void mesg_pager(p,m)
  29. /*      File *p;
  30. /*      char *m[];
  31. /*
  32. /*      void sort_pager(p,dir)
  33. /*      File *p;
  34. /*
  35. /*      int cp_pager(path)
  36. /*      char *path;
  37. /*
  38. /*      int pr_pager()
  39. /*
  40. /*      int rd_pager(p,path)
  41. /*      File *p;
  42. /*      char *path;
  43. /*
  44. /*      char *gets_pager();
  45. /*      File *p;
  46. /*
  47. /*      void puts_pager(s);
  48. /*      char *s;
  49. /*
  50. /*      int ds_pager()
  51. /*
  52. /*      int pr_pager()
  53. /*
  54. /*      int up_pager()
  55. /*
  56. /*      int dn_pager()
  57. /*
  58. /*      int pu_pager()
  59. /*
  60. /*      int pd_pager()
  61. /* DESCRIPTION
  62. /*      The pager provides acces to a pager file which is displayed
  63. /*      on the screen in the middle window. Some functions operate
  64. /*    on what is called the "current" pager file. All functions
  65. /*    have access to the contents of the middle screen window only.
  66. /*
  67. /*      open_pager() creates a new (empty) pager file. The return value
  68. /*      should be used in subsequent accesses to the file. Sets the
  69. /*      current file.
  70. /*
  71. /*      close_pager() releases storage for a pager file. Sets the
  72. /*      current file to none if that is the one being deleted.
  73. /*
  74. /*      app_pager() appends a new line of text to the end of a pager file.
  75. /*      Sets the current file.
  76. /*
  77. /*      del_pager() deletes the line at the current cursor position. Sets the
  78. /*      current file.
  79. /*
  80. /*      mesg_pager() invokes app_pager() to copy a null-terminated array of
  81. /*    strings to a pager file. Since it invokes app_pager(), the current
  82. /*    pager file is set as well. Pager files filled by mesg-pager()
  83. /*    will not be displayed with an '-- end of display --' line at their end.
  84. /*
  85. /*      ins_pager() inserts a line at the current cursor position. Sets the
  86. /*      current file.
  87. /*
  88. /*      scan_pager() takes similar arguments as scanf(3), reads from the
  89. /*      line at the current cursor position and returns the number of
  90. /*      successfull conversions done. Does not set the current file.
  91. /*
  92. /*      sort_pager() sorts a file alphabetically. Sets the current file.
  93. /*      The dir argument selects the direction of sort (FORW_SORT, BACK_SORT).
  94. /*
  95. /*      set_pager() sets the current file.
  96. /*
  97. /*      gets_pager() returns a pointer to the current line in the
  98. /*      current file, or a null pointer is there is none.
  99. /*
  100. /*      puts_pager() replaces the current line in the current file.
  101. /*
  102. /*      cp_pager() copies the contents of current pager file
  103. /*      to a normal (external) file. It returns a nonzero status if
  104. /*      an error occurred (bad path, write error,...).
  105. /*
  106. /*      pr_pager() copies the current pager file to the printer.
  107. /*
  108. /*      rd_pager() appends a permanent file to the current pager file.
  109. /*      It returns a nonzero status if an error occurred. Sets the current file.
  110. /*    rd_pager() reads through the ascf(3) ascii filter, so that it is
  111. /*    suitable for viewing word-processor files.
  112. /*
  113. /*      up_pager() moves the cursor one line up, if there is one. The
  114. /*    screen is scrolled when the cursor was at the top of the screen.
  115. /*
  116. /*      dn_pager moves the cursor one line down, if there is one. The
  117. /*    screen is scrolled when the cursor was at the bottom of the screen.
  118. /*
  119. /*      pu_pager() displays a page of text that precedes the one on the
  120. /*      screen, or as much as there is.
  121. /*
  122. /*      pd_pager() displays the next page of text, or as much as there is.
  123. /* FUNCTIONS AND MACROS
  124. /*      printcl(), printat(), beep(), propen(), prclose(),ascopen(),
  125. /*    ascclose(), ascget()
  126. /* SEE ALSO
  127. /*      path(3), window(3), window(5), asc(3)
  128. /* DIAGNOSTICS
  129. /*      The buzzer makes noise when attempt is made to move the
  130. /*      cursor beyond the beginning or end of the pager file.
  131. /*      The program aborts with an error message if references are made
  132. /*      to the "current file" or "current line" if there is none.
  133. /* BUGS
  134. /*      It looks a lot like an editor, but it isn't.
  135. /*
  136. /*    No optimization. It just overwrites the whole middle window.
  137. /* AUTHOR(S)
  138. /*      W.Z. Venema
  139. /*      Eindhoven University of Technology
  140. /*      Department of Mathematics and Computer Science
  141. /*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  142. /* CREATION DATE
  143. /*      Fri Apr  3 22:06:00 GMT+1:00 1987
  144. /* LAST MODIFICATION
  145. /*    90/01/22 13:02:21
  146. /* VERSION/RELEASE
  147. /*    2.1
  148. /*--*/
  149.  
  150. #include <stdio.h>
  151.  
  152. #include "defs.h"
  153. #include "window.h"
  154. #include "pager.h"
  155. #include "path.h"
  156. #include "ascf.h"
  157.  
  158. hidden File *curfile = NULL;        /* head of the current file */
  159.  
  160. /* open_pager - create pager file and set current file */
  161.  
  162. public File *open_pager()
  163. {
  164.     register File *p = curfile = (File *) myalloc(sizeof(File));
  165.  
  166.     p->top = p->curr = p->head = p->last = NULL;
  167.     p->opts = 0;
  168.     return (p);
  169. }
  170.  
  171. /* close_pager - release memory in a pager file */
  172.  
  173. public void close_pager(p)
  174. register File *p;
  175. {
  176.     register Line *q;
  177.  
  178.     if (p) {
  179.     for (q = p->head; q; q = q->next)    /* release lines */
  180.         free((char *) q);
  181.     if (curfile == p)            /* unset current file */
  182.         curfile = 0;
  183.     free((char *) p);            /* release header */
  184.     }
  185. }
  186.  
  187. /* app_pager - append line at end of file and set current file */
  188.  
  189. public  app_pager(p, s)
  190. register File *p;
  191. char   *s;
  192. {
  193.     register Line *l = (Line *) myalloc(sizeof(Line) + strlen(s));
  194.  
  195.     if (p->head == 0) {                /* first line in the file */
  196.     p->head = p->top = p->curr = l;
  197.     } else {                    /* real append */
  198.     p->last->next = l;
  199.     }
  200.     l->next = NULL;                /* since it is last */
  201.     l->prev = p->last;                /* since it is last */
  202.     p->last = l;                /* since it is last */
  203.  
  204.     strcpy(l->line, s);                /* copy the line */
  205.  
  206.     curfile = p;                /* set current file */
  207. }
  208.  
  209. /* del_pager - delete line at cursor and set current file (untested!) */
  210.  
  211. public void del_pager(p)
  212. register File *p;
  213. {
  214.     register Line *l = p->curr;
  215.  
  216.     if (l) {
  217.     if (l->prev)
  218.         l->prev->next = l->next;
  219.     if (l->next)
  220.         l->next->prev = l->prev;
  221.     if (l == p->head)
  222.         p->curr = p->head = l->next;
  223.     if (l == p->top)
  224.         p->curr = p->top = l->next ? l->next : l->prev;
  225.     if (l == p->last)
  226.         p->curr = p->last = l->prev;
  227.     if (l == p->curr)
  228.         p->curr = l->next;
  229.     free((char *) l);
  230.     }
  231.     curfile = p;
  232. }
  233.  
  234. /* set_pager - set the current file; use with care */
  235.  
  236. public void set_pager(p)
  237. File   *p;
  238. {
  239.     curfile = p;
  240. }
  241.  
  242.  /*
  243.   * The following functions provide an easy interface to the keyboard
  244.   * interpreter routines. The keyboard interpreter just associates a key
  245.   * stroke with a function call, does not care what a function does and has
  246.   * almost no facility for passing function arguments. Although the keyboard
  247.   * interpreter manipulates cursor and page coordinates when the some keys
  248.   * are hit, it never knows which keys affect what the user sees on the
  249.   * screen. That explains why the following functions rely on the above ones
  250.   * for setting the "current file". It may also explain why the above
  251.   * routines do not immediately update the terminal screen, whereas the
  252.   * routines below do.
  253.   */
  254.  
  255. /* ds_pager - display a page of the current pager file */
  256.  
  257. public int ds_pager()
  258. {
  259.     static char endline[] = "-- end of display --";
  260.  
  261.     if (curfile && curfile->curr) {
  262.     register Line *p;
  263.     register int k;
  264.  
  265.     for (p = curfile->top, k = 0; p && k < midwin->size; p = p->next)
  266.         k += p->llen = printcl(midwin, p->lineno = k, p->line);
  267.     if (k < midwin->size)
  268.         printcl(midwin, k++, (curfile->opts & PG_NOEND) ? "" : endline);
  269.     while (k < midwin->size)
  270.         printcl(midwin, k++, "");
  271.     printat(midwin, curfile->curr->lineno, "");
  272.     } else {
  273.     register int k;
  274.  
  275.     printcl(midwin, 0, (curfile->opts & PG_NOEND) ? "" : endline);
  276.     for (k = 1; k < midwin->size; k++)
  277.         printcl(midwin, k, "");
  278.     printat(midwin, 0, "");
  279.     }
  280.     return (0);                    /* screen up-to-date */
  281. }
  282.  
  283. /* up_pager - up-arrow key hit. check cursor position */
  284.  
  285. public int up_pager()
  286. {
  287.     register Line *p = curfile ? curfile->curr : 0;
  288.  
  289.     if (p == 0 || p->prev == 0) {
  290.     beep();
  291.     } else {
  292.     if (p->lineno == 0)
  293.         pu_pager();
  294.     printat(midwin, (curfile->curr = p->prev)->lineno, "");
  295.     }
  296.     return (0);
  297. }
  298.  
  299. /* dn_pager - down-arrow key hit. check cursor position */
  300.  
  301. public int dn_pager()
  302. {
  303.     register Line *p = curfile ? curfile->curr : 0;
  304.  
  305.     if (p == 0 || p->next == 0) {
  306.     beep();
  307.     } else {
  308.     if (p->lineno + p->llen >= midwin->size)
  309.         pd_pager();
  310.     printat(midwin, (curfile->curr = p->next)->lineno, "");
  311.     }
  312.     return (0);
  313. }
  314.  
  315. /* pu_pager - display preceding page of info */
  316.  
  317. public int pu_pager()
  318. {
  319.     register Line *p;
  320.     register int k;
  321.  
  322.     if (curfile && (p = curfile->top) && curfile->top->prev) {
  323.     for (k = 0; k < midwin->size && p; k += p->llen, p = p->prev)
  324.         curfile->top = p;
  325.     curfile->curr = curfile->top;
  326.     ds_pager();
  327.     } else {
  328.     beep();
  329.     }
  330.     return (0);
  331. }
  332.  
  333. /* pd_pager - display next page of info */
  334.  
  335. public int pd_pager()
  336. {
  337.     register Line *p = curfile ? curfile->top : 0;
  338.     register int k;
  339.     register Line *dummy;
  340.  
  341.     for (k = 0; k < midwin->size && p; k += p->llen, p = p->next)
  342.     dummy = p;
  343.     if (p) {
  344.     curfile->curr = curfile->top = dummy;
  345.     ds_pager();
  346.     } else {
  347.     beep();
  348.     }
  349.     return (0);
  350. }
  351.  
  352.  /*
  353.   * The following functions copy external files to pager file and vice-versa.
  354.   * There is a limited error detection facility in the form of nonzero return
  355.   * values.
  356.   */
  357.  
  358. /* cp_pager - copy current pager file to permanent file */
  359.  
  360. public int cp_pager(path)
  361. char   *path;
  362. {
  363.     register FILE *fp;
  364.  
  365.     if (curfile && (fp = fopen(path, "w"))) {
  366.     register Line *pp;
  367.     int     err;
  368.  
  369.     for (pp = curfile->head; pp; pp = pp->next)
  370.         fputs(pp->line, fp), putc('\n', fp);
  371.     err = (fflush(fp) || ferror(fp));
  372.     fclose(fp);
  373.     return (err);
  374.     } else {
  375.     return (-1);
  376.     }
  377. }
  378.  
  379. /* pr_pager - print pager file on default printer */
  380.  
  381. public int pr_pager()
  382. {
  383.     register FILE *fp;
  384.  
  385.     if (curfile && (fp = propen())) {
  386.     register Line *pp;
  387.     int     err;
  388.  
  389.     for (pp = curfile->head; pp; pp = pp->next)
  390.         fputs(pp->line, fp), putc('\n', fp);
  391.     err = (fflush(fp) || ferror(fp));
  392.     prclose(fp);
  393.     return (err);
  394.     } else {
  395.     return (-1);
  396.     }
  397. }
  398.  
  399. /* rd_pager - copy ordinary file via filter to pager file */
  400.  
  401. public int rd_pager(p, path)
  402. File   *p;
  403. char   *path;
  404. {
  405.     register FILE *fp;
  406.  
  407.     if (p && (fp = ascopen(path, "r"))) {    /* init the filter */
  408.     char    buf[BUFSIZ];
  409.     int     err;
  410.  
  411.     while (ascgets(buf, sizeof(buf), fp))    /* copy to pager file */
  412.         app_pager(p, buf);        /* line by line */
  413.  
  414.     err = ferror(fp);            /* check for errors */
  415.     ascclose(fp);
  416.     return (err);
  417.     } else {
  418.     return (-1);
  419.     }
  420. }
  421.  
  422. /* fwdcmp, revcmp - compare lexical order of lines */
  423.  
  424. hidden int fwdcmp(l1, l2)
  425. Line  **l1,
  426.       **l2;
  427. {
  428.     return (strcmp((*l1)->line, (*l2)->line));
  429. }
  430.  
  431. hidden int revcmp(l1, l2)
  432. Line  **l1,
  433.       **l2;
  434. {
  435.     return (strcmp((*l2)->line, (*l1)->line));
  436. }
  437.  
  438. /* sort_pager - sort a pager file */
  439.  
  440. public void sort_pager(pp, dir)
  441. File   *pp;
  442. int     dir;
  443. {
  444.     register Line *l;
  445.     register int i;
  446.     int     lines;
  447.     Line  **lvec;
  448.  
  449.     /* Build a vector with pointers to line structures. */
  450.  
  451.     for (i = 0, l = pp->head; l; l = l->next)    /* count nbr of lines */
  452.     i++;
  453.     if (i <= 1)                    /* no work */
  454.     return;
  455.  
  456.     lvec = (Line **) myalloc((lines = i) * sizeof(*lvec));
  457.  
  458.     for (i = 0, l = pp->head; l; l = l->next)    /* fill vector */
  459.     lvec[i++] = l;
  460.  
  461.     /* Sort the vector with pointers to line structures. */
  462.  
  463.     qsort((char *) lvec, lines, sizeof(*lvec),
  464.       dir == FORW_SORT ? fwdcmp : revcmp);
  465.  
  466.     /* Restore links between line structures and destroy the sorted vector */
  467.  
  468.     for (i = 0; i < lines - 1; i++)        /* fix forward links */
  469.     lvec[i]->next = lvec[i + 1];
  470.     lvec[i]->next = NULL;
  471.  
  472.     lvec[0]->prev = NULL;            /* fix backward links */
  473.     for (i = 1; i < lines; i++)
  474.     lvec[i]->prev = lvec[i - 1];
  475.  
  476.     pp->head = pp->top = pp->curr = lvec[0];    /* fix file header */
  477.     pp->last = lvec[lines - 1];
  478.  
  479.     free((char *) lvec);            /* release vector */
  480.  
  481.     curfile = pp;                /* set current file */
  482. }
  483.  
  484. /* gets_pager - return current line in current file */
  485.  
  486. public char *gets_pager()
  487. {
  488.     return (curfile && curfile->curr ? curfile->curr->line : 0);
  489. }
  490.  
  491. /* puts_pager - replace line (cleanup this mess) */
  492.  
  493. public void puts_pager(s)
  494. char   *s;
  495. {
  496.     if (curfile == 0 || curfile->curr == 0) {    /* no-no if there is no line */
  497.     fatal("puts_pager: no current file");
  498.     } else {
  499.     register Line *old = curfile->curr;    /* get current line */
  500.     register Line *new = (Line *) myalloc(sizeof(Line) + strlen(s));
  501.  
  502.     new->prev = old->prev;            /* fill it in */
  503.     new->next = old->next;
  504.     new->lineno = old->lineno;
  505.     strcpy(new->line, s);
  506.     if (new->next)                /* check next line */
  507.         new->next->prev = new;
  508.     if (new->prev)                /* check previous line */
  509.         new->prev->next = new;
  510.     if (old == curfile->head)        /* check file head */
  511.         curfile->head = new;
  512.     if (old == curfile->top)        /* check file display */
  513.         curfile->top = new;
  514.     if (old == curfile->last)        /* check file tail */
  515.         curfile->last = new;
  516.     free((char *) curfile->curr);        /* release old line */
  517.     curfile->curr = new;            /* set current line */
  518.     }
  519. }
  520.  
  521. /* mesg_pager - copy null-terminated array of strings to pager file */
  522.  
  523. public void mesg_pager(pp, msg)
  524. register File *pp;
  525. register char **msg;
  526. {
  527.     pp->opts |= PG_NOEND;            /* suppress end marker */
  528.  
  529.     while (*msg)
  530.     app_pager(pp, *msg++);
  531. }
  532.