home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************
- * File: SCRLTEXT.C
- * Purpose: Simple demo of 2-D scrolling
- * Date: February 1991
- * Author: George Spofford
- * Compilers: MSC 6.0, Turbo C++ 1.0, MetaWare HighC-386 1.7
- * Switches:
- * MSC 6.0: -- large model
- * cl -AL -c scrltest.c
- * link scrltest+vidprim;
- * High C: -- needs both hce.lib and na.lib
- * hc386 -c -DDOS_386 scrltest.c
- * 386link scrltest vidprim -lib hce.lib na.lib
- *
- * Object code may be used freely. Source code may be used freely
- * if author and publication are acknowledged.
- ****************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <conio.h>
- #include "vidprim.h"
-
- #define U_ARROW 72
- #define D_ARROW 80
- #define L_ARROW 75
- #define R_ARROW 77
- #define PGUP 73
- #define PGDN 81
- #define HOME 71
- #define END 79
-
- #define TRUE 1
- #define FALSE 0
-
- #define TCALLOC( t, n) (t *) calloc (n, sizeof (t))
- #define TMALLOC( t, n) (t *) malloc (n * sizeof (t))
-
- #define MAXLINE 512
-
- typedef struct slist_st {
- char *str;
- struct slist_st *next, *prev;
- } slist_t;
-
- typedef struct { /* text-scroll object's
- state template */
- bbox_t bbox; /* bounding box */
- slist_t *first, *last; /* first and last lines on screen */
- slist_t *LHead, *LTail; /* first and last lines of text */
- int acrossO; /* character pos of left edge */
- } TextListState_t;
-
- typedef enum {
- Repaint, UpLine, DownLine, LeftChar, RightChar,
- PageUp, PageDown, Home, End
- } ScrollMsg_e;
-
-
- /* This construct will be used frequently
- when drawing text lines */
- #define PLACESL(r, o, p) \
- if (strlen (p->str) > o->acrossO) /* if long enough to show */ \
- x_outtext (r, 0, p->str + o->acrossO) /* show what's visible */
-
- int ReadLines (FILE *fp, int tabsize);
- TextListState_t *InitTextScroller (bbox_t *bbp,
- slist_t *ListHead,
- slist_t *ListTail);
- void ScrollTextObj (TextListState_t *tsp,
- ScrollMsg_e Msg);
- void ScrollLines (void);
- void TabExpand (char *out, char *in,
- int tabsize);
-
- slist_t *ListHead, *ListTail; /* text-lines to be viewed */
-
- void main (int argc, char *argv[])
- {
- FILE *fp;
- int tabsize = 5; /* size of tabs in spaces */
-
- if (argc < 2) {
- fputs ("args: text-file-path [tabsize]\n", stderr);
- exit (1);
- }
-
- if (NULL == (fp = fopen (argv[1], "r"))) {
- fprintf (stderr, "cannot open '%s'\n", argv[1]);
- exit (2);
- }
-
- if (argc == 3)
- tabsize = atoi (argv[2]);
-
- if ( ! ReadLines (fp, tabsize)) {
- fprintf (stderr,
- "error occurred reading '%s'\n", argv[1]);
- exit (3);
- }
-
- fclose (fp);
-
- /* set up display */
- InitDisplay (3, 25);
- CursorOff ();
-
- ScrollLines ();
-
- SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_WHITE));
- ClearScreen ();
- SetTextCursor (0, 0);
- }
-
- /* ScrollLines: Display what text fits in box,
- ** respond to keystrokes to scroll text around.
- */
- void ScrollLines (void)
- {
- bbox_t bbox;
- TextListState_t *tsp; /* scroller object ptr */
- int c;
-
- BBSET( bbox, 5, 10, 15, 60); /* set box for scroller */
- if (NULL == (tsp =
- InitTextScroller (&bbox, ListHead, ListTail)))
- return;
-
- SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_GREEN));
- /* assume that current box is whole screen
- when function is invoked */
- x_outtext (0, 0,
- "Press Q to quit, arrow keys to scroll around");
-
- bbox.o[DOWN] -= 1; bbox.o[ACROSS] -= 1; /* expand box */
- bbox.n[DOWN] += 2; bbox.n[ACROSS] += 2;
- /* make a visible pane */
- SetCurAttrib (MK_ATTR( CGA_MAGENTA, CGA_MAGENTA));
- ClearBox (&bbox);
-
- SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_CYAN));
- ScrollTextObj (tsp, Repaint);
-
- for (;;) {
- c = getch ();
- if (c == 'Q' || c == 'q') /* check for quit key */
- break;
- if (c != 0) /* if not extended key, wait for next one */
- continue;
-
- switch (getch ()) { /* process extended key */
- case U_ARROW: ScrollTextObj (tsp, UpLine); break;
- case D_ARROW: ScrollTextObj (tsp, DownLine); break;
- case R_ARROW: ScrollTextObj (tsp, RightChar); break;
- case L_ARROW: ScrollTextObj (tsp, LeftChar); break;
- case PGUP: ScrollTextObj (tsp, PageUp); break;
- case PGDN: ScrollTextObj (tsp, PageDown); break;
- case HOME: ScrollTextObj (tsp, Home); break;
- case END: ScrollTextObj (tsp, End); break;
- default:
- break;
- }
- }
- }
-
-
- /* InitTextScroller
- ** Allocates and initializes a text-scroll state object.
- */
- TextListState_t *InitTextScroller (bbox_t *bbp,
- slist_t *ListHead, slist_t *ListTail)
- {
- TextListState_t *new;
-
- if (NULL != (new = TMALLOC( TextListState_t, 1))) {
- memcpy (&new->bbox, bbp, sizeof (bbox_t));
- /* set first on screen to head */
- new->LHead = new->first = ListHead;
- new->LTail = ListTail;
- new->acrossO = 0; /* at leftmost char pos */
- }
- return (new);
- }
-
-
- /* ScrollTextObj
- ** Simple message handler for text-scroll object.
- */
- void ScrollTextObj (TextListState_t *self, ScrollMsg_e Msg)
- {
- slist_t *p;
- int i, j;
-
- SetCurBox (&self->bbox); /* make window current */
-
- switch (Msg) {
- case Repaint:
- ClearBox (&self->bbox); /* clear it out */
-
- /* show first of lines */
- for (i = 0, p = self->first; i < self->bbox.n[DOWN] && p;
- ++i, p = p->next) {
- PLACESL( i, self, p); /* place on screen */
- self->last = p; /* track last line */
- }
- break;
-
- case UpLine:
- if (self->first->prev == NULL)
- break;
- ScrollBox (&self->bbox, 1, 0); /* scroll down one */
- self->first = self->first->prev; /* previous lines */
- self->last = self->last->prev;
-
- PLACESL( 0, self, self->first); /* put top line on screen */
- break;
-
- case DownLine:
- if (self->last->next == NULL)
- break;
- ScrollBox (&self->bbox, -1, 0); /* scroll up one */
- self->last = self->last->next; /* next lines */
- self->first = self->first->next;
-
- /* put bottom line on screen */
- PLACESL( self->bbox.n[DOWN] - 1, self, self->last);
- break;
-
- case RightChar:
- ++self->acrossO; /* advance right */
- ScrollBox (&self->bbox, 0, -1); /* scroll left */
-
- /* for each line on screen, place newly visible
- character if line is long enough to have one */
- for (i = 0, p = self->first; p && i < self->bbox.n[DOWN];
- ++i, p = p->next)
- if (strlen (p->str) >=
- self->acrossO + self->bbox.n[ACROSS])
- x_outch (i, self->bbox.n[ACROSS]-1,
- p->str[ self->acrossO + self->bbox.n[ACROSS] - 1]);
- break;
-
- case LeftChar:
- if (self->acrossO == 0)
- break;
- --self->acrossO; /* left one character */
- ScrollBox (&self->bbox, 0, 1); /* scroll screen right */
-
- /* for each line on screen, place newly visible
- character if line is long enough to have one */
- for (i = 0, p = self->first; p && i < self->bbox.n[DOWN];
- ++i, p = p->next)
- if (strlen (p->str) > self->acrossO)
- x_outch (i, 0, p->str[self->acrossO]);
- break;
-
- case PageUp:
- if (self->first->prev == NULL)
- break;
-
- /* work upwards by one screenful or until top,
- count the number of lines involved */
- for (i = 0; self->first->prev != NULL &&
- i < self->bbox.n[DOWN]; ++i) {
- self->first = self->first->prev;
- self->last = self->last->prev;
- }
- /* scroll down by # of new lines */
- ScrollBox (&self->bbox, i, 0);
-
- /* put top lines on screen */
- for (j = 0, p = self->first; j < i; ++j, p = p->next)
- PLACESL( j, self, p);
- break;
-
- case PageDown:
- if (self->last->next == NULL)
- break;
- /* work downwards by one screenful or until bottom,
- count the number of lines involved */
- for (i = 0; self->last->next != NULL &&
- i < self->bbox.n[DOWN]; ++i) {
- self->first = self->first->next;
- self->last = self->last->next;
- }
- /* scroll up by # of new lines */
- ScrollBox (&self->bbox, -i, 0);
-
- /* put bottom lines on screen if long enough to show */
- /* j in 1..i equivalent to j in 0..i-1 used with
- bbp->n[DOWN] - 1 - j */
- for (j = 1, p = self->last; j <= i; p = p->prev, ++j)
- PLACESL( self->bbox.n[DOWN] - j, self, p);
- break;
-
- case Home:
- if (self->first->prev == NULL && self->acrossO == 0)
- break;
- self->acrossO = 0;
- self->first = self->LHead;
-
- ScrollTextObj (self, Repaint); /* simply repaint */
- break;
-
- case End:
- if (self->last->next == NULL && self->acrossO == 0)
- break;
- self->acrossO = 0;
- self->last = self->LTail;
- /* from tail, count up one screenful or
- until head reached */
- for (i = 0, p = self->last; p->prev != NULL &&
- i < self->bbox.n[DOWN]; ++i) {
- self->first = p;
- p = p->prev;
- }
-
- ScrollTextObj (self, Repaint); /* simply repaint */
- break;
-
- default:
- break;
- }
- }
-
-
- /* ReadLines: Reads text lines into a doubly-linked list.
- ** Returns false on (memory) error.
- */
- int ReadLines (FILE *fp, int tabsize)
- {
- slist_t *new;
- char buf[MAXLINE];
- char expand[MAXLINE];
- char *p;
-
- while (fgets (buf, MAXLINE, fp)) {
- if (NULL != (p = strchr (buf, '\n')))
- *p = '\0';
- TabExpand (expand, buf, tabsize);
-
- /* for some reason, MetaWare's strdup() doesn't behave here
- * on zero-length strings, so just explicitly calloc()
- * and strcpy () */
-
- if ( NULL == (new = TCALLOC( slist_t, 1)) ||
- NULL == (new->str = TMALLOC (char, 1 + strlen (expand))) )
- return (FALSE);
-
- strcpy (new->str, expand);
-
- if (ListHead == NULL)
- ListHead = ListTail = new;
- else {
- ListTail->next = new;
- new->prev = ListTail;
- ListTail = new;
- }
- }
- return (TRUE);
- }
-
- /* TabExpand - expand tabs to spaces for display */
- void TabExpand (char *to, char *from, int ntabsp)
- {
- char *t;
- char *f;
- int nsp; /* # of spaces to add upon '\t' */
-
- for (t = to, f = from; *f; ++f)
- if (*f == '\t') {
- /* nsp = # of sp. 'til next tab-stop */
- nsp = ntabsp - ((t-to) % ntabsp);
- memset (t, ' ', nsp);
- t += nsp;
- }
- else
- *t++ = *f;
-
-
- *t = '\0';
- }
-
- /* END OF SCRLTEXT.C */