home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / 2_DSCRL.ZIP / SCRLTEXT.C next >
C/C++ Source or Header  |  1991-04-18  |  11KB  |  385 lines

  1. /***************************************************************
  2. * File:       SCRLTEXT.C
  3. * Purpose:    Simple demo of 2-D scrolling
  4. * Date:       February 1991
  5. * Author:     George Spofford
  6. * Compilers:  MSC 6.0, Turbo C++ 1.0, MetaWare HighC-386 1.7
  7. * Switches:
  8. *   MSC 6.0: -- large model
  9. *     cl -AL -c scrltest.c
  10. *     link scrltest+vidprim;
  11. *   High C:  -- needs both hce.lib and na.lib
  12. *     hc386 -c -DDOS_386 scrltest.c
  13. *     386link scrltest vidprim -lib hce.lib na.lib
  14. *
  15. * Object code may be used freely. Source code may be used freely
  16. * if author and publication are acknowledged.
  17. ****************************************************************/
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <conio.h>
  23. #include "vidprim.h"
  24.  
  25. #define U_ARROW  72
  26. #define D_ARROW  80
  27. #define L_ARROW  75
  28. #define R_ARROW  77
  29. #define PGUP     73
  30. #define PGDN     81
  31. #define HOME     71
  32. #define END      79
  33.  
  34. #define TRUE  1
  35. #define FALSE 0
  36.  
  37. #define TCALLOC( t, n) (t *) calloc (n, sizeof (t))
  38. #define TMALLOC( t, n) (t *) malloc (n * sizeof (t))
  39.  
  40. #define MAXLINE 512
  41.  
  42. typedef struct slist_st {
  43.   char *str;
  44.   struct slist_st *next, *prev;
  45. } slist_t;
  46.  
  47. typedef struct {           /* text-scroll object's
  48.                                 state template */
  49.   bbox_t    bbox;          /* bounding box */
  50.   slist_t  *first, *last;  /* first and last lines on screen */
  51.   slist_t  *LHead, *LTail; /* first and last lines of text */
  52.   int       acrossO;       /* character pos of left edge */
  53. } TextListState_t;
  54.  
  55. typedef enum {
  56.   Repaint, UpLine, DownLine, LeftChar, RightChar,
  57.   PageUp, PageDown, Home, End
  58. } ScrollMsg_e;
  59.  
  60.  
  61. /*  This construct will be used frequently
  62.     when drawing text lines */
  63. #define PLACESL(r, o, p) \
  64. if (strlen (p->str) > o->acrossO)  /* if long enough to show */ \
  65.   x_outtext (r, 0, p->str + o->acrossO) /* show what's visible */
  66.  
  67. int              ReadLines        (FILE *fp, int tabsize);
  68. TextListState_t *InitTextScroller (bbox_t *bbp,
  69.                                    slist_t *ListHead,
  70.                                    slist_t *ListTail);
  71. void             ScrollTextObj    (TextListState_t *tsp,
  72.                                    ScrollMsg_e Msg);
  73. void             ScrollLines      (void);
  74. void             TabExpand        (char *out, char *in,
  75.                                    int tabsize);
  76.  
  77. slist_t *ListHead, *ListTail; /* text-lines to be viewed */
  78.  
  79. void main (int argc, char *argv[])
  80. {
  81.   FILE   *fp;
  82.   int     tabsize = 5; /* size of tabs in spaces */
  83.  
  84.   if (argc < 2) {
  85.     fputs ("args: text-file-path [tabsize]\n", stderr);
  86.     exit (1);
  87.   }
  88.  
  89.   if (NULL == (fp = fopen (argv[1], "r"))) {
  90.     fprintf (stderr, "cannot open '%s'\n", argv[1]);
  91.     exit (2);
  92.   }
  93.  
  94.   if (argc == 3)
  95.     tabsize = atoi (argv[2]);
  96.  
  97.   if ( ! ReadLines (fp, tabsize)) {
  98.     fprintf (stderr,
  99.              "error occurred reading '%s'\n", argv[1]);
  100.     exit (3);
  101.   }
  102.  
  103.   fclose (fp);
  104.  
  105.   /* set up display */
  106.   InitDisplay (3, 25);
  107.   CursorOff ();
  108.  
  109.   ScrollLines ();
  110.  
  111.   SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_WHITE));
  112.   ClearScreen ();
  113.   SetTextCursor (0, 0);
  114. }
  115.  
  116. /* ScrollLines: Display what text fits in box,
  117. ** respond to keystrokes to scroll text around.
  118. */
  119. void ScrollLines (void)
  120. {
  121.   bbox_t           bbox;
  122.   TextListState_t *tsp; /* scroller object ptr */
  123.   int              c;
  124.  
  125.   BBSET( bbox, 5, 10, 15, 60); /* set box for scroller */
  126.   if (NULL == (tsp =
  127.             InitTextScroller (&bbox, ListHead, ListTail)))
  128.     return;
  129.  
  130.   SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_GREEN));
  131.   /* assume that current box is whole screen
  132.      when function is invoked */
  133.   x_outtext (0, 0,
  134.          "Press Q to quit, arrow keys to scroll around");
  135.  
  136.   bbox.o[DOWN] -= 1;   bbox.o[ACROSS] -= 1; /* expand box */
  137.   bbox.n[DOWN] += 2;   bbox.n[ACROSS] += 2;
  138.   /* make a visible pane */
  139.   SetCurAttrib (MK_ATTR( CGA_MAGENTA, CGA_MAGENTA));
  140.   ClearBox (&bbox);
  141.  
  142.   SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_CYAN));
  143.   ScrollTextObj (tsp, Repaint);
  144.  
  145.   for (;;) {
  146.     c = getch ();
  147.     if (c == 'Q' || c == 'q') /* check for quit key */
  148.       break;
  149.     if (c != 0)  /* if not extended key, wait for next one */
  150.       continue;
  151.  
  152.     switch (getch ()) { /* process extended key */
  153.      case U_ARROW:      ScrollTextObj (tsp, UpLine);    break;
  154.      case D_ARROW:      ScrollTextObj (tsp, DownLine);  break;
  155.      case R_ARROW:      ScrollTextObj (tsp, RightChar); break;
  156.      case L_ARROW:      ScrollTextObj (tsp, LeftChar);  break;
  157.      case PGUP:         ScrollTextObj (tsp, PageUp);    break;
  158.      case PGDN:         ScrollTextObj (tsp, PageDown);  break;
  159.      case HOME:         ScrollTextObj (tsp, Home);      break;
  160.      case END:          ScrollTextObj (tsp, End);       break;
  161.      default:
  162.       break;
  163.     }
  164.   }
  165. }
  166.  
  167.  
  168. /* InitTextScroller
  169. ** Allocates and initializes a text-scroll state object.
  170. */
  171. TextListState_t *InitTextScroller (bbox_t *bbp,
  172.                     slist_t *ListHead, slist_t *ListTail)
  173. {
  174.   TextListState_t *new;
  175.  
  176.   if (NULL != (new = TMALLOC( TextListState_t, 1))) {
  177.     memcpy (&new->bbox, bbp, sizeof (bbox_t));
  178.     /* set first on screen to head */
  179.     new->LHead = new->first = ListHead;
  180.     new->LTail = ListTail;
  181.     new->acrossO = 0;          /* at leftmost char pos */
  182.   }
  183.   return (new);
  184. }
  185.  
  186.  
  187. /* ScrollTextObj
  188. ** Simple message handler for text-scroll object.
  189. */
  190. void ScrollTextObj (TextListState_t *self, ScrollMsg_e Msg)
  191. {
  192.   slist_t  *p;
  193.   int       i, j;
  194.  
  195.   SetCurBox (&self->bbox); /* make window current */
  196.  
  197.   switch (Msg) {
  198.    case Repaint:
  199.     ClearBox (&self->bbox); /* clear it out */
  200.  
  201.     /* show first of lines */
  202.     for (i = 0, p = self->first; i < self->bbox.n[DOWN] && p;
  203.       ++i, p = p->next) {
  204.       PLACESL( i, self, p); /* place on screen */
  205.       self->last = p;       /* track last line */
  206.     }
  207.     break;
  208.  
  209.    case UpLine:
  210.     if (self->first->prev == NULL)
  211.       break;
  212.     ScrollBox (&self->bbox, 1, 0);   /* scroll down one */
  213.     self->first = self->first->prev; /* previous lines */
  214.     self->last = self->last->prev;
  215.  
  216.     PLACESL( 0, self, self->first); /* put top line on screen */
  217.     break;
  218.  
  219.    case DownLine:
  220.     if (self->last->next == NULL)
  221.       break;
  222.     ScrollBox (&self->bbox, -1, 0); /* scroll up one */
  223.     self->last = self->last->next;  /* next lines */
  224.     self->first = self->first->next;
  225.  
  226.     /* put bottom line on screen */
  227.     PLACESL( self->bbox.n[DOWN] - 1, self, self->last);
  228.     break;
  229.  
  230.    case RightChar:
  231.     ++self->acrossO;                /* advance right */
  232.     ScrollBox (&self->bbox, 0, -1); /* scroll left */
  233.  
  234.     /* for each line on screen, place newly visible
  235.        character if line is long enough to have one */
  236.     for (i = 0, p = self->first; p && i < self->bbox.n[DOWN];
  237.              ++i, p = p->next)
  238.       if (strlen (p->str) >=
  239.              self->acrossO + self->bbox.n[ACROSS])
  240.         x_outch (i, self->bbox.n[ACROSS]-1,
  241.         p->str[ self->acrossO + self->bbox.n[ACROSS] - 1]);
  242.     break;
  243.  
  244.    case LeftChar:
  245.     if (self->acrossO == 0)
  246.       break;
  247.     --self->acrossO;               /* left one character */
  248.     ScrollBox (&self->bbox, 0, 1); /* scroll screen right */
  249.  
  250.     /* for each line on screen, place newly visible
  251.        character if line is long enough to have one */
  252.     for (i = 0, p = self->first; p && i < self->bbox.n[DOWN];
  253.              ++i, p = p->next)
  254.       if (strlen (p->str) > self->acrossO)
  255.         x_outch (i, 0, p->str[self->acrossO]);
  256.     break;
  257.  
  258.    case PageUp:
  259.     if (self->first->prev == NULL)
  260.       break;
  261.  
  262.     /* work upwards by one screenful or until top,
  263.        count the number of lines involved */
  264.     for (i = 0; self->first->prev != NULL &&
  265.             i < self->bbox.n[DOWN]; ++i) {
  266.       self->first = self->first->prev;
  267.       self->last  = self->last->prev;
  268.     }
  269.     /* scroll down by # of new lines */
  270.     ScrollBox (&self->bbox, i, 0);
  271.  
  272.     /* put top lines on screen */
  273.     for (j = 0, p = self->first; j < i; ++j, p = p->next)
  274.       PLACESL( j, self, p);
  275.     break;
  276.  
  277.    case PageDown:
  278.     if (self->last->next == NULL)
  279.       break;
  280.     /* work downwards by one screenful or until bottom,
  281.        count the number of lines involved */
  282.     for (i = 0; self->last->next != NULL &&
  283.          i < self->bbox.n[DOWN]; ++i) {
  284.       self->first = self->first->next;
  285.       self->last = self->last->next;
  286.     }
  287.     /* scroll up by # of new lines */
  288.     ScrollBox (&self->bbox, -i, 0);
  289.  
  290.     /* put bottom lines on screen if long enough to show */
  291.     /* j in 1..i equivalent to j in 0..i-1 used with
  292.        bbp->n[DOWN] - 1 - j */
  293.     for (j = 1, p = self->last; j <= i; p = p->prev, ++j)
  294.       PLACESL( self->bbox.n[DOWN] - j, self, p);
  295.     break;
  296.  
  297.    case Home:
  298.     if (self->first->prev == NULL && self->acrossO == 0)
  299.       break;
  300.     self->acrossO = 0;
  301.     self->first = self->LHead;
  302.  
  303.     ScrollTextObj (self, Repaint); /* simply repaint */
  304.     break;
  305.  
  306.    case End:
  307.     if (self->last->next == NULL && self->acrossO == 0)
  308.       break;
  309.     self->acrossO = 0;
  310.     self->last    = self->LTail;
  311.     /* from tail, count up one screenful or
  312.        until head reached */
  313.     for (i = 0, p = self->last; p->prev != NULL &&
  314.          i < self->bbox.n[DOWN]; ++i) {
  315.       self->first = p;
  316.       p = p->prev;
  317.     }
  318.  
  319.     ScrollTextObj (self, Repaint); /* simply repaint */
  320.     break;
  321.  
  322.    default:
  323.     break;
  324.   }
  325. }
  326.  
  327.  
  328. /* ReadLines: Reads text lines into a doubly-linked list.
  329. ** Returns false on (memory) error.
  330. */
  331. int ReadLines (FILE *fp, int tabsize)
  332. {
  333.   slist_t *new;
  334.   char buf[MAXLINE];
  335.   char expand[MAXLINE];
  336.   char *p;
  337.  
  338.   while (fgets (buf, MAXLINE, fp)) {
  339.     if (NULL != (p = strchr (buf, '\n')))
  340.       *p = '\0';
  341.     TabExpand (expand, buf, tabsize);
  342.  
  343.     /* for some reason, MetaWare's strdup() doesn't behave here
  344.      * on zero-length strings, so just explicitly calloc()
  345.      * and strcpy () */
  346.  
  347.     if (   NULL == (new = TCALLOC( slist_t, 1)) ||
  348.       NULL == (new->str = TMALLOC (char, 1 + strlen (expand))) )
  349.       return (FALSE);
  350.  
  351.     strcpy (new->str, expand);
  352.  
  353.     if (ListHead == NULL)
  354.       ListHead = ListTail = new;
  355.     else {
  356.       ListTail->next = new;
  357.       new->prev = ListTail;
  358.       ListTail = new;
  359.     }
  360.   }
  361.   return (TRUE);
  362. }
  363.  
  364. /* TabExpand - expand tabs to spaces for display */
  365. void TabExpand (char *to, char *from, int ntabsp)
  366. {
  367.   char *t;
  368.   char *f;
  369.   int   nsp; /* # of spaces to add upon '\t' */
  370.  
  371.   for (t = to, f = from; *f; ++f)
  372.     if (*f == '\t') {
  373.       /* nsp = # of sp. 'til next tab-stop */
  374.       nsp = ntabsp - ((t-to) % ntabsp);
  375.       memset (t, ' ', nsp);
  376.       t += nsp;
  377.     }
  378.     else
  379.       *t++ = *f;
  380.  
  381.  
  382.   *t = '\0';
  383. }
  384.  
  385. /* END OF SCRLTEXT.C */