1
2 /*
3 * hc.c
4 *
5 * Stand-alone FRACTINT help compiler. Compile in the COMPACT memory model.
6 *
7 * See HC.DOC for source file syntax.
8 *
9 *
10 * Revision History:
11 *
12 * 02-26-91 EAN Initial version.
13 *
14 * 03-21-91 EAN Modified for automatic paragraph formatting.
15 * Added several new commands:
16 * Format[+/-] Enable/disable paragraph formatting
17 * Doc[+/-] Enable/disable output to document.
18 * Online[+/-] Enable/disable output to online help.
19 * Label= Defines a label. Replaces ~(...)
20 * FF Forces a form-feed. Replaces ~~
21 * FormatExclude=val Exclude lines past val from
22 * formatting. If before any topic sets
23 * global default, otherwise set local.
24 * FormatExclude= Set to global default.
25 * FormatExclude=n Disable exclusion. (global or local)
26 * FormatExclude[+/-] Enable/disable format exclusion.
27 * Center[+/-] Enable/disable centering of text.
28 * \ before nl Forces the end of a paragraph
29 * Support for commands embedded in text with new
30 * ~(...) format.
31 * Support for multiple commands on a line separated by
32 * commas.
33 * Support for implict links; explicit links must now
34 * start with an equal sign.
35 * 04-03-91 EAN Added "include" command (works like #include)
36 * 04-10-91 EAN Added support for "data" topics.
37 * Added Comment/EndComment commands for multi-line
38 * comments.
39 * Added CompressSpaces[+/-] command.
40 * Added DocContents command for document printing.
41 * Added BinInc command which includes a binary file
42 * in a data topic.
43 * Fixed tables to flow down instead of across the page.
44 * Makes no allowances for page breaks within tables.
45 * 11-03-94 TIW Increased buffer size.
46 *
47 */
48
49
50 #define HC_C
51
52 #define INCLUDE_COMMON /* tell helpcom.h to include common code */
53
54
55 #ifdef XFRACT
56 #define strupr strlwr
57 #else
58 #include <io.h>
59 #endif
60
61 #ifndef USE_VARARGS
62 #include <stdarg.h>
63 #else
64 #include <varargs.h>
65 #endif
66
67 #include <fcntl.h>
68 #include <string.h>
69 #include <ctype.h>
70
71 #ifdef __TURBOC__
72 # include <dir.h>
73 # define FNSPLIT fnsplit
74 #else
75 # define MAXFILE FILE_MAX_FNAME
76 # define MAXEXT FILE_MAX_EXT
77 # define FNSPLIT _splitpath
78 #endif
79
80
81 #include <assert.h>
82 /* see Fractint.c for a description of the "include" hierarchy */
83 #include "port.h"
84 #include "helpcom.h"
85
86 #ifdef XFRACT
87 #ifndef HAVESTRI
88 extern int stricmp(char *, char *);
89 extern int strnicmp(char *, char *, int);
90 #endif
91 extern int filelength(int);
92 extern int _splitpath(char *,char *,char *,char *,char *);
93 #endif
94
95 /*
96 * When defined, SHOW_ERROR_LINE will cause the line number in HC.C where
97 * errors/warnings/messages are generated to be displayed at the start of
98 * the line.
99 *
100 * Used when debugging HC. Also useful for finding the line (in HC.C) that
101 * generated a error or warning.
102 */
103
104 #ifndef XFRACT
105 #define SHOW_ERROR_LINE
106 #endif
107
108
109 #define DEFAULT_SRC_FNAME "help.src"
110 #define DEFAULT_HLP_FNAME "fractint.hlp"
111 #define DEFAULT_EXE_FNAME "fractint.exe"
112 #define DEFAULT_DOC_FNAME "fractint.doc"
113
114 #define TEMP_FNAME "HC.$$$"
115 #define SWAP_FNAME "HCSWAP.$$$"
116
117 #define MAX_ERRORS (25) /* stop after this many errors */
118 #define MAX_WARNINGS (25) /* stop after this many warnings */
119 /* 0 = never stop */
120
121 #define INDEX_LABEL "HELP_INDEX"
122 #define DOCCONTENTS_TITLE "DocContent"
123
124
125
126 /* #define BUFFER_SIZE (24*1024) */
127 #define BUFFER_SIZE (30*1024)
128
129
130 typedef struct
131 {
132 int type; /* 0 = name is topic title, 1 = name is label, */
133 /* 2 = "special topic"; name is NULL and */
134 /* topic_num/topic_off is valid */
135 int topic_num; /* topic number to link to */
136 unsigned topic_off; /* offset into topic to link to */
137 int doc_page; /* document page # to link to */
138 char *name; /* name of label or title of topic to link to */
139 char *srcfile; /* .SRC file link appears in */
140 int srcline; /* .SRC file line # link appears in */
141 } LINK;
142
143
144 typedef struct
145 {
146 unsigned offset; /* offset from start of topic text */
147 unsigned length; /* length of page (in chars) */
148 int margin; /* if > 0 then page starts in_para and text */
149 /* should be indented by this much */
150 } PAGE;
151
152
153 /* values for TOPIC.flags */
154
155 #define TF_IN_DOC (1) /* 1 if topic is part of the printed document */
156 #define TF_DATA (2) /* 1 if it is a "data" topic */
157
158
159 typedef struct
160 {
161 unsigned flags; /* see #defines for TF_??? */
162 int doc_page; /* page number in document where topic starts */
163 unsigned title_len; /* length of title */
164 char *title; /* title for this topic */
165 int num_page; /* number of pages */
166 PAGE *page; /* list of pages */
167 unsigned text_len; /* lenth of topic text */
168 long text; /* topic text (all pages) */
169 long offset; /* offset to topic from start of file */
170 } TOPIC;
171
172
173 typedef struct
174 {
175 char *name; /* its name */
176 int topic_num; /* topic number */
177 unsigned topic_off; /* offset of label in the topic's text */
178 int doc_page;
179 } LABEL;
180
181
182 /* values for CONTENT.flags */
183
184 #define CF_NEW_PAGE (1) /* true if section starts on a new page */
185
186
187 #define MAX_CONTENT_TOPIC (10)
188
189
190 typedef struct
191 {
192 unsigned flags;
193 char *id;
194 char *name;
195 int doc_page;
196 unsigned page_num_pos;
197 int num_topic;
198 char is_label[MAX_CONTENT_TOPIC];
199 char *topic_name[MAX_CONTENT_TOPIC];
200 int topic_num[MAX_CONTENT_TOPIC];
201 char *srcfile;
202 int srcline;
203 } CONTENT;
204
205
206 struct help_sig_info
207 {
208 unsigned long sig;
209 int version;
210 unsigned long base;
211 } ;
212
213
214 int num_topic = 0; /* topics */
215 TOPIC *topic;
216
217 int num_label = 0; /* labels */
218 LABEL *label;
219
220 int num_plabel = 0; /* private labels */
221 LABEL *plabel;
222
223 int num_link = 0; /* all links */
224 LINK *a_link = 0;
225
226 int num_contents = 0; /* the table-of-contents */
227 CONTENT *contents;
228
229 int quiet_mode = 0; /* true if "/Q" option used */
230
231 int max_pages = 0; /* max. pages in any topic */
232 int max_links = 0; /* max. links on any page */
233 int num_doc_pages = 0; /* total number of pages in document */
234
235 FILE *srcfile; /* .SRC file */
236 int srcline = 0; /* .SRC line number (used for errors) */
237 int srccol = 0; /* .SRC column. */
238
239 int version = -1; /* help file version */
240
241 int errors = 0, /* number of errors reported */
242 warnings = 0; /* number of warnings reported */
243
244 char src_fname[81] = ""; /* command-line .SRC filename */
245 char hdr_fname[81] = ""; /* .H filename */
246 char hlp_fname[81] = ""; /* .HLP filename */
247 char *src_cfname = NULL; /* current .SRC filename */
248
249 int format_exclude = 0; /* disable formatting at this col, 0 to */
250 /* never disable formatting */
251 FILE *swapfile;
252 long swappos;
253
254 char *buffer; /* alloc'ed as BUFFER_SIZE bytes */
255 char *curr; /* current position in the buffer */
256 char cmd[128]; /* holds the current command */
257 int compress_spaces;
258 int xonline;
259 int xdoc;
260
261 #define MAX_INCLUDE_STACK (5) /* allow 5 nested includes */
262
263 struct
264 {
265 char *fname;
266 FILE *file;
267 int line;
268 int col;
269 } include_stack[MAX_INCLUDE_STACK];
270 int include_stack_top = -1;
271
272
273 #define CHK_BUFFER(off) { if ((long)(curr+(off)) - (long)buffer >= (BUFFER_SIZE-1024)) fatal(0,"Buffer overflowed -- Help topic too large."); }
274
275 #ifdef __WATCOMC__
276 #define putw( x1, x2 ) fprintf( x2, "%c%c", x1&0xFF, x1>>8 );
277 #endif
278
279 #ifdef XFRACT
280 #define putw( x1, x2 ) fwrite( &(x1), 1, sizeof(int), x2);
281 #endif
282
283 /*
284 * error/warning/message reporting functions.
285 */
286
287
report_errors(void)288 void report_errors(void)
289 {
290 printf("\n");
291 printf("Compiler Status:\n");
292 printf("%8d Error%c\n", errors, (errors==1) ? ' ' : 's');
293 printf("%8d Warning%c\n", warnings, (warnings==1) ? ' ' : 's');
294 }
295
296
print_msg(char * type,int lnum,char * format,va_list arg)297 void print_msg(char *type, int lnum, char *format, va_list arg)
298 {
299 if (type != NULL)
300 {
301 printf(" %s", type);
302 if (lnum>0)
303 printf(" %s %d", src_cfname, lnum);
304 printf(": ");
305 }
306 vprintf(format, arg);
307 printf("\n");
308 }
309
310
311 #ifndef USE_VARARGS
fatal(int diff,char * format,...)312 void fatal(int diff, char *format, ...)
313 #else
314 void fatal(va_alist)
315 va_dcl
316 #endif
317 {
318 va_list arg;
319
320 #ifndef USE_VARARGS
321 va_start(arg, format);
322 #else
323 int diff;
324 char *format;
325 va_start(arg);
326 diff = va_arg(arg,int);
327 format = va_arg(arg,char *);
328 #endif
329
330 print_msg("Fatal", srcline-diff, format, arg);
331 va_end(arg);
332
333 if ( errors || warnings )
334 report_errors();
335
336 exit( errors + 1 );
337 }
338
339
340 #ifndef USE_VARARGS
error(int diff,char * format,...)341 void error(int diff, char *format, ...)
342 #else
343 void error(va_alist)
344 va_dcl
345 #endif
346 {
347 va_list arg;
348
349 #ifndef USE_VARARGS
350 va_start(arg, format);
351 #else
352 int diff;
353 char *format;
354 va_start(arg);
355 diff = va_arg(arg,int);
356 format = va_arg(arg,char *);
357 #endif
358 print_msg("Error", srcline-diff, format, arg);
359 va_end(arg);
360
361 if (++errors >= MAX_ERRORS && MAX_ERRORS > 0)
362 fatal(0,"Too many errors!");
363 }
364
365
366 #ifndef USE_VARARGS
warn(int diff,char * format,...)367 void warn(int diff, char *format, ...)
368 #else
369 void warn(va_alist)
370 va_dcl
371 #endif
372 {
373 va_list arg;
374 #ifndef USE_VARARGS
375 va_start(arg, format);
376 #else
377 int diff;
378 char *format;
379 va_start(arg);
380 diff = va_arg(arg, int);
381 format = va_arg(arg, char *);
382 #endif
383 print_msg("Warning", srcline-diff, format, arg);
384 va_end(arg);
385
386 if (++warnings >= MAX_WARNINGS && MAX_WARNINGS > 0)
387 fatal(0,"Too many warnings!");
388 }
389
390
391 #ifndef USE_VARARGS
notice(char * format,...)392 void notice(char *format, ...)
393 #else
394 void notice(va_alist)
395 va_dcl
396 #endif
397 {
398 va_list arg;
399 #ifndef USE_VARARGS
400 va_start(arg, format);
401 #else
402 char *format;
403
404 va_start(arg);
405 format = va_arg(arg,char *);
406 #endif
407 print_msg("Note", srcline, format, arg);
408 va_end(arg);
409 }
410
411
412 #ifndef USE_VARARGS
msg(char * format,...)413 void msg(char *format, ...)
414 #else
415 void msg(va_alist)
416 va_dcl
417 #endif
418 {
419 va_list arg;
420 #ifdef USE_VARARGS
421 char *format;
422 #endif
423
424 if (quiet_mode)
425 return;
426 #ifndef USE_VARARGS
427 va_start(arg, format);
428 #else
429 va_start(arg);
430 format = va_arg(arg,char *);
431 #endif
432 print_msg(NULL, 0, format, arg);
433 va_end(arg);
434 }
435
436
437 #ifdef SHOW_ERROR_LINE
438 # define fatal (printf("[%04d] ", __LINE__), fatal)
439 # define error (printf("[%04d] ", __LINE__), error)
440 # define warn (printf("[%04d] ", __LINE__), warn)
441 # define notice (printf("[%04d] ", __LINE__), notice)
442 # define msg (printf((quiet_mode)?"":"[%04d] ", __LINE__), msg)
443 #endif
444
445
446 /*
447 * store-topic-text-to-disk stuff.
448 */
449
450
alloc_topic_text(TOPIC * t,unsigned size)451 void alloc_topic_text(TOPIC *t, unsigned size)
452 {
453 t->text_len = size;
454 t->text = swappos;
455 swappos += size;
456 fseek(swapfile, t->text, SEEK_SET);
457 fwrite(buffer, 1, t->text_len, swapfile);
458 }
459
460
get_topic_text(TOPIC * t)461 char *get_topic_text(TOPIC *t)
462 {
463 fseek(swapfile, t->text, SEEK_SET);
464 fread(buffer, 1, t->text_len, swapfile);
465 return (buffer);
466 }
467
468
release_topic_text(TOPIC * t,int save)469 void release_topic_text(TOPIC *t, int save)
470 {
471 if ( save )
472 {
473 fseek(swapfile, t->text, SEEK_SET);
474 fwrite(buffer, 1, t->text_len, swapfile);
475 }
476 }
477
478
479 /*
480 * memory-allocation functions.
481 */
482
483
484 #define new(item) (item *)newx(sizeof(item))
485 #define delete(item) free(item)
486
487
newx(unsigned size)488 VOIDPTR newx(unsigned size)
489 {
490 VOIDPTR ptr;
491
492 ptr = malloc(size);
493
494 if (ptr == NULL)
495 fatal(0,"Out of memory!");
496
497 return (ptr);
498 }
499
500
renewx(VOIDPTR ptr,unsigned size)501 VOIDPTR renewx(VOIDPTR ptr, unsigned size)
502 {
503 ptr = realloc(ptr, size);
504
505 if (ptr == NULL)
506 fatal(0,"Out of memory!");
507
508 return (ptr);
509 }
510
511
dupstr(char * s,unsigned len)512 char *dupstr(char *s, unsigned len)
513 {
514 char *ptr;
515
516 if (len == 0)
517 len = strlen(s) + 1;
518
519 ptr = newx(len);
520
521 memcpy(ptr, s, len);
522
523 return (ptr);
524 }
525
526
527 #define LINK_ALLOC_SIZE (16)
528
529
add_link(LINK * l)530 int add_link(LINK *l)
531 {
532 if (num_link == 0)
533 a_link = newx( sizeof(LINK)*LINK_ALLOC_SIZE );
534
535 else if (num_link%LINK_ALLOC_SIZE == 0)
536 a_link = renewx(a_link, sizeof(LINK) * (num_link+LINK_ALLOC_SIZE) );
537
538 a_link[num_link] = *l;
539
540 return( num_link++ );
541 }
542
543
544 #define PAGE_ALLOC_SIZE (4)
545
546
add_page(TOPIC * t,PAGE * p)547 int add_page(TOPIC *t, PAGE *p)
548 {
549 if (t->num_page == 0)
550 t->page = newx( sizeof(PAGE)*PAGE_ALLOC_SIZE );
551
552 else if (t->num_page%PAGE_ALLOC_SIZE == 0)
553 t->page = renewx(t->page, sizeof(PAGE) * (t->num_page+PAGE_ALLOC_SIZE) );
554
555 t->page[t->num_page] = *p;
556
557 return ( t->num_page++ );
558 }
559
560
561 #define TOPIC_ALLOC_SIZE (16)
562
563
add_topic(TOPIC * t)564 int add_topic(TOPIC *t)
565 {
566 if (num_topic == 0)
567 topic = newx( sizeof(TOPIC)*TOPIC_ALLOC_SIZE );
568
569 else if (num_topic%TOPIC_ALLOC_SIZE == 0)
570 topic = renewx(topic, sizeof(TOPIC) * (num_topic+TOPIC_ALLOC_SIZE) );
571
572 topic[num_topic] = *t;
573
574 return ( num_topic++ );
575 }
576
577
578 #define LABEL_ALLOC_SIZE (16)
579
580
add_label(LABEL * l)581 int add_label(LABEL *l)
582 {
583 if (l->name[0] == '@') /* if it's a private label... */
584 {
585 if (num_plabel == 0)
586 plabel = newx( sizeof(LABEL)*LABEL_ALLOC_SIZE );
587
588 else if (num_plabel%LABEL_ALLOC_SIZE == 0)
589 plabel = renewx(plabel, sizeof(LABEL) * (num_plabel+LABEL_ALLOC_SIZE) );
590
591 plabel[num_plabel] = *l;
592
593 return ( num_plabel++ );
594 }
595 else
596 {
597 if (num_label == 0)
598 label = newx( sizeof(LABEL)*LABEL_ALLOC_SIZE );
599
600 else if (num_label%LABEL_ALLOC_SIZE == 0)
601 label = renewx(label, sizeof(LABEL) * (num_label+LABEL_ALLOC_SIZE) );
602
603 label[num_label] = *l;
604
605 return ( num_label++ );
606 }
607 }
608
609
610 #define CONTENTS_ALLOC_SIZE (16)
611
612
add_content(CONTENT * c)613 int add_content(CONTENT *c)
614 {
615 if (num_contents == 0)
616 contents = newx( sizeof(CONTENT)*CONTENTS_ALLOC_SIZE );
617
618 else if (num_contents%CONTENTS_ALLOC_SIZE == 0)
619 contents = renewx(contents, sizeof(CONTENT) * (num_contents+CONTENTS_ALLOC_SIZE) );
620
621 contents[num_contents] = *c;
622
623 return ( num_contents++ );
624 }
625
626
627 /*
628 * read_char() stuff
629 */
630
631
632 #define READ_CHAR_BUFF_SIZE (32)
633
634
635 int read_char_buff[READ_CHAR_BUFF_SIZE];
636 int read_char_buff_pos = -1;
637 int read_char_sp = 0;
638
639
unread_char(int ch)640 void unread_char(int ch)
641 /*
642 * Will not handle new-lines or tabs correctly!
643 */
644 {
645 if (read_char_buff_pos+1 >= READ_CHAR_BUFF_SIZE)
646 fatal(0,"Compiler Error -- Read char buffer overflow!");
647
648 read_char_buff[++read_char_buff_pos] = ch;
649
650 --srccol;
651 }
652
653
unread_string(char * s)654 void unread_string(char *s)
655 {
656 int p = strlen(s);
657
658 while (p-- > 0)
659 unread_char(s[p]);
660 }
661
662
eos(void)663 int eos(void) /* end-of-source ? */
664 {
665 return ( !((read_char_sp==0) && (read_char_buff_pos==0) && feof(srcfile)) );
666 }
667
668
_read_char(void)669 int _read_char(void)
670 {
671 int ch;
672
673 if (srcline <= 0)
674 {
675 srcline = 1;
676 srccol = 0;
677 }
678
679 if (read_char_buff_pos >= 0)
680 {
681 ++srccol;
682 return ( read_char_buff[read_char_buff_pos--] );
683 }
684
685 if (read_char_sp > 0)
686 {
687 --read_char_sp;
688 return (' ');
689 }
690
691 if ( feof(srcfile) )
692 return (-1);
693
694 while (1)
695 {
696 ch = getc(srcfile);
697
698 switch (ch)
699 {
700 case '\t': /* expand a tab */
701 {
702 int diff = ( ( (srccol/8) + 1 ) * 8 ) - srccol;
703
704 srccol += diff;
705 read_char_sp += diff;
706 break;
707 }
708
709 case ' ':
710 ++srccol;
711 ++read_char_sp;
712 break;
713
714 case '\n':
715 read_char_sp = 0; /* delete spaces before a \n */
716 srccol = 0;
717 ++srcline;
718 return ('\n');
719
720 case -1: /* EOF */
721 if (read_char_sp > 0)
722 {
723 --read_char_sp;
724 return (' ');
725 }
726 return (-1);
727
728 default:
729 if (read_char_sp > 0)
730 {
731 ungetc(ch, srcfile);
732 --read_char_sp;
733 return (' ');
734 }
735
736 ++srccol;
737 return (ch);
738
739 } /* switch */
740 }
741 }
742
743
read_char(void)744 int read_char(void)
745 {
746 int ch;
747
748 ch = _read_char();
749
750 while (ch == ';' && srccol==1) /* skip over comments */
751 {
752 ch = _read_char();
753
754 while (ch!='\n' && ch!=-1 )
755 ch = _read_char();
756
757 ch = _read_char();
758 }
759
760 if (ch == '\\') /* process an escape code */
761 {
762 ch = _read_char();
763
764 if (ch >= '0' && ch <= '9')
765 {
766 char buff[4];
767 int ctr;
768
769 for (ctr=0; ; ctr++)
770 {
771 if ( ch<'0' || ch>'9' || ch==-1 || ctr>=3 )
772 {
773 unread_char(ch);
774 break;
775 }
776 buff[ctr] = ch;
777 ch = _read_char();
778 }
779 buff[ctr] = '\0';
780 ch = atoi(buff);
781 }
782
783 #ifdef XFRACT
784 /* Convert graphics arrows into keyboard chars */
785 if (ch>=24 && ch<=27) {
786 ch = "KJHL"[ch-24];
787 }
788 #endif
789 ch |= 0x100;
790 }
791
792 if ( (ch & 0xFF) == 0 )
793 {
794 error(0,"Null character (\'\\0\') not allowed!");
795 ch = 0x1FF; /* since we've had an error the file will not be written; */
796 /* the value we return doesn't really matter */
797 }
798
799 return(ch);
800 }
801
802
803 /*
804 * misc. search functions.
805 */
806
807
find_label(char * name)808 LABEL *find_label(char *name)
809 {
810 int l;
811 LABEL *lp;
812
813 if (*name == '@')
814 {
815 for (l=0, lp=plabel; l<num_plabel; l++, lp++)
816 if ( strcmp(name, lp->name) == 0 )
817 return (lp);
818 }
819 else
820 {
821 for (l=0, lp=label; l<num_label; l++, lp++)
822 if ( strcmp(name, lp->name) == 0 )
823 return (lp);
824 }
825
826 return (NULL);
827 }
828
829
find_topic_title(char * title)830 int find_topic_title(char *title)
831 {
832 int t;
833 int len;
834
835 while (*title == ' ')
836 ++title;
837
838 len = strlen(title) - 1;
839 while ( title[len] == ' ' && len > 0 )
840 --len;
841
842 ++len;
843
844 if ( len > 2 && title[0] == '\"' && title[len-1] == '\"' )
845 {
846 ++title;
847 len -= 2;
848 }
849
850 for (t=0; t<num_topic; t++)
851 if ( strlen(topic[t].title) == len &&
852 strnicmp(title, topic[t].title, len) == 0 )
853 return (t);
854
855 return (-1); /* not found */
856 }
857
858
859 /*
860 * .SRC file parser stuff
861 */
862
863
validate_label_name(char * name)864 int validate_label_name(char *name)
865 {
866 if ( !isalpha(*name) && *name!='@' && *name!='_' )
867 return (0); /* invalid */
868
869 while (*(++name) != '\0')
870 if ( !isalpha(*name) && !isdigit(*name) && *name!='_' )
871 return(0); /* invalid */
872
873 return (1); /* valid */
874 }
875
876
read_until(char * buff,int len,char * stop_chars)877 char *read_until(char *buff, int len, char *stop_chars)
878 {
879 int ch;
880
881 while ( --len > 0 )
882 {
883 ch = read_char();
884
885 if ( ch == -1 )
886 {
887 *buff++ = '\0';
888 break;
889 }
890
891 if ( (ch&0xFF) <= MAX_CMD )
892 *buff++ = CMD_LITERAL;
893
894 *buff++ = ch;
895
896 if ( (ch&0x100)==0 && strchr(stop_chars, ch) != NULL )
897 break;
898 }
899
900 return ( buff-1 );
901 }
902
903
skip_over(char * skip)904 void skip_over(char *skip)
905 {
906 int ch;
907
908 while (1)
909 {
910 ch = read_char();
911
912 if ( ch == -1 )
913 break;
914
915 else if ( (ch&0x100) == 0 && strchr(skip, ch) == NULL )
916 {
917 unread_char(ch);
918 break;
919 }
920 }
921 }
922
923
pchar(int ch)924 char *pchar(int ch)
925 {
926 static char buff[16];
927
928 if ( ch >= 0x20 && ch <= 0x7E )
929 sprintf(buff, "\'%c\'", ch);
930 else
931 sprintf(buff, "\'\\x%02X\'", ch&0xFF);
932
933 return (buff);
934 }
935
936
put_spaces(int how_many)937 void put_spaces(int how_many)
938 {
939 if (how_many > 2 && compress_spaces)
940 {
941 if (how_many > 255)
942 {
943 error(0,"Too many spaces (over 255).");
944 how_many = 255;
945 }
946
947 *curr++ = CMD_SPACE;
948 *curr++ = (BYTE)how_many;
949 }
950 else
951 {
952 while (how_many-- > 0)
953 *curr++ = ' ';
954 }
955 }
956
957
get_next_item(void)958 int get_next_item(void) /* used by parse_contents() */
959 {
960 int last;
961 char *ptr;
962
963 skip_over(" \t\n");
964 ptr = read_until(cmd, 128, ",}");
965 last = (*ptr == '}');
966 --ptr;
967 while ( ptr >= cmd && strchr(" \t\n",*ptr) ) /* strip trailing spaces */
968 --ptr;
969 *(++ptr) = '\0';
970
971 return (last);
972 }
973
974
process_contents(void)975 void process_contents(void)
976 {
977 CONTENT c;
978 char *ptr;
979 int indent;
980 int ch;
981 TOPIC t;
982
983 t.flags = 0;
984 t.title_len = strlen(DOCCONTENTS_TITLE)+1;
985 t.title = dupstr(DOCCONTENTS_TITLE, t.title_len);
986 t.doc_page = -1;
987 t.num_page = 0;
988
989 curr = buffer;
990
991 c.flags = 0;
992 c.id = dupstr("",1);
993 c.name = dupstr("",1);
994 c.doc_page = -1;
995 c.page_num_pos = 0;
996 c.num_topic = 1;
997 c.is_label[0] = 0;
998 c.topic_name[0] = dupstr(DOCCONTENTS_TITLE,0);
999 c.srcline = -1;
1000 add_content(&c);
1001
1002 while (1)
1003 {
1004 ch = read_char();
1005
1006 if (ch == '{') /* process a CONTENT entry */
1007 {
1008 int last;
1009
1010 c.flags = 0;
1011 c.num_topic = 0;
1012 c.doc_page = -1;
1013 c.srcfile = src_cfname;
1014 c.srcline = srcline;
1015
1016 if ( get_next_item() )
1017 {
1018 error(0,"Unexpected end of DocContent entry.");
1019 continue;
1020 }
1021 c.id = dupstr(cmd,0);
1022
1023 if ( get_next_item() )
1024 {
1025 error(0,"Unexpected end of DocContent entry.");
1026 continue;
1027 }
1028 indent = atoi(cmd);
1029
1030 last = get_next_item();
1031
1032 if ( cmd[0] == '\"' )
1033 {
1034 ptr = cmd+1;
1035 if (ptr[strlen(ptr)-1] == '\"')
1036 ptr[strlen(ptr)-1] = '\0';
1037 else
1038 warn(0,"Missing ending quote.");
1039
1040 c.is_label[c.num_topic] = 0;
1041 c.topic_name[c.num_topic] = dupstr(ptr,0);
1042 ++c.num_topic;
1043 c.name = dupstr(ptr,0);
1044 }
1045 else
1046 c.name = dupstr(cmd,0);
1047
1048 /* now, make the entry in the buffer */
1049
1050 sprintf(curr, "%-5s %*.0s%s", c.id, indent*2, "", c.name);
1051 ptr = curr + strlen(curr);
1052 while ( (ptr-curr) < PAGE_WIDTH-10 )
1053 *ptr++ = '.';
1054 c.page_num_pos = (unsigned) ( (ptr-3) - buffer );
1055 curr = ptr;
1056
1057 while (!last)
1058 {
1059 last = get_next_item();
1060
1061 if ( stricmp(cmd, "FF") == 0 )
1062 {
1063 if ( c.flags & CF_NEW_PAGE )
1064 warn(0,"FF already present in this entry.");
1065 c.flags |= CF_NEW_PAGE;
1066 continue;
1067 }
1068
1069 if (cmd[0] == '\"')
1070 {
1071 ptr = cmd+1;
1072 if (ptr[strlen(ptr)-1] == '\"')
1073 ptr[strlen(ptr)-1] = '\0';
1074 else
1075 warn(0,"Missing ending quote.");
1076
1077 c.is_label[c.num_topic] = 0;
1078 c.topic_name[c.num_topic] = dupstr(ptr,0);
1079 }
1080 else
1081 {
1082 c.is_label[c.num_topic] = 1;
1083 c.topic_name[c.num_topic] = dupstr(cmd,0);
1084 }
1085
1086 if ( ++c.num_topic >= MAX_CONTENT_TOPIC )
1087 {
1088 error(0,"Too many topics in DocContent entry.");
1089 break;
1090 }
1091 }
1092
1093 add_content(&c);
1094 }
1095
1096 else if (ch == '~') /* end at any command */
1097 {
1098 unread_char(ch);
1099 break;
1100 }
1101
1102 else
1103 *curr++ = ch;
1104
1105 CHK_BUFFER(0);
1106 }
1107
1108 alloc_topic_text(&t, (unsigned) (curr - buffer) );
1109 add_topic(&t);
1110 }
1111
1112
parse_link(void)1113 int parse_link(void) /* returns length of link or 0 on error */
1114 {
1115 char *ptr;
1116 char *end;
1117 int bad = 0;
1118 int len;
1119 LINK l;
1120 int lnum;
1121 int err_off;
1122
1123 l.srcfile = src_cfname;
1124 l.srcline = srcline;
1125 l.doc_page = -1;
1126
1127 end = read_until(cmd, 128, "}\n"); /* get the entire hot-link */
1128
1129 if (*end == '\0')
1130 {
1131 error(0,"Unexpected EOF in hot-link.");
1132 return (0);
1133 }
1134
1135 if (*end == '\n')
1136 {
1137 err_off = 1;
1138 warn(1,"Hot-link has no closing curly-brace (\'}\').");
1139 }
1140 else
1141 err_off = 0;
1142
1143 *end = '\0';
1144
1145 if (cmd[0] == '=') /* it's an "explicit" link to a label or "special" */
1146 {
1147 ptr = strchr(cmd, ' ');
1148
1149 if (ptr == NULL)
1150 ptr = end;
1151 else
1152 *ptr++ = '\0';
1153
1154 len = (int) (end - ptr);
1155
1156 if ( cmd[1] == '-' )
1157 {
1158 l.type = 2; /* type 2 = "special" */
1159 l.topic_num = atoi(cmd+1);
1160 l.topic_off = 0;
1161 l.name = NULL;
1162 }
1163 else
1164 {
1165 l.type = 1; /* type 1 = to a label */
1166 if ((int)strlen(cmd) > 32)
1167 warn(err_off, "Label is long.");
1168 if (cmd[1] == '\0')
1169 {
1170 error(err_off, "Explicit hot-link has no Label.");
1171 bad = 1;
1172 }
1173 else
1174 l.name = dupstr(cmd+1,0);
1175 }
1176 if (len == 0)
1177 warn(err_off, "Explicit hot-link has no title.");
1178 }
1179 else
1180 {
1181 ptr = cmd;
1182 l.type = 0; /* type 0 = topic title */
1183 len = (int) (end - ptr);
1184 if (len == 0)
1185 {
1186 error(err_off, "Implicit hot-link has no title.");
1187 bad = 1;
1188 }
1189 l.name = dupstr(ptr,len+1);
1190 l.name[len] = '\0';
1191 }
1192
1193 if ( !bad )
1194 {
1195 CHK_BUFFER(1+3*sizeof(int)+len+1)
1196 lnum = add_link(&l);
1197 *curr++ = CMD_LINK;
1198 setint(curr,lnum);
1199 curr += 3*sizeof(int);
1200 memcpy(curr, ptr, len);
1201 curr += len;
1202 *curr++ = CMD_LINK;
1203 return (len);
1204 }
1205 else
1206 return (0);
1207 }
1208
1209
1210 #define MAX_TABLE_SIZE (100)
1211
1212
create_table(void)1213 int create_table(void)
1214 {
1215 char *ptr;
1216 int width;
1217 int cols;
1218 int start_off;
1219 int first_link;
1220 int rows;
1221 int r, c;
1222 int ch;
1223 int done;
1224 int len;
1225 int lnum;
1226 int count;
1227 char *title[MAX_TABLE_SIZE];
1228 char *table_start;
1229
1230 ptr = strchr(cmd, '=');
1231
1232 if (ptr == NULL)
1233 return (0); /* should never happen! */
1234
1235 ptr++;
1236
1237 len = sscanf(ptr, " %d %d %d", &width, &cols, &start_off);
1238
1239 if (len < 3)
1240 {
1241 error(1,"Too few arguments to Table.");
1242 return (0);
1243 }
1244
1245 if (width<=0 || width > 78 || cols<=0 || start_off<0 || start_off > 78)
1246 {
1247 error(1,"Argument out of range.");
1248 return (0);
1249 }
1250
1251 done = 0;
1252
1253 first_link = num_link;
1254 table_start = curr;
1255 count = 0;
1256
1257 /* first, read all the links in the table */
1258
1259 do
1260 {
1261
1262 do
1263 ch = read_char();
1264 while ( ch=='\n' || ch == ' ' );
1265
1266 if (done)
1267 break;
1268
1269 switch (ch)
1270 {
1271 case -1:
1272 error(0,"Unexpected EOF in a Table.");
1273 return(0);
1274
1275 case '{':
1276 if (count >= MAX_TABLE_SIZE)
1277 fatal(0,"Table is too large.");
1278 len = parse_link();
1279 curr = table_start; /* reset to the start... */
1280 title[count] = dupstr(curr+3*sizeof(int)+1, len+1);
1281 if (len >= width)
1282 {
1283 warn(1,"Link is too long; truncating.");
1284 len = width-1;
1285 }
1286 title[count][len] = '\0';
1287 ++count;
1288 break;
1289
1290 case '~':
1291 {
1292 int imbedded;
1293
1294 ch = read_char();
1295
1296 if (ch=='(')
1297 imbedded = 1;
1298 else
1299 {
1300 imbedded = 0;
1301 unread_char(ch);
1302 }
1303
1304 ptr = read_until(cmd, 128, ")\n,");
1305
1306 ch = *ptr;
1307 *ptr = '\0';
1308
1309 if ( stricmp(cmd, "EndTable") == 0 )
1310 done = 1;
1311 else
1312 {
1313 error(1,"Unexpected command in table \"%s\"", cmd);
1314 warn(1,"Command will be ignored.");
1315 }
1316
1317 if (ch == ',')
1318 {
1319 if (imbedded)
1320 unread_char('(');
1321 unread_char('~');
1322 }
1323 }
1324 break;
1325
1326 default:
1327 error(0,"Unexpected character %s.", pchar(ch));
1328 break;
1329 }
1330 }
1331 while (!done);
1332
1333 /* now, put all the links into the buffer... */
1334
1335 rows = 1 + ( count / cols );
1336
1337 for (r=0; r<rows; r++)
1338 {
1339 put_spaces(start_off);
1340 for (c=0; c<cols; c++)
1341 {
1342 lnum = c*rows + r;
1343
1344 if ( first_link+lnum >= num_link )
1345 break;
1346
1347 len = strlen(title[lnum]);
1348 *curr++ = CMD_LINK;
1349 setint(curr,first_link+lnum);
1350 curr += 3*sizeof(int);
1351 memcpy(curr, title[lnum], len);
1352 curr += len;
1353 *curr++ = CMD_LINK;
1354
1355 delete(title[lnum]);
1356
1357 if ( c < cols-1 )
1358 put_spaces( width-len );
1359 }
1360 *curr++ = '\n';
1361 }
1362
1363 return (1);
1364 }
1365
1366
process_comment(void)1367 void process_comment(void)
1368 {
1369 int ch;
1370
1371 while ( 1 )
1372 {
1373 ch = read_char();
1374
1375 if (ch == '~')
1376 {
1377 int imbedded;
1378 char *ptr;
1379
1380 ch = read_char();
1381
1382 if (ch=='(')
1383 imbedded = 1;
1384 else
1385 {
1386 imbedded = 0;
1387 unread_char(ch);
1388 }
1389
1390 ptr = read_until(cmd, 128, ")\n,");
1391
1392 ch = *ptr;
1393 *ptr = '\0';
1394
1395 if ( stricmp(cmd, "EndComment") == 0 )
1396 {
1397 if (ch == ',')
1398 {
1399 if (imbedded)
1400 unread_char('(');
1401 unread_char('~');
1402 }
1403 break;
1404 }
1405 }
1406
1407 else if ( ch == -1 )
1408 {
1409 error(0,"Unexpected EOF in Comment");
1410 break;
1411 }
1412 }
1413 }
1414
1415
process_bininc(void)1416 void process_bininc(void)
1417 {
1418 int handle;
1419 long len;
1420
1421 if ( (handle=open(cmd+7, O_RDONLY|O_BINARY)) == -1 )
1422 {
1423 error(0,"Unable to open \"%s\"", cmd+7);
1424 return ;
1425 }
1426
1427 len = filelength(handle);
1428
1429 if ( len >= BUFFER_SIZE )
1430 {
1431 error(0,"File \"%s\" is too large to BinInc (%dK).", cmd+7, (int)(len>>10));
1432 close(handle);
1433 return ;
1434 }
1435
1436 /*
1437 * Since we know len is less than BUFFER_SIZE (and therefore less then
1438 * 64K) we can treat it as an unsigned.
1439 */
1440
1441 CHK_BUFFER((unsigned)len);
1442
1443 read(handle, curr, (unsigned)len);
1444
1445 curr += (unsigned)len;
1446
1447 close(handle);
1448 }
1449
1450
start_topic(TOPIC * t,char * title,int title_len)1451 void start_topic(TOPIC *t, char *title, int title_len)
1452 {
1453 t->flags = 0;
1454 t->title_len = title_len;
1455 t->title = dupstr(title, title_len+1);
1456 t->title[title_len] = '\0';
1457 t->doc_page = -1;
1458 t->num_page = 0;
1459 curr = buffer;
1460 }
1461
1462
end_topic(TOPIC * t)1463 void end_topic(TOPIC *t)
1464 {
1465 alloc_topic_text(t, (unsigned) (curr - buffer) );
1466 add_topic(t);
1467 }
1468
1469
end_of_sentence(char * ptr)1470 int end_of_sentence(char *ptr) /* true if ptr is at the end of a sentence */
1471 {
1472 if ( *ptr == ')')
1473 --ptr;
1474
1475 if ( *ptr == '\"')
1476 --ptr;
1477
1478 return ( *ptr=='.' || *ptr=='?' || *ptr=='!' );
1479 }
1480
1481
add_blank_for_split(void)1482 void add_blank_for_split(void) /* add space at curr for merging two lines */
1483 {
1484 if ( !is_hyphen(curr-1) ) /* no spaces if it's a hyphen */
1485 {
1486 if ( end_of_sentence(curr-1) )
1487 *curr++ = ' '; /* two spaces at end of a sentence */
1488 *curr++ = ' ';
1489 }
1490 }
1491
1492
put_a_char(int ch,TOPIC * t)1493 void put_a_char(int ch, TOPIC *t)
1494 {
1495 if (ch == '{' && !(t->flags & TF_DATA) ) /* is it a hot-link? */
1496 parse_link();
1497 else
1498 {
1499 if ( (ch&0xFF) <= MAX_CMD)
1500 *curr++ = CMD_LITERAL;
1501 *curr++ = ch;
1502 }
1503 }
1504
1505
1506 enum STATES /* states for FSM's */
1507 {
1508 S_Start, /* initial state, between paragraphs */
1509 S_StartFirstLine, /* spaces at start of first line */
1510 S_FirstLine, /* text on the first line */
1511 S_FirstLineSpaces, /* spaces on the first line */
1512 S_StartSecondLine, /* spaces at start of second line */
1513 S_Line, /* text on lines after the first */
1514 S_LineSpaces, /* spaces on lines after the first */
1515 S_StartLine, /* spaces at start of lines after second */
1516 S_FormatDisabled, /* format automatically disabled for this line */
1517 S_FormatDisabledSpaces, /* spaces in line which format is disabled */
1518 S_Spaces
1519 } ;
1520
1521
check_command_length(int eoff,int len)1522 void check_command_length(int eoff, int len)
1523 {
1524 if (strlen(cmd) != len)
1525 error(eoff, "Invalid text after a command \"%s\"", cmd+len);
1526 }
1527
1528
read_src(char * fname)1529 void read_src(char *fname)
1530 {
1531 int ch;
1532 char *ptr;
1533 TOPIC t;
1534 LABEL lbl;
1535 char *margin_pos = NULL;
1536 int in_topic = 0,
1537 formatting = 1,
1538 state = S_Start,
1539 num_spaces = 0,
1540 margin = 0,
1541 in_para = 0,
1542 centering = 0,
1543 lformat_exclude = format_exclude,
1544 again;
1545
1546 xonline = xdoc = 0;
1547
1548 src_cfname = fname;
1549
1550 if ( (srcfile = fopen(fname, "rt")) == NULL )
1551 fatal(0,"Unable to open \"%s\"", fname);
1552
1553 msg("Compiling: %s", fname);
1554
1555 in_topic = 0;
1556
1557 curr = buffer;
1558
1559 while ( 1 )
1560 {
1561
1562 ch = read_char();
1563
1564 if ( ch == -1 ) /* EOF? */
1565 {
1566 if ( include_stack_top >= 0)
1567 {
1568 fclose(srcfile);
1569 src_cfname = include_stack[include_stack_top].fname;
1570 srcfile = include_stack[include_stack_top].file;
1571 srcline = include_stack[include_stack_top].line;
1572 srccol = include_stack[include_stack_top].col;
1573 --include_stack_top;
1574 continue;
1575 }
1576 else
1577 {
1578 if (in_topic) /* if we're in a topic, finish it */
1579 end_topic(&t);
1580 if (num_topic == 0)
1581 warn(0,".SRC file has no topics.");
1582 break;
1583 }
1584 }
1585
1586 if (ch == '~') /* is is a command? */
1587 {
1588 int imbedded;
1589 int eoff;
1590 int done;
1591
1592 ch = read_char();
1593 if (ch == '(')
1594 {
1595 imbedded = 1;
1596 eoff = 0;
1597 }
1598 else
1599 {
1600 imbedded = 0;
1601 eoff=0;
1602 unread_char(ch);
1603 }
1604
1605 done = 0;
1606
1607 while ( !done )
1608 {
1609 do
1610 ch = read_char();
1611 while (ch == ' ');
1612 unread_char(ch);
1613
1614 if (imbedded)
1615 ptr = read_until(cmd, 128, ")\n,");
1616 else
1617 ptr = read_until(cmd, 128, "\n,");
1618
1619 done = 1;
1620
1621 if ( *ptr == '\0' )
1622 {
1623 error(0,"Unexpected EOF in command.");
1624 break;
1625 }
1626
1627 if (*ptr == '\n')
1628 ++eoff;
1629
1630 if ( imbedded && *ptr == '\n' )
1631 error(eoff,"Imbedded command has no closing parend (\')\')");
1632
1633 done = (*ptr != ','); /* we done if it's not a comma */
1634
1635 if ( *ptr != '\n' && *ptr != ')' && *ptr != ',' )
1636 {
1637 error(0,"Command line too long.");
1638 break;
1639 }
1640
1641 *ptr = '\0';
1642
1643
1644 /* commands allowed anytime... */
1645
1646 if ( strnicmp(cmd, "Topic=", 6) == 0 )
1647 {
1648 if (in_topic) /* if we're in a topic, finish it */
1649 end_topic(&t);
1650 else
1651 in_topic = 1;
1652
1653 if (cmd[6] == '\0')
1654 warn(eoff,"Topic has no title.");
1655
1656 else if ((int)strlen(cmd+6) > 70)
1657 error(eoff,"Topic title is too long.");
1658
1659 else if ((int)strlen(cmd+6) > 60)
1660 warn(eoff,"Topic title is long.");
1661
1662 if ( find_topic_title(cmd+6) != -1 )
1663 error(eoff,"Topic title already exists.");
1664
1665 start_topic(&t, cmd+6, (unsigned)(ptr-(cmd+6)));
1666 formatting = 1;
1667 centering = 0;
1668 state = S_Start;
1669 in_para = 0;
1670 num_spaces = 0;
1671 xonline = xdoc = 0;
1672 lformat_exclude = format_exclude;
1673 compress_spaces = 1;
1674 continue;
1675 }
1676
1677 else if ( strnicmp(cmd, "Data=", 5) == 0 )
1678 {
1679 if (in_topic) /* if we're in a topic, finish it */
1680 end_topic(&t);
1681 else
1682 in_topic = 1;
1683
1684 if (cmd[5] == '\0')
1685 warn(eoff,"Data topic has no label.");
1686
1687 if ( !validate_label_name(cmd+5) )
1688 {
1689 error(eoff,"Label \"%s\" contains illegal characters.", cmd+5);
1690 continue;
1691 }
1692
1693 if ( find_label(cmd+5) != NULL )
1694 {
1695 error(eoff,"Label \"%s\" already exists", cmd+5);
1696 continue;
1697 }
1698
1699 if ( cmd[5] == '@' )
1700 warn(eoff, "Data topic has a local label.");
1701
1702 start_topic(&t, "", 0);
1703 t.flags |= TF_DATA;
1704
1705 if ((int)strlen(cmd+5) > 32)
1706 warn(eoff,"Label name is long.");
1707
1708 lbl.name = dupstr(cmd+5, 0);
1709 lbl.topic_num = num_topic;
1710 lbl.topic_off = 0;
1711 lbl.doc_page = -1;
1712 add_label(&lbl);
1713
1714 formatting = 0;
1715 centering = 0;
1716 state = S_Start;
1717 in_para = 0;
1718 num_spaces = 0;
1719 xonline = xdoc = 0;
1720 lformat_exclude = format_exclude;
1721 compress_spaces = 0;
1722 continue;
1723 }
1724
1725 else if ( strnicmp(cmd, "DocContents", 11) == 0 )
1726 {
1727 check_command_length(eoff, 11);
1728 if (in_topic) /* if we're in a topic, finish it */
1729 end_topic(&t);
1730 if (!done)
1731 {
1732 if (imbedded)
1733 unread_char('(');
1734 unread_char('~');
1735 done = 1;
1736 }
1737 compress_spaces = 1;
1738 process_contents();
1739 in_topic = 0;
1740 continue;
1741 }
1742
1743 else if ( stricmp(cmd, "Comment") == 0 )
1744 {
1745 process_comment();
1746 continue;
1747 }
1748
1749 else if ( strnicmp(cmd, "FormatExclude", 13) == 0 )
1750 {
1751 if (cmd[13] == '-')
1752 {
1753 check_command_length(eoff, 14);
1754 if ( in_topic )
1755 {
1756 if (lformat_exclude > 0)
1757 lformat_exclude = -lformat_exclude;
1758 else
1759 warn(eoff,"\"FormatExclude-\" is already in effect.");
1760 }
1761 else
1762 {
1763 if (format_exclude > 0)
1764 format_exclude = -format_exclude;
1765 else
1766 warn(eoff,"\"FormatExclude-\" is already in effect.");
1767 }
1768 }
1769 else if (cmd[13] == '+')
1770 {
1771 check_command_length(eoff,14);
1772 if ( in_topic )
1773 {
1774 if (lformat_exclude < 0)
1775 lformat_exclude = -lformat_exclude;
1776 else
1777 warn(eoff,"\"FormatExclude+\" is already in effect.");
1778 }
1779 else
1780 {
1781 if (format_exclude < 0)
1782 format_exclude = -format_exclude;
1783 else
1784 warn(eoff,"\"FormatExclude+\" is already in effect.");
1785 }
1786 }
1787 else if (cmd[13] == '=')
1788 {
1789 if (cmd[14] == 'n' || cmd[14] == 'N')
1790 {
1791 check_command_length(eoff,15);
1792 if (in_topic)
1793 lformat_exclude = 0;
1794 else
1795 format_exclude = 0;
1796 }
1797 else if (cmd[14] == '\0')
1798 lformat_exclude = format_exclude;
1799 else
1800 {
1801 int n = ( ( (in_topic) ? lformat_exclude : format_exclude) < 0 ) ? -1 : 1;
1802
1803 lformat_exclude = atoi(cmd+14);
1804
1805 if ( lformat_exclude <= 0 )
1806 {
1807 error(eoff,"Invalid argument to FormatExclude=");
1808 lformat_exclude = 0;
1809 }
1810
1811 lformat_exclude *= n;
1812
1813 if ( !in_topic )
1814 format_exclude = lformat_exclude;
1815 }
1816 }
1817 else
1818 error(eoff,"Invalid format for FormatExclude");
1819
1820 continue;
1821 }
1822
1823 else if ( strnicmp(cmd, "Include ", 8) == 0 )
1824 {
1825 if (include_stack_top >= MAX_INCLUDE_STACK-1)
1826 error(eoff, "Too many nested Includes.");
1827 else
1828 {
1829 ++include_stack_top;
1830 include_stack[include_stack_top].fname = src_cfname;
1831 include_stack[include_stack_top].file = srcfile;
1832 include_stack[include_stack_top].line = srcline;
1833 include_stack[include_stack_top].col = srccol;
1834 strupr(cmd+8);
1835 if ( (srcfile = fopen(cmd+8, "rt")) == NULL )
1836 {
1837 error(eoff, "Unable to open \"%s\"", cmd+8);
1838 srcfile = include_stack[include_stack_top--].file;
1839 }
1840 src_cfname = dupstr(cmd+8,0); /* never deallocate! */
1841 srcline = 1;
1842 srccol = 0;
1843 }
1844
1845 continue;
1846 }
1847
1848
1849 /* commands allowed only before all topics... */
1850
1851 if ( !in_topic )
1852 {
1853 if ( strnicmp(cmd, "HdrFile=", 8) == 0 )
1854 {
1855 if (hdr_fname[0] != '\0')
1856 warn(eoff,"Header Filename has already been defined.");
1857 strcpy(hdr_fname, cmd+8);
1858 strupr(hdr_fname);
1859 }
1860
1861 else if ( strnicmp(cmd, "HlpFile=", 8) == 0 )
1862 {
1863 if (hlp_fname[0] != '\0')
1864 warn(eoff,"Help Filename has already been defined.");
1865 strcpy(hlp_fname, cmd+8);
1866 strupr(hlp_fname);
1867 }
1868
1869 else if ( strnicmp(cmd, "Version=", 8) == 0 )
1870 {
1871 if (version != -1) /* an unlikely value */
1872 warn(eoff,"Help version has already been defined");
1873 version = atoi(cmd+8);
1874 }
1875
1876 else
1877 error(eoff,"Bad or unexpected command \"%s\"", cmd);
1878
1879 continue;
1880 }
1881
1882
1883 /* commands allowed only in a topic... */
1884
1885 else
1886 {
1887 if (strnicmp(cmd, "FF", 2) == 0 )
1888 {
1889 check_command_length(eoff,2);
1890 if ( in_para )
1891 *curr++ = '\n'; /* finish off current paragraph */
1892 *curr++ = CMD_FF;
1893 state = S_Start;
1894 in_para = 0;
1895 num_spaces = 0;
1896 }
1897
1898 else if (strnicmp(cmd, "DocFF", 5) == 0 )
1899 {
1900 check_command_length(eoff,5);
1901 if ( in_para )
1902 *curr++ = '\n'; /* finish off current paragraph */
1903 if (!xonline)
1904 *curr++ = CMD_XONLINE;
1905 *curr++ = CMD_FF;
1906 if (!xonline)
1907 *curr++ = CMD_XONLINE;
1908 state = S_Start;
1909 in_para = 0;
1910 num_spaces = 0;
1911 }
1912
1913 else if (strnicmp(cmd, "OnlineFF", 8) == 0 )
1914 {
1915 check_command_length(eoff,8);
1916 if ( in_para )
1917 *curr++ = '\n'; /* finish off current paragraph */
1918 if (!xdoc)
1919 *curr++ = CMD_XDOC;
1920 *curr++ = CMD_FF;
1921 if (!xdoc)
1922 *curr++ = CMD_XDOC;
1923 state = S_Start;
1924 in_para = 0;
1925 num_spaces = 0;
1926 }
1927
1928 else if ( strnicmp(cmd, "Label=", 6) == 0 )
1929 {
1930 if ((int)strlen(cmd+6) <= 0)
1931 error(eoff,"Label has no name.");
1932
1933 else if ( !validate_label_name(cmd+6) )
1934 error(eoff,"Label \"%s\" contains illegal characters.", cmd+6);
1935
1936 else if ( find_label(cmd+6) != NULL )
1937 error(eoff,"Label \"%s\" already exists", cmd+6);
1938
1939 else
1940 {
1941 if ((int)strlen(cmd+6) > 32)
1942 warn(eoff,"Label name is long.");
1943
1944 if ( (t.flags & TF_DATA) && cmd[6] == '@' )
1945 warn(eoff, "Data topic has a local label.");
1946
1947 lbl.name = dupstr(cmd+6, 0);
1948 lbl.topic_num = num_topic;
1949 lbl.topic_off = (unsigned)(curr - buffer);
1950 lbl.doc_page = -1;
1951 add_label(&lbl);
1952 }
1953 }
1954
1955 else if ( strnicmp(cmd, "Table=", 6) == 0 )
1956 {
1957 if ( in_para )
1958 {
1959 *curr++ = '\n'; /* finish off current paragraph */
1960 in_para = 0;
1961 num_spaces = 0;
1962 state = S_Start;
1963 }
1964
1965 if (!done)
1966 {
1967 if (imbedded)
1968 unread_char('(');
1969 unread_char('~');
1970 done = 1;
1971 }
1972
1973 create_table();
1974 }
1975
1976 else if ( strnicmp(cmd, "FormatExclude", 12) == 0 )
1977 {
1978 if (cmd[13] == '-')
1979 {
1980 check_command_length(eoff,14);
1981 if (lformat_exclude > 0)
1982 lformat_exclude = -lformat_exclude;
1983 else
1984 warn(0,"\"FormatExclude-\" is already in effect.");
1985 }
1986 else if (cmd[13] == '+')
1987 {
1988 check_command_length(eoff,14);
1989 if (lformat_exclude < 0)
1990 lformat_exclude = -lformat_exclude;
1991 else
1992 warn(0,"\"FormatExclude+\" is already in effect.");
1993 }
1994 else
1995 error(eoff,"Unexpected or invalid argument to FormatExclude.");
1996 }
1997
1998 else if ( strnicmp(cmd, "Format", 6) == 0 )
1999 {
2000 if (cmd[6] == '+')
2001 {
2002 check_command_length(eoff,7);
2003 if ( !formatting )
2004 {
2005 formatting = 1;
2006 in_para = 0;
2007 num_spaces = 0;
2008 state = S_Start;
2009 }
2010 else
2011 warn(eoff,"\"Format+\" is already in effect.");
2012 }
2013 else if (cmd[6] == '-')
2014 {
2015 check_command_length(eoff,7);
2016 if ( formatting )
2017 {
2018 if ( in_para )
2019 *curr++ = '\n'; /* finish off current paragraph */
2020 state = S_Start;
2021 in_para = 0;
2022 formatting = 0;
2023 num_spaces = 0;
2024 state = S_Start;
2025 }
2026 else
2027 warn(eoff,"\"Format-\" is already in effect.");
2028 }
2029 else
2030 error(eoff,"Invalid argument to Format.");
2031 }
2032
2033 else if ( strnicmp(cmd, "Online", 6) == 0 )
2034 {
2035 if (cmd[6] == '+')
2036 {
2037 check_command_length(eoff,7);
2038
2039 if ( xonline )
2040 {
2041 *curr++ = CMD_XONLINE;
2042 xonline = 0;
2043 }
2044 else
2045 warn(eoff,"\"Online+\" already in effect.");
2046 }
2047 else if (cmd[6] == '-')
2048 {
2049 check_command_length(eoff,7);
2050 if ( !xonline )
2051 {
2052 *curr++ = CMD_XONLINE;
2053 xonline = 1;
2054 }
2055 else
2056 warn(eoff,"\"Online-\" already in effect.");
2057 }
2058 else
2059 error(eoff,"Invalid argument to Online.");
2060 }
2061
2062 else if ( strnicmp(cmd, "Doc", 3) == 0 )
2063 {
2064 if (cmd[3] == '+')
2065 {
2066 check_command_length(eoff,4);
2067 if ( xdoc )
2068 {
2069 *curr++ = CMD_XDOC;
2070 xdoc = 0;
2071 }
2072 else
2073 warn(eoff,"\"Doc+\" already in effect.");
2074 }
2075 else if (cmd[3] == '-')
2076 {
2077 check_command_length(eoff,4);
2078 if ( !xdoc )
2079 {
2080 *curr++ = CMD_XDOC;
2081 xdoc = 1;
2082 }
2083 else
2084 warn(eoff,"\"Doc-\" already in effect.");
2085 }
2086 else
2087 error(eoff,"Invalid argument to Doc.");
2088 }
2089
2090 else if ( strnicmp(cmd, "Center", 6) == 0 )
2091 {
2092 if (cmd[6] == '+')
2093 {
2094 check_command_length(eoff,7);
2095 if ( !centering )
2096 {
2097 centering = 1;
2098 if ( in_para )
2099 {
2100 *curr++ = '\n';
2101 in_para = 0;
2102 }
2103 state = S_Start; /* for centering FSM */
2104 }
2105 else
2106 warn(eoff,"\"Center+\" already in effect.");
2107 }
2108 else if (cmd[6] == '-')
2109 {
2110 check_command_length(eoff,7);
2111 if ( centering )
2112 {
2113 centering = 0;
2114 state = S_Start; /* for centering FSM */
2115 }
2116 else
2117 warn(eoff,"\"Center-\" already in effect.");
2118 }
2119 else
2120 error(eoff,"Invalid argument to Center.");
2121 }
2122
2123 else if ( strnicmp(cmd, "CompressSpaces", 14) == 0 )
2124 {
2125 check_command_length(eoff,15);
2126
2127 if ( cmd[14] == '+' )
2128 {
2129 if ( compress_spaces )
2130 warn(eoff,"\"CompressSpaces+\" is already in effect.");
2131 else
2132 compress_spaces = 1;
2133 }
2134 else if ( cmd[14] == '-' )
2135 {
2136 if ( !compress_spaces )
2137 warn(eoff,"\"CompressSpaces-\" is already in effect.");
2138 else
2139 compress_spaces = 0;
2140 }
2141 else
2142 error(eoff,"Invalid argument to CompressSpaces.");
2143 }
2144
2145 else if ( strnicmp("BinInc ", cmd, 7) == 0 )
2146 {
2147 if ( !(t.flags & TF_DATA) )
2148 error(eoff,"BinInc allowed only in Data topics.");
2149 else
2150 process_bininc();
2151 }
2152
2153 else
2154 error(eoff,"Bad or unexpected command \"%s\".", cmd);
2155 } /* else */
2156
2157 } /* while (!done) */
2158
2159 continue;
2160 }
2161
2162 if ( !in_topic )
2163 {
2164 cmd[0] = ch;
2165 ptr = read_until(cmd+1, 127, "\n~");
2166 if (*ptr == '~')
2167 unread_char('~');
2168 *ptr = '\0';
2169 error(0,"Text outside of any topic \"%s\".", cmd);
2170 continue;
2171 }
2172
2173 if ( centering )
2174 {
2175 do
2176 {
2177 again = 0; /* default */
2178
2179 switch (state)
2180 {
2181 case S_Start:
2182 if (ch == ' ')
2183 ; /* do nothing */
2184 else if ( (ch&0xFF) == '\n' )
2185 *curr++ = ch; /* no need to center blank lines. */
2186 else
2187 {
2188 *curr++ = CMD_CENTER;
2189 state = S_Line;
2190 again = 1;
2191 }
2192 break;
2193
2194 case S_Line:
2195 put_a_char(ch, &t);
2196 if ( (ch&0xFF) == '\n')
2197 state = S_Start;
2198 break;
2199 } /* switch */
2200 }
2201 while (again);
2202 }
2203
2204 else if ( formatting )
2205 {
2206 int again;
2207
2208 do
2209 {
2210 again = 0; /* default */
2211
2212 switch (state)
2213 {
2214 case S_Start:
2215 if ( (ch&0xFF) == '\n' )
2216 *curr++ = ch;
2217 else
2218 {
2219 state = S_StartFirstLine;
2220 num_spaces = 0;
2221 again = 1;
2222 }
2223 break;
2224
2225 case S_StartFirstLine:
2226 if ( ch == ' ')
2227 ++num_spaces;
2228
2229 else
2230 {
2231 if (lformat_exclude > 0 && num_spaces >= lformat_exclude )
2232 {
2233 put_spaces(num_spaces);
2234 num_spaces = 0;
2235 state = S_FormatDisabled;
2236 again = 1;
2237 }
2238 else
2239 {
2240 *curr++ = CMD_PARA;
2241 *curr++ = (char)num_spaces;
2242 *curr++ = (char)num_spaces;
2243 margin_pos = curr - 1;
2244 state = S_FirstLine;
2245 again = 1;
2246 in_para = 1;
2247 }
2248 }
2249 break;
2250
2251 case S_FirstLine:
2252 if (ch == '\n')
2253 {
2254 state = S_StartSecondLine;
2255 num_spaces = 0;
2256 }
2257 else if (ch == ('\n'|0x100) ) /* force end of para ? */
2258 {
2259 *curr++ = '\n';
2260 in_para = 0;
2261 state = S_Start;
2262 }
2263 else if ( ch == ' ' )
2264 {
2265 state = S_FirstLineSpaces;
2266 num_spaces = 1;
2267 }
2268 else
2269 put_a_char(ch, &t);
2270 break;
2271
2272 case S_FirstLineSpaces:
2273 if (ch == ' ')
2274 ++num_spaces;
2275 else
2276 {
2277 put_spaces(num_spaces);
2278 state = S_FirstLine;
2279 again = 1;
2280 }
2281 break;
2282
2283 case S_StartSecondLine:
2284 if ( ch == ' ')
2285 ++num_spaces;
2286 else if ((ch&0xFF) == '\n') /* a blank line means end of a para */
2287 {
2288 *curr++ = '\n'; /* end the para */
2289 *curr++ = '\n'; /* for the blank line */
2290 in_para = 0;
2291 state = S_Start;
2292 }
2293 else
2294 {
2295 if (lformat_exclude > 0 && num_spaces >= lformat_exclude )
2296 {
2297 *curr++ = '\n';
2298 in_para = 0;
2299 put_spaces(num_spaces);
2300 num_spaces = 0;
2301 state = S_FormatDisabled;
2302 again = 1;
2303 }
2304 else
2305 {
2306 add_blank_for_split();
2307 margin = num_spaces;
2308 *margin_pos = (char)num_spaces;
2309 state = S_Line;
2310 again = 1;
2311 }
2312 }
2313 break;
2314
2315 case S_Line: /* all lines after the first */
2316 if (ch == '\n')
2317 {
2318 state = S_StartLine;
2319 num_spaces = 0;
2320 }
2321 else if (ch == ('\n' | 0x100) ) /* force end of para ? */
2322 {
2323 *curr++ = '\n';
2324 in_para = 0;
2325 state = S_Start;
2326 }
2327 else if ( ch == ' ' )
2328 {
2329 state = S_LineSpaces;
2330 num_spaces = 1;
2331 }
2332 else
2333 put_a_char(ch, &t);
2334 break;
2335
2336 case S_LineSpaces:
2337 if (ch == ' ')
2338 ++num_spaces;
2339 else
2340 {
2341 put_spaces(num_spaces);
2342 state = S_Line;
2343 again = 1;
2344 }
2345 break;
2346
2347 case S_StartLine: /* for all lines after the second */
2348 if ( ch == ' ')
2349 ++num_spaces;
2350 else if ((ch&0xFF) == '\n') /* a blank line means end of a para */
2351 {
2352 *curr++ = '\n'; /* end the para */
2353 *curr++ = '\n'; /* for the blank line */
2354 in_para = 0;
2355 state = S_Start;
2356 }
2357 else
2358 {
2359 if ( num_spaces != margin )
2360 {
2361 *curr++ = '\n';
2362 in_para = 0;
2363 state = S_StartFirstLine; /* with current num_spaces */
2364 again = 1;
2365 }
2366 else
2367 {
2368 add_blank_for_split();
2369 state = S_Line;
2370 again = 1;
2371 }
2372 }
2373 break;
2374
2375 case S_FormatDisabled:
2376 if ( ch == ' ' )
2377 {
2378 state = S_FormatDisabledSpaces;
2379 num_spaces = 1;
2380 }
2381 else
2382 {
2383 if ( (ch&0xFF) == '\n' )
2384 state = S_Start;
2385 put_a_char(ch, &t);
2386 }
2387 break;
2388
2389 case S_FormatDisabledSpaces:
2390 if ( ch == ' ' )
2391 ++num_spaces;
2392 else
2393 {
2394 put_spaces(num_spaces);
2395 num_spaces = 0; /* is this needed? */
2396 state = S_FormatDisabled;
2397 again = 1;
2398 }
2399 break;
2400
2401 } /* switch (state) */
2402 }
2403 while (again);
2404 }
2405
2406 else
2407 {
2408 do
2409 {
2410 again = 0; /* default */
2411
2412 switch (state)
2413 {
2414 case S_Start:
2415 if ( ch == ' ' )
2416 {
2417 state = S_Spaces;
2418 num_spaces = 1;
2419 }
2420 else
2421 put_a_char(ch, &t);
2422 break;
2423
2424 case S_Spaces:
2425 if (ch == ' ')
2426 ++num_spaces;
2427 else
2428 {
2429 put_spaces(num_spaces);
2430 num_spaces = 0; /* is this needed? */
2431 state = S_Start;
2432 again = 1;
2433 }
2434 break;
2435 } /* switch */
2436 }
2437 while (again);
2438 }
2439
2440 CHK_BUFFER(0)
2441 } /* while ( 1 ) */
2442
2443 fclose(srcfile);
2444
2445 srcline = -1;
2446 }
2447
2448
2449 /*
2450 * stuff to resolve hot-link references.
2451 */
2452
2453
make_hot_links(void)2454 void make_hot_links(void)
2455 /*
2456 * calculate topic_num/topic_off for each link.
2457 */
2458 {
2459 LINK *l;
2460 LABEL *lbl;
2461 int lctr;
2462 int t;
2463 CONTENT *c;
2464 int ctr;
2465
2466 msg("Making hot-links.");
2467
2468 /*
2469 * Calculate topic_num for all entries in DocContents. Also set
2470 * "TF_IN_DOC" flag for all topics included in the document.
2471 */
2472
2473 for (lctr=0, c=contents; lctr<num_contents; lctr++, c++)
2474 {
2475 for (ctr=0; ctr<c->num_topic; ctr++)
2476 {
2477 if ( c->is_label[ctr] )
2478 {
2479 lbl = find_label(c->topic_name[ctr]);
2480 if (lbl == NULL)
2481 {
2482 src_cfname = c->srcfile;
2483 srcline = c->srcline;
2484 error(0,"Cannot find DocContent label \"%s\".", c->topic_name[ctr]);
2485 srcline = -1;
2486 }
2487 else
2488 {
2489 if ( topic[lbl->topic_num].flags & TF_DATA )
2490 {
2491 src_cfname = c->srcfile;
2492 srcline = c->srcline;
2493 error(0,"Label \"%s\" is a data-only topic.", c->topic_name[ctr]);
2494 srcline = -1;
2495 }
2496 else
2497 {
2498 c->topic_num[ctr] = lbl->topic_num;
2499 if ( topic[lbl->topic_num].flags & TF_IN_DOC )
2500 warn(0,"Topic \"%s\" appears in document more than once.",
2501 topic[lbl->topic_num].title);
2502 else
2503 topic[lbl->topic_num].flags |= TF_IN_DOC;
2504 }
2505 }
2506
2507 }
2508 else
2509 {
2510 t = find_topic_title(c->topic_name[ctr]);
2511
2512 if (t == -1)
2513 {
2514 src_cfname = c->srcfile;
2515 srcline = c->srcline;
2516 error(0,"Cannot find DocContent topic \"%s\".", c->topic_name[ctr]);
2517 srcline = -1; /* back to reality */
2518 }
2519 else
2520 {
2521 c->topic_num[ctr] = t;
2522 if ( topic[t].flags & TF_IN_DOC )
2523 warn(0,"Topic \"%s\" appears in document more than once.",
2524 topic[t].title);
2525 else
2526 topic[t].flags |= TF_IN_DOC;
2527 }
2528 }
2529 }
2530 }
2531
2532 /*
2533 * Find topic_num and topic_off for all hot-links. Also flag all hot-
2534 * links which will (probably) appear in the document.
2535 */
2536
2537 for (lctr=0, l=a_link; lctr<num_link; l++, lctr++)
2538 {
2539 switch ( l->type )
2540 {
2541 case 0: /* name is the title of the topic */
2542 t = find_topic_title(l->name);
2543 if (t == -1)
2544 {
2545 src_cfname = l->srcfile;
2546 srcline = l->srcline; /* pretend we are still in the source... */
2547 error(0,"Cannot find implicit hot-link \"%s\".", l->name);
2548 srcline = -1; /* back to reality */
2549 }
2550 else
2551 {
2552 l->topic_num = t;
2553 l->topic_off = 0;
2554 l->doc_page = (topic[t].flags & TF_IN_DOC) ? 0 : -1;
2555 }
2556 break;
2557
2558 case 1: /* name is the name of a label */
2559 lbl = find_label(l->name);
2560 if (lbl == NULL)
2561 {
2562 src_cfname = l->srcfile;
2563 srcline = l->srcline; /* pretend again */
2564 error(0,"Cannot find explicit hot-link \"%s\".", l->name);
2565 srcline = -1;
2566 }
2567 else
2568 {
2569 if ( topic[lbl->topic_num].flags & TF_DATA )
2570 {
2571 src_cfname = l->srcfile;
2572 srcline = l->srcline;
2573 error(0,"Label \"%s\" is a data-only topic.", l->name);
2574 srcline = -1;
2575 }
2576 else
2577 {
2578 l->topic_num = lbl->topic_num;
2579 l->topic_off = lbl->topic_off;
2580 l->doc_page = (topic[lbl->topic_num].flags & TF_IN_DOC) ? 0 : -1;
2581 }
2582 }
2583 break;
2584
2585 case 2: /* it's a "special" link; topic_off already has the value */
2586 break;
2587 }
2588 }
2589
2590 }
2591
2592
2593 /*
2594 * online help pagination stuff
2595 */
2596
2597
add_page_break(TOPIC * t,int margin,char * text,char * start,char * curr,int num_links)2598 void add_page_break(TOPIC *t, int margin, char *text, char *start, char *curr, int num_links)
2599 {
2600 PAGE p;
2601
2602 p.offset = (unsigned) (start - text);
2603 p.length = (unsigned) (curr - start);
2604 p.margin = margin;
2605 add_page(t, &p);
2606
2607 if (max_links < num_links)
2608 max_links = num_links;
2609 }
2610
2611
paginate_online(void)2612 void paginate_online(void) /* paginate the text for on-line help */
2613 { /* also calculates max_pages and max_links */
2614 int lnum;
2615 char *start;
2616 char *curr;
2617 char *text;
2618 TOPIC *t;
2619 int tctr;
2620 unsigned len;
2621 int skip_blanks;
2622 int num_links;
2623 int col;
2624 int tok;
2625 int size,
2626 width;
2627 int start_margin;
2628
2629 msg("Paginating online help.");
2630
2631 for (t=topic, tctr=0; tctr<num_topic; t++, tctr++)
2632 {
2633 if ( t->flags & TF_DATA )
2634 continue; /* don't paginate data topics */
2635
2636 text = get_topic_text(t);
2637 curr = text;
2638 len = t->text_len;
2639
2640 start = curr;
2641 skip_blanks = 0;
2642 lnum = 0;
2643 num_links = 0;
2644 col = 0;
2645 start_margin = -1;
2646
2647 while (len > 0)
2648 {
2649 tok = find_token_length(ONLINE, curr, len, &size, &width);
2650
2651 switch ( tok )
2652 {
2653 case TOK_PARA:
2654 {
2655 int indent,
2656 margin;
2657
2658 ++curr;
2659
2660 indent = *curr++;
2661 margin = *curr++;
2662
2663 len -= 3;
2664
2665 col = indent;
2666
2667 while (1)
2668 {
2669 tok = find_token_length(ONLINE, curr, len, &size, &width);
2670
2671 if (tok == TOK_DONE || tok == TOK_NL || tok == TOK_FF )
2672 break;
2673
2674 if ( tok == TOK_PARA )
2675 {
2676 col = 0; /* fake a nl */
2677 ++lnum;
2678 break;
2679 }
2680
2681 if (tok == TOK_XONLINE || tok == TOK_XDOC )
2682 {
2683 curr += size;
2684 len -= size;
2685 continue;
2686 }
2687
2688 /* now tok is TOK_SPACE or TOK_LINK or TOK_WORD */
2689
2690 if (col+width > SCREEN_WIDTH)
2691 { /* go to next line... */
2692 if ( ++lnum >= SCREEN_DEPTH )
2693 { /* go to next page... */
2694 add_page_break(t, start_margin, text, start, curr, num_links);
2695 start = curr + ( (tok == TOK_SPACE) ? size : 0 );
2696 start_margin = margin;
2697 lnum = 0;
2698 num_links = 0;
2699 }
2700 if ( tok == TOK_SPACE )
2701 width = 0; /* skip spaces at start of a line */
2702
2703 col = margin;
2704 }
2705
2706 col += width;
2707 curr += size;
2708 len -= size;
2709 }
2710
2711 skip_blanks = 0;
2712 width = size = 0;
2713 break;
2714 }
2715
2716 case TOK_NL:
2717 if (skip_blanks && col == 0)
2718 {
2719 start += size;
2720 break;
2721 }
2722 ++lnum;
2723 if ( lnum >= SCREEN_DEPTH || (col == 0 && lnum==SCREEN_DEPTH-1) )
2724 {
2725 add_page_break(t, start_margin, text, start, curr, num_links);
2726 start = curr + size;
2727 start_margin = -1;
2728 lnum = 0;
2729 num_links = 0;
2730 skip_blanks = 1;
2731 }
2732 col = 0;
2733 break;
2734
2735 case TOK_FF:
2736 col = 0;
2737 if (skip_blanks)
2738 {
2739 start += size;
2740 break;
2741 }
2742 add_page_break(t, start_margin, text, start, curr, num_links);
2743 start_margin = -1;
2744 start = curr + size;
2745 lnum = 0;
2746 num_links = 0;
2747 break;
2748
2749 case TOK_DONE:
2750 case TOK_XONLINE: /* skip */
2751 case TOK_XDOC: /* ignore */
2752 case TOK_CENTER: /* ignore */
2753 break;
2754
2755 case TOK_LINK:
2756 ++num_links;
2757
2758 /* fall-through */
2759
2760 default: /* TOK_SPACE, TOK_LINK, TOK_WORD */
2761 skip_blanks = 0;
2762 break;
2763
2764 } /* switch */
2765
2766 curr += size;
2767 len -= size;
2768 col += width;
2769 } /* while */
2770
2771 if (!skip_blanks)
2772 add_page_break(t, start_margin, text, start, curr, num_links);
2773
2774 if (max_pages < t->num_page)
2775 max_pages = t->num_page;
2776
2777 release_topic_text(t, 0);
2778 } /* for */
2779 }
2780
2781
2782 /*
2783 * paginate document stuff
2784 */
2785
2786
2787 #define CNUM 0
2788 #define TNUM 1
2789 #define LINK_DEST_WARN 2
2790
2791
2792 typedef struct
2793 {
2794 int cnum, /* must match above #defines so pd_get_info() will work */
2795 tnum,
2796 link_dest_warn;
2797
2798 char far *start;
2799 CONTENT *c;
2800 LABEL *lbl;
2801
2802 } PAGINATE_DOC_INFO;
2803
2804
find_next_label_by_topic(int t)2805 LABEL *find_next_label_by_topic(int t)
2806 {
2807 LABEL *temp, *g, *p;
2808 int ctr;
2809
2810 g = p = NULL;
2811
2812 for (temp=label, ctr=0; ctr<num_label; ctr++, temp++)
2813 if ( temp->topic_num == t && temp->doc_page == -1 )
2814 {
2815 g = temp;
2816 break;
2817 }
2818 else if (temp->topic_num > t)
2819 break;
2820
2821 for (temp=plabel, ctr=0; ctr<num_plabel; ctr++, temp++)
2822 if ( temp->topic_num == t && temp->doc_page == -1 )
2823 {
2824 p = temp;
2825 break;
2826 }
2827 else if (temp->topic_num > t)
2828 break;
2829
2830 if ( p == NULL )
2831 return (g);
2832
2833 else if ( g == NULL )
2834 return (p);
2835
2836 else
2837 return ( (g->topic_off < p->topic_off) ? g : p );
2838 }
2839
2840
set_hot_link_doc_page(void)2841 void set_hot_link_doc_page(void)
2842 /*
2843 * Find doc_page for all hot-links.
2844 */
2845 {
2846 LINK *l;
2847 LABEL *lbl;
2848 int lctr;
2849 int t;
2850
2851 for (lctr=0, l=a_link; lctr<num_link; l++, lctr++)
2852 {
2853 switch ( l->type )
2854 {
2855 case 0: /* name is the title of the topic */
2856 t = find_topic_title(l->name);
2857 if (t == -1)
2858 {
2859 src_cfname = l->srcfile;
2860 srcline = l->srcline; /* pretend we are still in the source... */
2861 error(0,"Cannot find implicit hot-link \"%s\".", l->name);
2862 srcline = -1; /* back to reality */
2863 }
2864 else
2865 l->doc_page = topic[t].doc_page;
2866 break;
2867
2868 case 1: /* name is the name of a label */
2869 lbl = find_label(l->name);
2870 if (lbl == NULL)
2871 {
2872 src_cfname = l->srcfile;
2873 srcline = l->srcline; /* pretend again */
2874 error(0,"Cannot find explicit hot-link \"%s\".", l->name);
2875 srcline = -1;
2876 }
2877 else
2878 l->doc_page = lbl->doc_page;
2879 break;
2880
2881 case 2: /* special topics don't appear in the document */
2882 break;
2883 }
2884 }
2885 }
2886
2887
set_content_doc_page(void)2888 void set_content_doc_page(void)
2889 /*
2890 * insert page #'s in the DocContents
2891 */
2892 {
2893 CONTENT *c;
2894 TOPIC *t;
2895 char *base;
2896 int tnum;
2897 int ctr;
2898 char buf[4];
2899 int len;
2900
2901 tnum = find_topic_title(DOCCONTENTS_TITLE);
2902 assert(tnum>=0);
2903 t = &topic[tnum];
2904
2905 base = get_topic_text(t);
2906
2907 for (ctr=1, c=contents+1; ctr<num_contents; ctr++, c++)
2908 {
2909 assert(c->doc_page>=1);
2910 sprintf(buf, "%d", c->doc_page);
2911 len = strlen(buf);
2912 assert(len<=3);
2913 memcpy(base+c->page_num_pos+(3-len), buf, len);
2914 }
2915
2916 release_topic_text(t, 1);
2917 }
2918
2919
pd_get_info(int cmd,PD_INFO * pd,int * info)2920 int pd_get_info(int cmd, PD_INFO *pd, int *info)
2921 { /* this funtion also used by print_document() */
2922 CONTENT *c;
2923
2924 switch (cmd)
2925 {
2926 case PD_GET_CONTENT:
2927 if ( ++info[CNUM] >= num_contents )
2928 return (0);
2929 c = &contents[info[CNUM]];
2930 info[TNUM] = -1;
2931 pd->id = c->id;
2932 pd->title = c->name;
2933 pd->new_page = (c->flags & CF_NEW_PAGE) ? 1 : 0;
2934 return (1);
2935
2936 case PD_GET_TOPIC:
2937 c = &contents[info[CNUM]];
2938 if ( ++info[TNUM] >= c->num_topic )
2939 return (0);
2940 pd->curr = get_topic_text( &topic[c->topic_num[info[TNUM]]] );
2941 pd->len = topic[c->topic_num[info[TNUM]]].text_len;
2942 return (1);
2943
2944 case PD_GET_LINK_PAGE:
2945 if ( a_link[getint(pd->s)].doc_page == -1 )
2946 {
2947 if ( info[LINK_DEST_WARN] )
2948 {
2949 src_cfname = a_link[getint(pd->s)].srcfile;
2950 srcline = a_link[getint(pd->s)].srcline;
2951 warn(0,"Hot-link destination is not in the document.");
2952 srcline = -1;
2953 }
2954 return (0);
2955 }
2956 pd->i = a_link[getint(pd->s)].doc_page;
2957 return (1);
2958
2959 case PD_RELEASE_TOPIC:
2960 c = &contents[info[CNUM]];
2961 release_topic_text(&topic[c->topic_num[info[TNUM]]], 0);
2962 return (1);
2963
2964 default:
2965 return (0);
2966 }
2967 }
2968
2969
paginate_doc_output(int cmd,PD_INFO * pd,PAGINATE_DOC_INFO * info)2970 int paginate_doc_output(int cmd, PD_INFO *pd, PAGINATE_DOC_INFO *info)
2971 {
2972 switch (cmd)
2973 {
2974 case PD_FOOTING:
2975 case PD_PRINT:
2976 case PD_PRINTN:
2977 case PD_PRINT_SEC:
2978 return (1);
2979
2980 case PD_HEADING:
2981 ++num_doc_pages;
2982 return (1);
2983
2984 case PD_START_SECTION:
2985 info->c = &contents[info->cnum];
2986 return (1);
2987
2988 case PD_START_TOPIC:
2989 info->start = pd->curr;
2990 info->lbl = find_next_label_by_topic(info->c->topic_num[info->tnum]);
2991 return (1);
2992
2993 case PD_SET_SECTION_PAGE:
2994 info->c->doc_page = pd->pnum;
2995 return (1);
2996
2997 case PD_SET_TOPIC_PAGE:
2998 topic[info->c->topic_num[info->tnum]].doc_page = pd->pnum;
2999 return (1);
3000
3001 case PD_PERIODIC:
3002 while ( info->lbl != NULL && (unsigned)(pd->curr - info->start) >= info->lbl->topic_off)
3003 {
3004 info->lbl->doc_page = pd->pnum;
3005 info->lbl = find_next_label_by_topic(info->c->topic_num[info->tnum]);
3006 }
3007 return (1);
3008
3009 default:
3010 return (0);
3011 }
3012 }
3013
3014
paginate_document(void)3015 void paginate_document(void)
3016 {
3017 PAGINATE_DOC_INFO info;
3018
3019 if (num_contents == 0)
3020 return ;
3021
3022 msg("Paginating document.");
3023
3024 info.cnum = info.tnum = -1;
3025 info.link_dest_warn = 1;
3026
3027 process_document((PD_FUNC)pd_get_info, (PD_FUNC)paginate_doc_output, &info);
3028
3029 set_hot_link_doc_page();
3030 set_content_doc_page();
3031 }
3032
3033
3034 /*
3035 * label sorting stuff
3036 */
3037
fcmp_LABEL(VOIDCONSTPTR a,VOIDCONSTPTR b)3038 int fcmp_LABEL(VOIDCONSTPTR a, VOIDCONSTPTR b)
3039 {
3040 char *an = ((LABEL *)a)->name,
3041 *bn = ((LABEL *)b)->name;
3042 int diff;
3043
3044 /* compare the names, making sure that the index goes first */
3045
3046 if ( (diff=strcmp(an,bn)) == 0 )
3047 return (0);
3048
3049 if ( strcmp(an, INDEX_LABEL) == 0 )
3050 return (-1);
3051
3052 if ( strcmp(bn, INDEX_LABEL) == 0 )
3053 return (1);
3054
3055 return ( diff );
3056 }
3057
3058
sort_labels(void)3059 void sort_labels(void)
3060 {
3061 qsort(label, num_label, sizeof(LABEL), fcmp_LABEL);
3062 qsort(plabel, num_plabel, sizeof(LABEL), fcmp_LABEL);
3063 }
3064
3065
3066 /*
3067 * file write stuff.
3068 */
3069
3070
compare_files(FILE * f1,FILE * f2)3071 int compare_files(FILE *f1, FILE *f2) /* returns TRUE if different */
3072 {
3073 if ( filelength(fileno(f1)) != filelength(fileno(f2)) )
3074 return (1); /* different if sizes are not the same */
3075
3076 while ( !feof(f1) && !feof(f2) )
3077 if ( getc(f1) != getc(f2) )
3078 return (1);
3079
3080 return ( ( feof(f1) && feof(f2) ) ? 0 : 1);
3081 }
3082
3083
_write_hdr(char * fname,FILE * file)3084 void _write_hdr(char *fname, FILE *file)
3085 {
3086 int ctr;
3087 char nfile[MAXFILE],
3088 next[MAXEXT];
3089
3090 FNSPLIT(fname, NULL, NULL, nfile, next);
3091 fprintf(file, "\n/*\n * %s%s\n", nfile, next);
3092 FNSPLIT(src_fname, NULL, NULL, nfile, next);
3093 fprintf(file, " *\n * Contains #defines for help.\n *\n");
3094 fprintf(file, " * Generated by HC from: %s%s\n *\n */\n\n\n", nfile, next);
3095
3096 fprintf(file, "/* current help file version */\n");
3097 fprintf(file, "\n");
3098 fprintf(file, "#define %-32s %3d\n", "HELP_VERSION", version);
3099 fprintf(file, "\n\n");
3100
3101 fprintf(file, "/* labels */\n\n");
3102
3103 for (ctr=0; ctr<num_label; ctr++)
3104 if (label[ctr].name[0] != '@') /* if it's not a local label... */
3105 {
3106 fprintf(file, "#define %-32s %3d", label[ctr].name, ctr);
3107 if ( strcmp(label[ctr].name, INDEX_LABEL) == 0 )
3108 fprintf(file, " /* index */");
3109 fprintf(file, "\n");
3110 }
3111
3112 fprintf(file, "\n\n");
3113 }
3114
3115
write_hdr(char * fname)3116 void write_hdr(char *fname)
3117 {
3118 FILE *temp,
3119 *hdr;
3120
3121 hdr = fopen(fname, "rt");
3122
3123 if (hdr == NULL)
3124 { /* if no prev. hdr file generate a new one */
3125 hdr = fopen(fname, "wt");
3126 if (hdr == NULL)
3127 fatal(0,"Cannot create \"%s\".", fname);
3128 msg("Writing: %s", fname);
3129 _write_hdr(fname, hdr);
3130 fclose(hdr);
3131 notice("FRACTINT must be re-compiled.");
3132 return ;
3133 }
3134
3135 msg("Comparing: %s", fname);
3136
3137 temp = fopen(TEMP_FNAME, "wt");
3138
3139 if (temp == NULL)
3140 fatal(0,"Cannot create temporary file: \"%s\".", TEMP_FNAME);
3141
3142 _write_hdr(fname, temp);
3143
3144 fclose(temp);
3145 temp = fopen(TEMP_FNAME, "rt");
3146
3147 if (temp == NULL)
3148 fatal(0,"Cannot open temporary file: \"%s\".", TEMP_FNAME);
3149
3150 if ( compare_files(temp, hdr) ) /* if they are different... */
3151 {
3152 msg("Updating: %s", fname);
3153 fclose(temp);
3154 fclose(hdr);
3155 unlink(fname); /* delete the old hdr file */
3156 rename(TEMP_FNAME, fname); /* rename the temp to the hdr file */
3157 notice("FRACTINT must be re-compiled.");
3158 }
3159 else
3160 { /* if they are the same leave the original alone. */
3161 fclose(temp);
3162 fclose(hdr);
3163 unlink(TEMP_FNAME); /* delete the temp */
3164 }
3165 }
3166
3167
calc_offsets(void)3168 void calc_offsets(void) /* calc file offset to each topic */
3169 {
3170 int t;
3171 TOPIC *tp;
3172 long offset;
3173 CONTENT *cp;
3174 int c;
3175
3176 /* NOTE: offsets do NOT include 6 bytes for signature & version! */
3177
3178 offset = sizeof(int) + /* max_pages */
3179 sizeof(int) + /* max_links */
3180 sizeof(int) + /* num_topic */
3181 sizeof(int) + /* num_label */
3182 sizeof(int) + /* num_contents */
3183 sizeof(int) + /* num_doc_pages */
3184 num_topic*sizeof(long) +/* offsets to each topic */
3185 num_label*2*sizeof(int);/* topic_num/topic_off for all public labels */
3186
3187 for (c=0, cp=contents; c<num_contents; c++, cp++)
3188 offset += sizeof(int) + /* flags */
3189 1 + /* id length */
3190 strlen(cp->id) + /* id text */
3191 1 + /* name length */
3192 strlen(cp->name) + /* name text */
3193 1 + /* number of topics */
3194 cp->num_topic*sizeof(int); /* topic numbers */
3195
3196 for (t=0, tp=topic; t<num_topic; t++, tp++)
3197 {
3198 tp->offset = offset;
3199 offset += (long)sizeof(int) + /* topic flags */
3200 sizeof(int) + /* number of pages */
3201 tp->num_page*3*sizeof(int) + /* page offset, length & starting margin */
3202 1 + /* length of title */
3203 tp->title_len + /* title */
3204 sizeof(int) + /* length of text */
3205 tp->text_len; /* text */
3206 }
3207
3208 }
3209
3210
insert_real_link_info(char * curr,unsigned len)3211 void insert_real_link_info(char *curr, unsigned len)
3212 /*
3213 * Replaces link indexes in the help text with topic_num, topic_off and
3214 * doc_page info.
3215 */
3216 {
3217 int size;
3218 int tok;
3219 LINK *l;
3220
3221 while (len > 0)
3222 {
3223 tok = find_token_length(0, curr, len, &size, NULL);
3224
3225 if ( tok == TOK_LINK )
3226 {
3227 l = &a_link[ getint(curr+1) ];
3228 setint(curr+1,l->topic_num);
3229 setint(curr+1+sizeof(int),l->topic_off);
3230 setint(curr+1+2*sizeof(int),l->doc_page);
3231 }
3232
3233 len -= size;
3234 curr += size;
3235 }
3236 }
3237
3238
_write_help(FILE * file)3239 void _write_help(FILE *file)
3240 {
3241 int t, p, l, c;
3242 char *text;
3243 TOPIC *tp;
3244 CONTENT *cp;
3245 struct help_sig_info hs;
3246
3247 /* write the signature and version */
3248
3249 hs.sig = HELP_SIG; /* Edit line 17 of helpcom.h if this is a syntax error */
3250 hs.version = version;
3251
3252 fwrite(&hs, sizeof(long)+sizeof(int), 1, file);
3253
3254 /* write max_pages & max_links */
3255
3256 putw(max_pages, file);
3257 putw(max_links, file);
3258
3259 /* write num_topic, num_label and num_contents */
3260
3261 putw(num_topic, file);
3262 putw(num_label, file);
3263 putw(num_contents, file);
3264
3265 /* write num_doc_page */
3266
3267 putw(num_doc_pages, file);
3268
3269 /* write the offsets to each topic */
3270
3271 for (t=0; t<num_topic; t++)
3272 fwrite(&topic[t].offset, sizeof(long), 1, file);
3273
3274 /* write all public labels */
3275
3276 for (l=0; l<num_label; l++)
3277 {
3278 putw(label[l].topic_num, file);
3279 putw(label[l].topic_off, file);
3280 }
3281
3282 /* write contents */
3283
3284 for (c=0, cp=contents; c<num_contents; c++, cp++)
3285 {
3286 putw(cp->flags, file);
3287
3288 t = strlen(cp->id);
3289 putc((BYTE)t, file);
3290 fwrite(cp->id, 1, t, file);
3291
3292 t = strlen(cp->name);
3293 putc((BYTE)t, file);
3294 fwrite(cp->name, 1, t, file);
3295
3296 putc((BYTE)cp->num_topic, file);
3297 fwrite(cp->topic_num, sizeof(int), cp->num_topic, file);
3298 }
3299
3300 /* write topics */
3301
3302 for (t=0, tp=topic; t<num_topic; t++, tp++)
3303 {
3304 /* write the topics flags */
3305
3306 putw(tp->flags, file);
3307
3308 /* write offset, length and starting margin for each page */
3309
3310 putw(tp->num_page, file);
3311 for (p=0; p<tp->num_page; p++)
3312 {
3313 putw(tp->page[p].offset, file);
3314 putw(tp->page[p].length, file);
3315 putw(tp->page[p].margin, file);
3316 }
3317
3318 /* write the help title */
3319
3320 putc((BYTE)tp->title_len, file);
3321 fwrite(tp->title, 1, tp->title_len, file);
3322
3323 /* insert hot-link info & write the help text */
3324
3325 text = get_topic_text(tp);
3326
3327 if ( !(tp->flags & TF_DATA) ) /* don't process data topics... */
3328 insert_real_link_info(text, tp->text_len);
3329
3330 putw(tp->text_len, file);
3331 fwrite(text, 1, tp->text_len, file);
3332
3333 release_topic_text(tp, 0); /* don't save the text even though */
3334 /* insert_real_link_info() modified it */
3335 /* because we don't access the info after */
3336 /* this. */
3337
3338 }
3339 }
3340
3341
write_help(char * fname)3342 void write_help(char *fname)
3343 {
3344 FILE *hlp;
3345
3346 hlp = fopen(fname, "wb");
3347
3348 if (hlp == NULL)
3349 fatal(0,"Cannot create .HLP file: \"%s\".", fname);
3350
3351 msg("Writing: %s", fname);
3352
3353 _write_help(hlp);
3354
3355 fclose(hlp);
3356 }
3357
3358
3359 /*
3360 * print document stuff.
3361 */
3362
3363
3364 typedef struct
3365 {
3366
3367 /*
3368 * Note: Don't move these first three or pd_get_info will work not
3369 * correctly.
3370 */
3371
3372 int cnum;
3373 int tnum;
3374 int link_dest_warn; /* = 0 */
3375
3376 FILE *file;
3377 int margin;
3378 int start_of_line;
3379 int spaces;
3380 } PRINT_DOC_INFO;
3381
3382
printerc(PRINT_DOC_INFO * info,int c,int n)3383 void printerc(PRINT_DOC_INFO *info, int c, int n)
3384 {
3385 while ( n-- > 0 )
3386 {
3387 if (c==' ')
3388 ++info->spaces;
3389
3390 else if (c=='\n' || c=='\f')
3391 {
3392 info->start_of_line = 1;
3393 info->spaces = 0; /* strip spaces before a new-line */
3394 putc(c, info->file);
3395 }
3396
3397 else
3398 {
3399 if (info->start_of_line)
3400 {
3401 info->spaces += info->margin;
3402 info->start_of_line = 0;
3403 }
3404
3405 while (info->spaces > 0)
3406 {
3407 fputc(' ', info->file);
3408 --info->spaces;
3409 }
3410
3411 fputc(c, info->file);
3412 }
3413 }
3414 }
3415
3416
printers(PRINT_DOC_INFO * info,char far * s,int n)3417 void printers(PRINT_DOC_INFO *info, char far *s, int n)
3418 {
3419 if (n > 0)
3420 {
3421 while ( n-- > 0 )
3422 printerc(info, *s++, 1);
3423 }
3424 else
3425 {
3426 while ( *s != '\0' )
3427 printerc(info, *s++, 1);
3428 }
3429 }
3430
3431
print_doc_output(int cmd,PD_INFO * pd,PRINT_DOC_INFO * info)3432 int print_doc_output(int cmd, PD_INFO *pd, PRINT_DOC_INFO *info)
3433 {
3434 switch (cmd)
3435 {
3436 case PD_HEADING:
3437 {
3438 char buff[20];
3439
3440 info->margin = 0;
3441 printers(info, "\n Fractint Version xx.xx Page ", 0);
3442 sprintf(buff, "%d\n\n", pd->pnum);
3443 printers(info, buff, 0);
3444 info->margin = PAGE_INDENT;
3445 return (1);
3446 }
3447
3448 case PD_FOOTING:
3449 info->margin = 0;
3450 printerc(info, '\f', 1);
3451 info->margin = PAGE_INDENT;
3452 return (1);
3453
3454 case PD_PRINT:
3455 printers(info, pd->s, pd->i);
3456 return (1);
3457
3458 case PD_PRINTN:
3459 printerc(info, *pd->s, pd->i);
3460 return (1);
3461
3462 case PD_PRINT_SEC:
3463 info->margin = TITLE_INDENT;
3464 if (pd->id[0] != '\0')
3465 {
3466 printers(info, pd->id, 0);
3467 printerc(info, ' ', 1);
3468 }
3469 printers(info, pd->title, 0);
3470 printerc(info, '\n', 1);
3471 info->margin = PAGE_INDENT;
3472 return (1);
3473
3474 case PD_START_SECTION:
3475 case PD_START_TOPIC:
3476 case PD_SET_SECTION_PAGE:
3477 case PD_SET_TOPIC_PAGE:
3478 case PD_PERIODIC:
3479 return (1);
3480
3481 default:
3482 return (0);
3483 }
3484 }
3485
3486
print_document(char * fname)3487 void print_document(char *fname)
3488 {
3489 PRINT_DOC_INFO info;
3490
3491 if (num_contents == 0)
3492 fatal(0,".SRC has no DocContents.");
3493
3494 msg("Printing to: %s", fname);
3495
3496 info.cnum = info.tnum = -1;
3497 info.link_dest_warn = 0;
3498
3499 if ( (info.file = fopen(fname, "wt")) == NULL )
3500 fatal(0,"Couldn't create \"%s\"", fname);
3501
3502 info.margin = PAGE_INDENT;
3503 info.start_of_line = 1;
3504 info.spaces = 0;
3505
3506 process_document((PD_FUNC)pd_get_info, (PD_FUNC)print_doc_output, &info);
3507
3508 fclose(info.file);
3509 }
3510
3511
3512 /*
3513 * compiler status and memory usage report stuff.
3514 */
3515
3516
report_memory(void)3517 void report_memory(void)
3518 {
3519 long string = 0, /* bytes in strings */
3520 text = 0, /* bytes in topic text (stored on disk) */
3521 data = 0, /* bytes in active data structure */
3522 dead = 0; /* bytes in unused data structure */
3523 int ctr, ctr2;
3524
3525 for (ctr=0; ctr<num_topic; ctr++)
3526 {
3527 data += sizeof(TOPIC);
3528 string += topic[ctr].title_len;
3529 text += topic[ctr].text_len;
3530 data += topic[ctr].num_page * sizeof(PAGE);
3531
3532 dead += (PAGE_ALLOC_SIZE-(topic[ctr].num_page%PAGE_ALLOC_SIZE)) * sizeof(PAGE);
3533 }
3534
3535 for (ctr=0; ctr<num_link; ctr++)
3536 {
3537 data += sizeof(LINK);
3538 string += strlen(a_link[ctr].name);
3539 }
3540
3541 if (num_link > 0)
3542 dead += (LINK_ALLOC_SIZE-(num_link%LINK_ALLOC_SIZE)) * sizeof(LINK);
3543
3544 for (ctr=0; ctr<num_label; ctr++)
3545 {
3546 data += sizeof(LABEL);
3547 string += strlen(label[ctr].name) + 1;
3548 }
3549
3550 if (num_label > 0)
3551 dead += (LABEL_ALLOC_SIZE-(num_label%LABEL_ALLOC_SIZE)) * sizeof(LABEL);
3552
3553 for (ctr=0; ctr<num_plabel; ctr++)
3554 {
3555 data += sizeof(LABEL);
3556 string += strlen(plabel[ctr].name) + 1;
3557 }
3558
3559 if (num_plabel > 0)
3560 dead += (LABEL_ALLOC_SIZE-(num_plabel%LABEL_ALLOC_SIZE)) * sizeof(LABEL);
3561
3562 for (ctr=0; ctr<num_contents; ctr++)
3563 {
3564 int t;
3565
3566 t = ( MAX_CONTENT_TOPIC - contents[ctr].num_topic ) *
3567 ( sizeof(contents[0].is_label[0]) +
3568 sizeof(contents[0].topic_name[0]) +
3569 sizeof(contents[0].topic_num[0]) );
3570 data += sizeof(CONTENT) - t;
3571 dead += t;
3572 string += strlen(contents[ctr].id) + 1;
3573 string += strlen(contents[ctr].name) + 1;
3574 for (ctr2=0; ctr2<contents[ctr].num_topic; ctr2++)
3575 string += strlen(contents[ctr].topic_name[ctr2]) + 1;
3576 }
3577
3578 dead += (CONTENTS_ALLOC_SIZE-(num_contents%CONTENTS_ALLOC_SIZE)) * sizeof(CONTENT);
3579
3580 printf("\n");
3581 printf("Memory Usage:\n");
3582 printf("%8ld Bytes in buffers.\n", (long)BUFFER_SIZE);
3583 printf("%8ld Bytes in strings.\n", string);
3584 printf("%8ld Bytes in data.\n", data);
3585 printf("%8ld Bytes in dead space.\n", dead);
3586 printf("--------\n");
3587 printf("%8ld Bytes total.\n", (long)BUFFER_SIZE+string+data+dead);
3588 printf("\n");
3589 printf("Disk Usage:\n");
3590 printf("%8ld Bytes in topic text.\n", text);
3591 }
3592
3593
report_stats(void)3594 void report_stats(void)
3595 {
3596 int pages = 0;
3597 int t;
3598
3599 for (t=0; t<num_topic; t++)
3600 pages += topic[t].num_page;
3601
3602 printf("\n");
3603 printf("Statistics:\n");
3604 printf("%8d Topics\n", num_topic);
3605 printf("%8d Links\n", num_link);
3606 printf("%8d Labels\n", num_label);
3607 printf("%8d Private labels\n", num_plabel);
3608 printf("%8d Table of contents (DocContent) entries\n", num_contents);
3609 printf("%8d Online help pages\n", pages);
3610 printf("%8d Document pages\n", num_doc_pages);
3611 }
3612
3613
3614 /*
3615 * add/delete help from .EXE functions.
3616 */
3617
3618
add_hlp_to_exe(char * hlp_fname,char * exe_fname)3619 void add_hlp_to_exe(char *hlp_fname, char *exe_fname)
3620 {
3621 int exe, /* handles */
3622 hlp;
3623 long len,
3624 count;
3625 int size;
3626 struct help_sig_info hs;
3627
3628 if ( (exe=open(exe_fname, O_RDWR|O_BINARY)) == -1 )
3629 fatal(0,"Unable to open \"%s\"", exe_fname);
3630
3631 if ( (hlp=open(hlp_fname, O_RDONLY|O_BINARY)) == -1 )
3632 fatal(0,"Unable to open \"%s\"", hlp_fname);
3633
3634 msg("Appending %s to %s", hlp_fname, exe_fname);
3635
3636 /* first, check and see if any help is currently installed */
3637
3638 lseek(exe, filelength(exe) - sizeof(struct help_sig_info), SEEK_SET);
3639
3640 read(exe, (char *)&hs, 10);
3641
3642 if ( hs.sig == HELP_SIG )
3643 warn(0,"Overwriting previous help. (Version=%d)", hs.version);
3644 else
3645 hs.base = filelength(exe);
3646
3647 /* now, let's see if their help file is for real (and get the version) */
3648
3649 read(hlp, (char *)&hs, sizeof(long)+sizeof(int));
3650
3651 if (hs.sig != HELP_SIG )
3652 fatal(0,"Help signature not found in %s", hlp_fname);
3653
3654 msg("Help file %s Version=%d", hlp_fname, hs.version);
3655
3656 /* append the help stuff, overwriting old help (if any) */
3657
3658 lseek(exe, hs.base, SEEK_SET);
3659
3660 len = filelength(hlp) - sizeof(long) - sizeof(int); /* adjust for the file signature & version */
3661
3662 for (count=0; count<len; )
3663 {
3664 size = (int) min((long)BUFFER_SIZE, len-count);
3665 read(hlp, buffer, size);
3666 write(exe, buffer, size);
3667 count += size;
3668 }
3669
3670 /* add on the signature, version and offset */
3671
3672 write(exe, (char *)&hs, 10);
3673
3674 chsize(exe, lseek(exe,0L,SEEK_CUR));/* truncate if old help was longer */
3675
3676 close(exe);
3677 close(hlp);
3678 }
3679
3680
delete_hlp_from_exe(char * exe_fname)3681 void delete_hlp_from_exe(char *exe_fname)
3682 {
3683 int exe; /* file handle */
3684 struct help_sig_info hs;
3685
3686 if ( (exe=open(exe_fname, O_RDWR|O_BINARY)) == -1 )
3687 fatal(0,"Unable to open \"%s\"", exe_fname);
3688
3689 msg("Deleting help from %s", exe_fname);
3690
3691 /* see if any help is currently installed */
3692
3693 #ifndef XFRACT
3694 lseek(exe, filelength(exe) - 10, SEEK_SET);
3695 read(exe, (char *)&hs, 10);
3696 #else
3697 lseek(exe, filelength(exe) - 12, SEEK_SET);
3698 read(exe, (char *)&hs, 12);
3699 #endif
3700
3701 if ( hs.sig == HELP_SIG )
3702 {
3703 chsize(exe, hs.base); /* truncate at the start of the help */
3704 close(exe);
3705 }
3706 else
3707 {
3708 close(exe);
3709 fatal(0,"No help found in %s", exe_fname);
3710 }
3711 }
3712
3713
3714 /*
3715 * command-line parser, etc.
3716 */
3717
3718
3719 #define MODE_COMPILE 1
3720 #define MODE_PRINT 2
3721 #define MODE_APPEND 3
3722 #define MODE_DELETE 4
3723
3724
main(int argc,char * argv[])3725 int main(int argc, char *argv[])
3726 {
3727 int show_stats = 0,
3728 show_mem = 0;
3729 int mode = 0;
3730
3731 char **arg;
3732 char fname1[81],
3733 fname2[81];
3734 char swappath[81];
3735
3736 fname1[0] = fname2[0] = swappath[0] = 0;
3737
3738 printf("HC - FRACTINT Help Compiler.\n\n");
3739
3740 buffer = malloc(BUFFER_SIZE);
3741
3742 if (buffer == NULL)
3743 fatal(0,"Not enough memory to allocate buffer.");
3744
3745 for (arg= &argv[1]; argc>1; argc--, arg++)
3746 {
3747 switch ( (*arg)[0] )
3748 {
3749 case '/':
3750 case '-':
3751 switch ( (*arg)[1] )
3752 {
3753 case 'c':
3754 if (mode == 0)
3755 mode = MODE_COMPILE;
3756 else
3757 fatal(0,"Cannot have /c with /a, /d or /p");
3758 break;
3759
3760 case 'a':
3761 if (mode == 0)
3762 mode = MODE_APPEND;
3763 else
3764 fatal(0,"Cannot have /a with /c, /d or /p");
3765 break;
3766
3767 case 'd':
3768 if (mode == 0)
3769 mode = MODE_DELETE;
3770 else
3771 fatal(0,"Cannot have /d with /c, /a or /p");
3772 break;
3773
3774 case 'p':
3775 if (mode == 0)
3776 mode = MODE_PRINT;
3777 else
3778 fatal(0,"Cannot have /p with /c, /a or /d");
3779 break;
3780
3781 case 'm':
3782 if (mode == MODE_COMPILE)
3783 show_mem = 1;
3784 else
3785 fatal(0,"/m switch allowed only when compiling (/c)");
3786 break;
3787
3788 case 's':
3789 if (mode == MODE_COMPILE)
3790 show_stats = 1;
3791 else
3792 fatal(0,"/s switch allowed only when compiling (/c)");
3793 break;
3794
3795 case 'r':
3796 if (mode == MODE_COMPILE || mode == MODE_PRINT)
3797 strcpy(swappath, (*arg)+2);
3798 else
3799 fatal(0,"/r switch allowed when compiling (/c) or printing (/p)");
3800 break;
3801
3802 case 'q':
3803 quiet_mode = 1;
3804 break;
3805
3806 default:
3807 fatal(0,"Bad command-line switch /%c", (*arg)[1]);
3808 break;
3809 }
3810 break;
3811
3812 default: /* assume it is a fname */
3813 if (fname1[0] == '\0')
3814 strcpy(fname1, *arg);
3815 else if (fname2[0] == '\0')
3816 strcpy(fname2, *arg);
3817 else
3818 fatal(0,"Unexpected command-line argument \"%s\"", *arg);
3819 break;
3820 } /* switch */
3821 } /* for */
3822
3823 strupr(fname1);
3824 strupr(fname2);
3825 strupr(swappath);
3826
3827 switch (mode)
3828 {
3829 case 0:
3830 printf( "To compile a .SRC file:\n");
3831 printf( " HC /c [/s] [/m] [/r[path]] [src_file]\n");
3832 printf( " /s = report statistics.\n");
3833 printf( " /m = report memory usage.\n");
3834 printf( " /r[path] = set swap file path.\n");
3835 printf( " src_file = .SRC file. Default is \"%s\"\n", DEFAULT_SRC_FNAME);
3836 printf( "To print a .SRC file:\n");
3837 printf( " HC /p [/r[path]] [src_file] [out_file]\n");
3838 printf( " /r[path] = set swap file path.\n");
3839 printf( " src_file = .SRC file. Default is \"%s\"\n", DEFAULT_SRC_FNAME);
3840 printf( " out_file = Filename to print to. Default is \"%s\"\n",
3841 DEFAULT_DOC_FNAME);
3842 printf( "To append a .HLP file to an .EXE file:\n");
3843 printf( " HC /a [hlp_file] [exe_file]\n");
3844 printf( " hlp_file = .HLP file. Default is \"%s\"\n", DEFAULT_HLP_FNAME);
3845 printf( " exe_file = .EXE file. Default is \"%s\"\n", DEFAULT_EXE_FNAME);
3846 printf( "To delete help info from an .EXE file:\n");
3847 printf( " HC /d [exe_file]\n");
3848 printf( " exe_file = .EXE file. Default is \"%s\"\n", DEFAULT_EXE_FNAME);
3849 printf( "\n");
3850 printf( "Use \"/q\" for quiet mode. (No status messages.)\n");
3851 break;
3852
3853 case MODE_COMPILE:
3854 if (fname2[0] != '\0')
3855 fatal(0,"Unexpected command-line argument \"%s\"", fname2);
3856
3857 strcpy(src_fname, (fname1[0]=='\0') ? DEFAULT_SRC_FNAME : fname1);
3858
3859 strcat(swappath, SWAP_FNAME);
3860
3861 if ( (swapfile=fopen(swappath, "w+b")) == NULL )
3862 fatal(0,"Cannot create swap file \"%s\"", swappath);
3863 swappos = 0;
3864
3865 read_src(src_fname);
3866
3867 if (hdr_fname[0] == '\0')
3868 error(0,"No .H file defined. (Use \"~HdrFile=\")");
3869 if (hlp_fname[0] == '\0')
3870 error(0,"No .HLP file defined. (Use \"~HlpFile=\")");
3871 if (version == -1)
3872 warn(0,"No help version has been defined. (Use \"~Version=\")");
3873
3874 /* order of these is very important... */
3875
3876 make_hot_links(); /* do even if errors since it may report */
3877 /* more... */
3878
3879 if ( !errors ) paginate_online();
3880 if ( !errors ) paginate_document();
3881 if ( !errors ) calc_offsets();
3882 if ( !errors ) sort_labels();
3883 if ( !errors ) write_hdr(hdr_fname);
3884 if ( !errors ) write_help(hlp_fname);
3885
3886 if ( show_stats )
3887 report_stats();
3888
3889 if ( show_mem )
3890 report_memory();
3891
3892 if ( errors || warnings )
3893 report_errors();
3894
3895 fclose(swapfile);
3896 remove(swappath);
3897
3898 break;
3899
3900 case MODE_PRINT:
3901 strcpy(src_fname, (fname1[0]=='\0') ? DEFAULT_SRC_FNAME : fname1);
3902
3903 strcat(swappath, SWAP_FNAME);
3904
3905 if ( (swapfile=fopen(swappath, "w+b")) == NULL )
3906 fatal(0,"Cannot create swap file \"%s\"", swappath);
3907 swappos = 0;
3908
3909 read_src(src_fname);
3910
3911 make_hot_links();
3912
3913 if ( !errors ) paginate_document();
3914 if ( !errors ) print_document( (fname2[0]=='\0') ? DEFAULT_DOC_FNAME : fname2 );
3915
3916 if ( errors || warnings )
3917 report_errors();
3918
3919 fclose(swapfile);
3920 remove(swappath);
3921
3922 break;
3923
3924 case MODE_APPEND:
3925 add_hlp_to_exe( (fname1[0]=='\0') ? DEFAULT_HLP_FNAME : fname1,
3926 (fname2[0]=='\0') ? DEFAULT_EXE_FNAME : fname2);
3927 break;
3928
3929 case MODE_DELETE:
3930 if (fname2[0] != '\0')
3931 fatal(0,"Unexpected argument \"%s\"", fname2);
3932 delete_hlp_from_exe((fname1[0]=='\0') ? DEFAULT_EXE_FNAME : fname1);
3933 break;
3934 }
3935
3936 free(buffer);
3937
3938 return ( errors ); /* return the number of errors */
3939 }
3940
3941
3942