1 
2 /*
3  * helpcom.h
4  *
5  *
6  * Common #defines, structures and code for HC.C and HELP.C
7  *
8  */
9 
10 #ifndef HELPCOM_H
11 #define HELPCOM_H
12 
13 
14 /*
15  * help file signature
16  * If you get a syntax error, remove the LU from the end of the number.
17  */
18 
19 #define HELP_SIG           (0xAFBC1823LU)
20 
21 
22 /*
23  * commands imbedded in the help text
24  */
25 
26 #define CMD_LITERAL       1   /* next char taken literally */
27 #define CMD_PARA          2   /* paragraph start code */
28 #define CMD_LINK          3   /* hot-link start/end code */
29 #define CMD_FF            4   /* force a form-feed */
30 #define CMD_XONLINE       5   /* exclude from online help on/off */
31 #define CMD_XDOC          6   /* exclude from printed document on/off */
32 #define CMD_CENTER        7   /* center this line */
33 #define CMD_SPACE         8   /* next byte is count of spaces */
34 
35 #define MAX_CMD           8
36 
37 
38 /*
39  * on-line help dimensions
40  */
41 
42 #define SCREEN_WIDTH      (78)
43 #define SCREEN_DEPTH      (22)
44 #define SCREEN_INDENT     (1)
45 
46 
47 /*
48  * printed document dimensions
49  */
50 
51 #define PAGE_WIDTH         (72)  /* width of printed text */
52 #define PAGE_INDENT        (2)   /* indent all text by this much */
53 #define TITLE_INDENT       (1)   /* indent titles by this much */
54 
55 #define PAGE_RDEPTH        (59)  /* the total depth (inc. heading) */
56 #define PAGE_HEADING_DEPTH (3)   /* depth of the heading */
57 #define PAGE_DEPTH         (PAGE_RDEPTH-PAGE_HEADING_DEPTH) /* depth of text */
58 
59 
60 /*
61  * Document page-break macros.  Goto to next page if this close (or closer)
62  * to end of page when starting a CONTENT, TOPIC, or at a BLANK line.
63  */
64 
65 #define CONTENT_BREAK (7)  /* start of a "DocContent" entry */
66 #define TOPIC_BREAK   (4)  /* start of each topic under a DocContent entry */
67 #define BLANK_BREAK   (2)  /* a blank line */
68 
69 
70 /*
71  * tokens returned by find_token_length
72  */
73 
74 #define TOK_DONE    (0)   /* len == 0             */
75 #define TOK_SPACE   (1)   /* a run of spaces      */
76 #define TOK_LINK    (2)   /* an entire link       */
77 #define TOK_PARA    (3)   /* a CMD_PARA           */
78 #define TOK_NL      (4)   /* a new-line ('\n')    */
79 #define TOK_FF      (5)   /* a form-feed (CMD_FF) */
80 #define TOK_WORD    (6)   /* a word               */
81 #define TOK_XONLINE (7)   /* a CMD_XONLINE        */
82 #define TOK_XDOC    (8)   /* a CMD_XDOC           */
83 #define TOK_CENTER  (9)   /* a CMD_CENTER         */
84 
85 
86 /*
87  * modes for find_token_length() and find_line_width()
88  */
89 
90 #define ONLINE 1
91 #define DOC    2
92 
93 
94 /*
95  * struct PD_INFO used by process_document()
96  */
97 
98 typedef struct
99    {
100 
101    /* used by process_document -- look but don't touch! */
102 
103    int       pnum,
104              lnum;
105 
106    /* PD_GET_TOPIC is allowed to change these */
107 
108    char far *curr;
109    unsigned  len;
110 
111    /* PD_GET_CONTENT is allowed to change these */
112 
113    char far *id;
114    char far *title;
115    int       new_page;
116 
117    /* general parameters */
118 
119    char far *s;
120    int       i;
121 
122 
123    } PD_INFO;
124 
125 
126 /*
127  * Commands passed to (*get_info)() and (*output)() by process_document()
128  */
129 
130 enum  PD_COMMANDS
131    {
132 
133 /* commands sent to pd_output */
134 
135    PD_HEADING,         /* call at the top of each page */
136    PD_FOOTING,          /* called at the end of each page */
137    PD_PRINT,            /* called to send text to the printer */
138    PD_PRINTN,           /* called to print a char n times */
139    PD_PRINT_SEC,        /* called to print the section title line */
140    PD_START_SECTION,    /* called at the start of each section */
141    PD_START_TOPIC,      /* called at the start of each topic */
142    PD_SET_SECTION_PAGE, /* set the current sections page number */
143    PD_SET_TOPIC_PAGE,   /* set the current topics page number */
144    PD_PERIODIC,         /* called just before curr is incremented to next token */
145 
146 /* commands sent to pd_get_info */
147 
148    PD_GET_CONTENT,
149    PD_GET_TOPIC,
150    PD_RELEASE_TOPIC,
151    PD_GET_LINK_PAGE
152 
153    } ;
154 
155 
156 typedef int (*PD_FUNC)(int cmd, PD_INFO *pd, VOIDPTR info);
157 
158 
159 int _find_token_length(char far *curr, unsigned len, int *size, int *width);
160 int find_token_length(int mode, char far *curr, unsigned len, int *size, int *width);
161 int find_line_width(int mode, char far *curr, unsigned len);
162 int process_document(PD_FUNC get_info, PD_FUNC output, VOIDPTR info);
163 
164 
165 /*
166  * Code common to both HC.C and HELP.C (in Fractint).
167  * #include INCLUDE_COMMON once for each program
168  */
169 
170 
171 #endif
172 #ifdef INCLUDE_COMMON
173 
174 
175 #ifndef XFRACT
176 #define getint(ptr) (*(int far *)(ptr))
177 #define setint(ptr,n) (*(int far *)(ptr)) = n
178 #else
179 /* Get an int from an unaligned pointer
180  * This routine is needed because this program uses unaligned 2 byte
181  * pointers all over the place.
182  */
183 int
getint(ptr)184 getint(ptr)
185 char *ptr;
186 {
187     int s;
188     bcopy(ptr,&s,sizeof(int));
189     return s;
190 }
191 
192 /* Set an int to an unaligned pointer */
setint(ptr,n)193 void setint(ptr, n)
194 int n;
195 char *ptr;
196 {
197     bcopy(&n,ptr,sizeof(int));
198 }
199 #endif
200 
201 
is_hyphen(char far * ptr)202 static int is_hyphen(char far *ptr)   /* true if ptr points to a real hyphen */
203    {                           /* checkes for "--" and " -" */
204    if ( *ptr != '-' )
205       return (0);    /* that was easy! */
206 
207    --ptr;
208 
209    return ( *ptr!=' ' && *ptr!='-' );
210    }
211 
212 
_find_token_length(register char far * curr,unsigned len,int * size,int * width)213 int _find_token_length(register char far *curr, unsigned len, int *size, int *width)
214    {
215    register int _size  = 0;
216    register int _width = 0;
217    int tok;
218 
219    if (len == 0)
220       tok = TOK_DONE;
221 
222    else
223       {
224       switch ( *curr )
225          {
226          case ' ':    /* it's a run of spaces */
227             tok = TOK_SPACE;
228             while ( *curr == ' ' && _size < (int)len )
229                {
230                ++curr;
231                ++_size;
232                ++_width;
233                }
234             break;
235 
236          case CMD_SPACE:
237             tok = TOK_SPACE;
238             ++curr;
239             ++_size;
240             _width = *curr;
241             ++curr;
242             ++_size;
243             break;
244 
245          case CMD_LINK:
246             tok = TOK_LINK;
247             _size += 1+3*sizeof(int); /* skip CMD_LINK + topic_num + topic_off + page_num */
248             curr += 1+3*sizeof(int);
249 
250             while ( *curr != CMD_LINK )
251                {
252                if ( *curr == CMD_LITERAL )
253                   {
254                   ++curr;
255                   ++_size;
256                   }
257                ++curr;
258                ++_size;
259                ++_width;
260                assert(_size < len);
261                }
262 
263             ++_size;   /* skip ending CMD_LINK */
264             break;
265 
266          case CMD_PARA:
267             tok = TOK_PARA;
268             _size += 3;     /* skip CMD_PARA + indent + margin */
269             break;
270 
271          case CMD_XONLINE:
272             tok = TOK_XONLINE;
273             ++_size;
274             break;
275 
276          case CMD_XDOC:
277             tok = TOK_XDOC;
278             ++_size;
279             break;
280 
281          case CMD_CENTER:
282             tok = TOK_CENTER;
283             ++_size;
284             break;
285 
286          case '\n':
287             tok = TOK_NL;
288             ++_size;
289             break;
290 
291          case CMD_FF:
292             tok = TOK_FF;
293             ++_size;
294             break;
295 
296          default:   /* it must be a word */
297             tok = TOK_WORD;
298             for(;;)
299                {
300                if ( _size >= (int)len )
301                   break;
302 
303                else if ( *curr == CMD_LITERAL )
304                   {
305                   curr += 2;
306                   _size += 2;
307                   _width += 1;
308                   }
309 
310                else if ( *curr == '\0' )
311                   {
312                   assert(0);
313                   }
314 
315                else if ((unsigned)*curr <= MAX_CMD || *curr == ' ' ||
316                         *curr == '\n')
317                   break;
318 
319                else if ( *curr == '-' )
320                   {
321                   ++curr;
322                   ++_size;
323                   ++_width;
324                   if ( is_hyphen(curr-1) )
325                      break;
326                   }
327 
328                else
329                   {
330                   ++curr;
331                   ++_size;
332                   ++_width;
333                   }
334                }
335             break;
336          } /* switch */
337       }
338 
339    if (size  != NULL)   *size  = _size;
340    if (width != NULL)   *width = _width;
341 
342    return (tok);
343    }
344 
345 
find_token_length(int mode,char far * curr,unsigned len,int * size,int * width)346 int find_token_length(int mode, char far *curr, unsigned len, int *size, int *width)
347    {
348    int tok;
349    int t;
350    int _size;
351 
352    tok = _find_token_length(curr, len, &t, width);
353 
354    if ( (tok == TOK_XONLINE && mode == ONLINE) ||
355         (tok == TOK_XDOC    && mode == DOC)      )
356       {
357       _size = 0;
358 
359       for(;;)
360          {
361          curr  += t;
362          len   -= t;
363          _size += t;
364 
365          tok = _find_token_length(curr, len, &t, NULL);
366 
367          if ( (tok == TOK_XONLINE && mode == ONLINE) ||
368               (tok == TOK_XDOC    && mode == DOC)    ||
369               (tok == TOK_DONE)                        )
370             break;
371          }
372 
373       _size += t;
374       }
375    else
376       _size = t;
377 
378    if (size != NULL )
379       *size = _size;
380 
381    return (tok);
382    }
383 
384 
find_line_width(int mode,char far * curr,unsigned len)385 int find_line_width(int mode, char far *curr, unsigned len)
386    {
387    int size   = 0,
388        width  = 0,
389        lwidth = 0,
390        done   = 0,
391        tok;
392 
393    do
394       {
395       tok = find_token_length(mode, curr, len, &size, &width);
396 
397       switch(tok)
398          {
399          case TOK_DONE:
400          case TOK_PARA:
401          case TOK_NL:
402          case TOK_FF:
403             done = 1;
404             break;
405 
406          case TOK_XONLINE:
407          case TOK_XDOC:
408          case TOK_CENTER:
409             curr += size;
410             len -= size;
411             break;
412 
413          default:   /* TOK_SPACE, TOK_LINK or TOK_WORD */
414             lwidth += width;
415             curr += size;
416             len -= size;
417             break;
418          }
419       }
420    while ( !done );
421 
422    return (lwidth);
423    }
424 
425 
426 #define DO_PRINTN(ch,n)  ( pd.s = &(ch), pd.i = (n), output(PD_PRINTN, &pd, info) )
427 #define DO_PRINT(str,n)  ( pd.s = (str), pd.i = (n), output(PD_PRINT, &pd, info) )
428 
429 
process_document(PD_FUNC get_info,PD_FUNC output,VOIDPTR info)430 int process_document(PD_FUNC get_info, PD_FUNC output, VOIDPTR info)
431    {
432    int       skip_blanks;
433    int       tok;
434    int       size,
435              width;
436    int       col;
437    char      page_text[10];
438    PD_INFO   pd;
439    char      nl = '\n',
440              sp = ' ';
441    int       first_section,
442              first_topic;
443 
444    pd.pnum = 1;
445    pd.lnum = 0;
446 
447    col = 0;
448 
449    output(PD_HEADING, &pd, info);
450 
451    first_section = 1;
452 
453    while ( get_info(PD_GET_CONTENT, &pd, info) )
454       {
455       if ( !output(PD_START_SECTION, &pd, info) )
456          return (0);
457 
458       if ( pd.new_page && pd.lnum != 0 )
459          {
460          if ( !output(PD_FOOTING, &pd, info) )
461             return (0);
462          ++pd.pnum;
463          pd.lnum = 0;
464          if ( !output(PD_HEADING, &pd, info) )
465             return (0);
466          }
467 
468       else
469          {
470          if ( pd.lnum+2 > PAGE_DEPTH-CONTENT_BREAK )
471             {
472             if ( !output(PD_FOOTING, &pd, info) )
473                return (0);
474             ++pd.pnum;
475             pd.lnum = 0;
476             if ( !output(PD_HEADING, &pd, info) )
477                return (0);
478             }
479          else if (pd.lnum > 0)
480             {
481             if ( !DO_PRINTN(nl, 2) )
482                return (0);
483             pd.lnum += 2;
484             }
485          }
486 
487       if ( !output(PD_SET_SECTION_PAGE, &pd, info) )
488          return (0);
489 
490       if ( !first_section )
491          {
492          if ( !output(PD_PRINT_SEC, &pd, info) )
493             return (0);
494          ++pd.lnum;
495          }
496 
497       col = 0;
498 
499       first_topic = 1;
500 
501       while ( get_info(PD_GET_TOPIC, &pd, info) )
502          {
503          if ( !output(PD_START_TOPIC, &pd, info) )
504             return (0);
505 
506          skip_blanks = 0;
507          col = 0;
508 
509          if ( !first_section )   /* do not skip blanks for DocContents */
510             {
511             while (pd.len > 0)
512                {
513                tok = find_token_length(DOC, pd.curr, pd.len, &size, NULL);
514                if (tok != TOK_XDOC && tok != TOK_XONLINE &&
515                    tok != TOK_NL   && tok != TOK_DONE )
516                   break;
517                pd.curr += size;
518                pd.len  -= size;
519                }
520             if ( first_topic && pd.len != 0 )
521                {
522                if ( !DO_PRINTN(nl, 1) )
523                   return (0);
524                ++pd.lnum;
525                }
526             }
527 
528          if ( pd.lnum > PAGE_DEPTH-TOPIC_BREAK )
529             {
530             if ( !output(PD_FOOTING, &pd, info) )
531                return (0);
532             ++pd.pnum;
533             pd.lnum = 0;
534             if ( !output(PD_HEADING, &pd, info) )
535                return (0);
536             }
537          else if ( !first_topic )
538             {
539             if ( !DO_PRINTN(nl, 1) )
540                return (0);
541             pd.lnum++;
542             }
543 
544          if ( !output(PD_SET_TOPIC_PAGE, &pd, info) )
545             return (0);
546 
547          do
548             {
549             if ( !output(PD_PERIODIC, &pd, info) )
550                return (0);
551 
552             tok = find_token_length(DOC, pd.curr, pd.len, &size, &width);
553 
554             switch ( tok )
555                {
556                case TOK_PARA:
557                   {
558                   int       indent,
559                             margin;
560                   unsigned  holdlen = 0;
561                   char far *holdcurr = 0;
562                   int       in_link = 0;
563 
564                   ++pd.curr;
565 
566                   indent = *pd.curr++;
567                   margin = *pd.curr++;
568 
569                   pd.len -= 3;
570 
571                   if ( !DO_PRINTN(sp, indent) )
572                      return (0);
573 
574                   col = indent;
575 
576                   for(;;)
577                      {
578                      if ( !output(PD_PERIODIC, &pd, info) )
579                         return (0);
580 
581                      tok = find_token_length(DOC, pd.curr, pd.len, &size, &width);
582 
583                      if ( tok == TOK_NL || tok == TOK_FF )
584                         break;
585 
586                      if ( tok == TOK_DONE )
587                         {
588                         if (in_link == 0)
589                            {
590                            col = 0;
591                            ++pd.lnum;
592                            if ( !DO_PRINTN(nl, 1) )
593                               return (0);
594                            break;
595                            }
596 
597                         else if (in_link == 1)
598                            {
599                            tok = TOK_SPACE;
600                            width = 1;
601                            size = 0;
602                            ++in_link;
603                            }
604 
605                         else if (in_link == 2)
606                            {
607                            tok = TOK_WORD;
608                            width = strlen(page_text);
609                            col += 8 - width;
610                            size = 0;
611                            pd.curr = page_text;
612                            ++in_link;
613                            }
614 
615                         else if (in_link == 3)
616                            {
617                            pd.curr = holdcurr;
618                            pd.len = holdlen;
619                            in_link = 0;
620                            continue;
621                            }
622                         }
623 
624                      if ( tok == TOK_PARA )
625                         {
626                         col = 0;   /* fake a nl */
627                         ++pd.lnum;
628                         if ( !DO_PRINTN(nl, 1) )
629                            return (0);
630                         break;
631                         }
632 
633                      if (tok == TOK_XONLINE || tok == TOK_XDOC )
634                         {
635                         pd.curr += size;
636                         pd.len -= size;
637                         continue;
638                         }
639 
640                      if ( tok == TOK_LINK )
641                         {
642                         pd.s = pd.curr+1;
643                         if ( get_info(PD_GET_LINK_PAGE, &pd, info) )
644                            {
645                            in_link = 1;
646                            sprintf(page_text, "(p. %d)", pd.i);
647                            }
648                         else
649                            in_link = 3;
650                         holdcurr = pd.curr + size;
651                         holdlen = pd.len - size;
652                         pd.len = size - 2 - 3*sizeof(int);
653                         pd.curr += 1 + 3*sizeof(int);
654                         continue;
655                         }
656 
657                      /* now tok is TOK_SPACE or TOK_WORD */
658 
659                      if (col+width > PAGE_WIDTH)
660                         {          /* go to next line... */
661                         if ( !DO_PRINTN(nl, 1) )
662                            return (0);
663                         if ( ++pd.lnum >= PAGE_DEPTH )
664                            {
665                            if ( !output(PD_FOOTING, &pd, info) )
666                               return (0);
667                            ++pd.pnum;
668                            pd.lnum = 0;
669                            if ( !output(PD_HEADING, &pd, info) )
670                               return (0);
671                            }
672 
673                         if ( tok == TOK_SPACE )
674                            width = 0;   /* skip spaces at start of a line */
675 
676                         if ( !DO_PRINTN(sp, margin) )
677                            return (0);
678                         col = margin;
679                         }
680 
681                      if (width > 0)
682                         {
683                         if (tok == TOK_SPACE)
684                            {
685                            if ( !DO_PRINTN(sp, width) )
686                               return (0);
687                            }
688                         else
689                            {
690                            if ( !DO_PRINT(pd.curr, (size==0) ? width : size) )
691                               return (0);
692                            }
693                         }
694 
695                      col += width;
696                      pd.curr += size;
697                      pd.len -= size;
698                      }
699 
700                   skip_blanks = 0;
701                   width = size = 0;
702                   break;
703                   }
704 
705                case TOK_NL:
706                   if (skip_blanks && col == 0)
707                      break;
708 
709                   ++pd.lnum;
710 
711                   if ( pd.lnum >= PAGE_DEPTH || (col == 0 && pd.lnum >= PAGE_DEPTH-BLANK_BREAK) )
712                      {
713                      if ( col != 0 )    /* if last wasn't a blank line... */
714                         {
715                         if ( !DO_PRINTN(nl, 1) )
716                            return (0);
717                         }
718                      if ( !output(PD_FOOTING, &pd, info) )
719                         return (0);
720                      ++pd.pnum;
721                      pd.lnum = 0;
722                      skip_blanks = 1;
723                      if ( !output(PD_HEADING, &pd, info) )
724                         return (0);
725                      }
726                   else
727                      {
728                      if ( !DO_PRINTN(nl, 1) )
729                         return (0);
730                      }
731 
732                   col = 0;
733                   break;
734 
735                case TOK_FF:
736                   if (skip_blanks)
737                      break;
738                   if ( !output(PD_FOOTING, &pd, info) )
739                      return (0);
740                   col = 0;
741                   pd.lnum = 0;
742                   ++pd.pnum;
743                   if ( !output(PD_HEADING, &pd, info) )
744                      return (0);
745                   break;
746 
747                case TOK_CENTER:
748                   width = (PAGE_WIDTH - find_line_width(DOC,pd.curr,pd.len)) / 2;
749                   if ( !DO_PRINTN(sp, width) )
750                      return (0);
751                   break;
752 
753                case TOK_LINK:
754                   skip_blanks = 0;
755                   if ( !DO_PRINT(pd.curr+1+3*sizeof(int),
756                           size-3*sizeof(int)-2) )
757                      return (0);
758                   pd.s = pd.curr+1;
759                   if ( get_info(PD_GET_LINK_PAGE, &pd, info) )
760                      {
761                      width += 9;
762                      sprintf(page_text, " (p. %d)", pd.i);
763                      if ( !DO_PRINT(page_text, strlen(page_text)) )
764                         return (0);
765                      }
766                   break;
767 
768                case TOK_WORD:
769                   skip_blanks = 0;
770                   if ( !DO_PRINT(pd.curr, size) )
771                      return (0);
772                   break;
773 
774                case TOK_SPACE:
775                   skip_blanks = 0;
776                   if ( !DO_PRINTN(sp, width) )
777                      return (0);
778                   break;
779 
780                case TOK_DONE:
781                case TOK_XONLINE:   /* skip */
782                case TOK_XDOC:      /* ignore */
783                   break;
784 
785                } /* switch */
786 
787             pd.curr += size;
788             pd.len  -= size;
789             col     += width;
790             }
791          while (pd.len > 0);
792 
793          get_info(PD_RELEASE_TOPIC, &pd, info);
794 
795          first_topic = 0;
796          } /* while */
797 
798       first_section = 0;
799       } /* while */
800 
801    if ( !output(PD_FOOTING, &pd, info) )
802       return (0);
803 
804    return (1);
805    }
806 
807 #undef DO_PRINT
808 #undef DO_PRINTN
809 
810 
811 #undef INCLUDE_COMMON
812 #endif   /* #ifdef INCLUDE_COMMON */
813