Mercurial > ~dholland > hg > ag > index.cgi
comparison help2html/mhh6.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 /* | |
2 * October 30, 2007. mhh6: use C, not C++. | |
3 * | |
4 * Sept 5, 2006. mhh5.syn modified for XML_OUTPUT option. | |
5 * | |
6 * June 20, 2001. mhh5.syn | |
7 * Modifying mhh4 to create HTML output | |
8 * (mhh4 sorts a help.src file case-insensitively by title line while | |
9 * cleaning it up a bit.) | |
10 * | |
11 * June 16 2001 | |
12 * Unlike mhh3b, mhh4 stores and sorts title *lines*, not titles, | |
13 * from help.src. Another AgStringDirectory has been added to hold | |
14 * topic bodies. | |
15 * | |
16 * Change mhh3b.syn to store title lines in string dicts. | |
17 * Change mhh3a.syn to use AgStringDictionary for titles. | |
18 * Jun 8/01 Change mhh3.syn to add main and some reduc. procedures | |
19 * | |
20 * June 8, 2001 - mhh3.syn now parses Jerry's current help.src (b8) | |
21 * with no conflicts or keyword anomalies but spaces (and tabs) are | |
22 * not allowed in blank lines. Why the eof line tolerates spaces is | |
23 * something of a mystery. | |
24 */ | |
25 | |
26 // -- CONFIGURATION SECTION ---------------------------- | |
27 [ | |
28 pointer input | |
29 no cr // no carr. ret. in output parser | |
30 parser file name = "#.c" | |
31 line numbers | |
32 ] | |
33 //------------------------------------------------------ | |
34 | |
35 | |
36 eof = 0 | |
37 char = ~eof | |
38 lead title char = char - blank - tab - ',' - bullet - '\n' - '\r' | |
39 title char = char - ',' - bullet - '\n' - '\r' | |
40 lead topic char = char - blank - tab - bullet - '\n' - '\r' | |
41 text char = char - bullet - '\n' - '\r' | |
42 table char = char - tab - '\n' - '\r' | |
43 | |
44 blank = 0x20 | |
45 tab = 9 | |
46 bullet = 7 | |
47 | |
48 //blank line | |
49 // -> blank?..., '\n' | |
50 blank line | |
51 -> '\n' /* Don't allow spaces in line */ | |
52 -> '\r','\n' | |
53 | |
54 eof line | |
55 -> blank?..., eof | |
56 | |
57 eol | |
58 -> '\n' | |
59 -> '\r','\n' | |
60 | |
61 (void) help sourcefile $ // ** Grammar token ** | |
62 -> topic..., blank line?, eof line | |
63 | |
64 | |
65 topic | |
66 -> blank line?..., title line, eol, blank line?..., topic lines, | |
67 end topic | |
68 | |
69 title line | |
70 -> title line too = { | |
71 title_line_count++; | |
72 // buffer_append(&titleLine, "</h3>\n<p>"); | |
73 saveTitleLine(); | |
74 } | |
75 | |
76 title line too | |
77 -> title = title_count++, putTitle(); | |
78 -> title line too, ',', blank?..., title = title_count++, appendTitle(); | |
79 | |
80 title | |
81 -> lead title char:c = | |
82 buffer_start(&title, c), buffer_start(&title1, toupper(c)); | |
83 -> title, title char:c = | |
84 buffer_add(&title, c), buffer_add(&title1, toupper(c)); | |
85 | |
86 end topic | |
87 -> "##", blank?..., eol | |
88 -> "\n##", blank?..., eol | |
89 -> "\r\n##", blank?..., eol | |
90 | |
91 topic lines | |
92 -> topic lines too = { saveTopicBody(); } | |
93 | |
94 topic lines too | |
95 -> text parag =buffer_append(&topicBody,"\n"); | |
96 -> topic lines too, blank line..., parag=buffer_append(&topicBody,"\n"); | |
97 | |
98 parag | |
99 -> text parag | |
100 -> table parag | |
101 -> list1 parag = finishList(Tlist1); | |
102 -> list2 parag = finishList(Tlist2); | |
103 -> listtab parag = finishList(Tlisttab); | |
104 -> code parag | |
105 | |
106 | |
107 text parag | |
108 -> partial text parag | |
109 -> partial text parag, table parag | |
110 -> text block, list1 parag = finishList(Tlist1); | |
111 -> text block, listtab parag = finishList(Tlisttab); | |
112 -> text block, code parag | |
113 -> text block, code parag, text block | |
114 | |
115 | |
116 partial text parag | |
117 -> text block | |
118 -> partial text parag, table parag, text block | |
119 | |
120 | |
121 | |
122 text block | |
123 -> !buffer_append(&topicBody, "<p>");, | |
124 first text line, other text line?... = | |
125 buffer_append(&topicBody, "</p>"); | |
126 | |
127 | |
128 table parag | |
129 -> table parag too = buffer_append(&topicBody, "\n</table>\n\n"); | |
130 | |
131 table parag too | |
132 -> first table line | |
133 -> table parag too, other table line | |
134 | |
135 | |
136 list1 parag | |
137 -> list1 block, list1 block?... | |
138 | |
139 list1 block | |
140 -> first list1 line, other list1 line?... = | |
141 buffer_append(&topicBody, "</li>\n"); | |
142 -> first list1 line, other list1 line?..., table parag = | |
143 buffer_append(&topicBody, "</li>\n"); | |
144 -> first list1 line, other list1 line?..., code parag = | |
145 buffer_append(&topicBody, "</li>\n"); | |
146 | |
147 | |
148 list2 parag | |
149 -> first list2 line, other list2 line?... = | |
150 buffer_append(&topicBody, "</li>\n"); | |
151 | |
152 listtab parag | |
153 -> listtab block, listtab block?... | |
154 | |
155 listtab block | |
156 -> first listtab line, other listtab line?... = | |
157 buffer_append(&topicBody, "</li>\n"); | |
158 -> first listtab line, other listtab line?..., table parag = | |
159 buffer_append(&topicBody, "</li>\n"); | |
160 | |
161 code parag | |
162 -> code parag too = | |
163 buffer_append(&topicBody, "\n</pre>"); | |
164 | |
165 code parag too | |
166 -> first code line | |
167 -> code parag too, other code line | |
168 | |
169 | |
170 first text line | |
171 -> lead topic char:c, text frag?, eol = { | |
172 total1sttextline++; | |
173 appendEnd(c); | |
174 } | |
175 -> blank, lead topic char:c, text frag?,eol = { | |
176 total1sttextlineb++; | |
177 buffer_add(&topicBody, 0x20); | |
178 appendEnd(c); | |
179 } | |
180 other text line | |
181 -> lead topic char:c, text frag?, eol = appendEnd(c); | |
182 | |
183 | |
184 //################# OLD #################################################### | |
185 //first table line | |
186 // -> tab seq, blank seq?, lead topic char:c, text frag?, '\n' = { | |
187 // total1sttableline++; | |
188 // buffer_append(&topicBody, "\n<pre> "); | |
189 // appendEnd(c); | |
190 // buffer_clear(&tabFrag); | |
191 // buffer_clear(&blankFrag); | |
192 // } | |
193 // | |
194 //other table line | |
195 // -> tab seq, blank seq?, lead topic char:c, text frag?, '\n' = { | |
196 // buffer_append(&topicBody, " "); | |
197 // appendEnd(c); | |
198 // buffer_clear(&tabFrag); | |
199 // buffer_clear(&blankFrag); | |
200 // } | |
201 //############################################################################ | |
202 | |
203 | |
204 | |
205 | |
206 first table line | |
207 -> first table line body, eol = | |
208 buffer_append(&topicBody, "</td></tr>"); | |
209 | |
210 first table line body | |
211 -> tab seq, blank seq?, lead topic char:c, table frag? = { | |
212 total1sttableline++; | |
213 buffer_append(&topicBody, | |
214 "\n\n<table cellpadding=\"7\" cellspacing=\"2\" >\n<tr><td> "); | |
215 appendTableCell(c); | |
216 buffer_clear(&tabFrag); | |
217 buffer_clear(&blankFrag); | |
218 } | |
219 | |
220 -> first table line body, tab seq, blank seq?, lead topic char:c, | |
221 table frag? = { | |
222 buffer_append(&topicBody, "</td>\n<td> "); | |
223 appendTableCell(c); | |
224 buffer_clear(&tabFrag); | |
225 buffer_clear(&blankFrag); | |
226 } | |
227 | |
228 other table line | |
229 -> other table line body, eol = | |
230 buffer_append(&topicBody, "</td></tr>"); | |
231 | |
232 other table line body | |
233 -> tab seq, blank seq?, lead topic char:c, table frag? = { | |
234 buffer_append(&topicBody, "\n\n<tr><td> "); | |
235 appendTableCell(c); | |
236 buffer_clear(&tabFrag); | |
237 buffer_clear(&blankFrag); | |
238 } | |
239 | |
240 -> other table line body, tab seq, blank seq?, lead topic char:c, | |
241 table frag? = { | |
242 buffer_append(&topicBody, "</td>\n<td> "); | |
243 appendTableCell(c); | |
244 buffer_clear(&tabFrag); | |
245 buffer_clear(&blankFrag); | |
246 } | |
247 | |
248 | |
249 | |
250 first list1 line | |
251 -> bullet, blank, lead topic char:c, text frag?, eol = { | |
252 total1stlist1line++; | |
253 if (intstack_top(¶gType) != Tlist1) { | |
254 intstack_push(¶gType, Tlist1); | |
255 buffer_append(&topicBody, "\n<ul>"); | |
256 } | |
257 buffer_append(&topicBody, "\n<li>"); | |
258 buffer_add(&topicBody, 0x20); | |
259 appendEnd(c); | |
260 } | |
261 | |
262 other list1 line | |
263 -> lead topic char:c, text frag?, eol = appendEnd(c); | |
264 | |
265 | |
266 first list2 line | |
267 -> bullet, blank, blank, lead topic char:c, text frag?, eol = { | |
268 total1stlist2line++; | |
269 if (intstack_top(¶gType) != Tlist2) { | |
270 intstack_push(¶gType, Tlist2); | |
271 buffer_append(&topicBody, "\n<ul>"); | |
272 } | |
273 buffer_append(&topicBody, "\n<li>"); | |
274 buffer_append(&topicBody, " "); | |
275 appendEnd(c); | |
276 } | |
277 | |
278 other list2 line | |
279 -> lead topic char:c, text frag?, eol = appendEnd(c); | |
280 | |
281 | |
282 first listtab line | |
283 -> bullet, tab:t, lead topic char:c, text frag?, eol = { | |
284 total1stlisttabline++; | |
285 if (intstack_top(¶gType) != Tlisttab) { | |
286 intstack_push(¶gType, Tlisttab); | |
287 buffer_append(&topicBody, "\n<ul>"); | |
288 } | |
289 buffer_append(&topicBody, "\n<li>"); | |
290 buffer_add(&topicBody, t); | |
291 appendEnd(c); | |
292 } | |
293 | |
294 other listtab line | |
295 -> lead topic char:c, text frag?, eol = appendEnd(c); | |
296 | |
297 | |
298 | |
299 first code line | |
300 -> " ", lead topic char:c, text frag?, eol = { | |
301 total1stcodeline++; | |
302 buffer_append(&topicBody, "\n<pre> "); | |
303 appendEnd(c); | |
304 } | |
305 -> " ", lead topic char:c, text frag?, eol = { | |
306 total1stcodeline++; | |
307 buffer_append(&topicBody, "\n<pre> "); | |
308 appendEnd(c); | |
309 } | |
310 -> " ", lead topic char:c, text frag?, eol = { | |
311 total1stcodeline++; | |
312 buffer_append(&topicBody, "\n<pre> "); | |
313 appendEnd(c); | |
314 } | |
315 -> " ", lead topic char:c, text frag?, eol = { | |
316 total1stcodeline++; | |
317 buffer_append(&topicBody, "\n<pre> "); | |
318 appendEnd(c); | |
319 } | |
320 -> " ", lead topic char:c, text frag?, eol = { | |
321 total1stcodeline++; | |
322 buffer_append(&topicBody, "\n<pre> "); | |
323 appendEnd(c); | |
324 } | |
325 -> " ", lead topic char:c, text frag?, eol = { | |
326 total1stcodeline++; | |
327 buffer_append(&topicBody, "\n<pre> "); | |
328 appendEnd(c); | |
329 } | |
330 -> " ", lead topic char:c, text frag?, eol = { | |
331 total1stcodeline++; | |
332 buffer_append(&topicBody, "\n<pre> "); | |
333 appendEnd(c); | |
334 } | |
335 | |
336 | |
337 other code line | |
338 -> " ", lead topic char:c, text frag?, eol = { | |
339 buffer_append(&topicBody, " "); | |
340 appendEnd(c); | |
341 } | |
342 -> " ", lead topic char:c, text frag?, eol = { | |
343 buffer_append(&topicBody, " "); | |
344 appendEnd(c); | |
345 } | |
346 -> " ", lead topic char:c, text frag?, eol = { | |
347 buffer_append(&topicBody, " "); | |
348 appendEnd(c); | |
349 } | |
350 -> " ", lead topic char:c, text frag?, eol = { | |
351 buffer_append(&topicBody, " "); | |
352 appendEnd(c); | |
353 } | |
354 -> " ", lead topic char:c, text frag?, eol = { | |
355 buffer_append(&topicBody, " "); | |
356 appendEnd(c); | |
357 } | |
358 -> " ", lead topic char:c, text frag?, eol = { | |
359 buffer_append(&topicBody, " "); | |
360 appendEnd(c); | |
361 } | |
362 -> " ", lead topic char:c, text frag?, eol = { | |
363 buffer_append(&topicBody, " "); | |
364 appendEnd(c); | |
365 } | |
366 | |
367 text frag | |
368 -> text char:c = buffer_start(&topicFrag, c); | |
369 -> text frag, text char:c = buffer_add(&topicFrag, c); | |
370 | |
371 table frag | |
372 -> table char:c = buffer_start(&topicFrag, c); | |
373 -> table frag, table char:c = buffer_add(&topicFrag, c); | |
374 | |
375 | |
376 tab seq | |
377 -> tab:t = buffer_start(&tabFrag, t); | |
378 -> tab seq, tab:t = buffer_add(&tabFrag, t); | |
379 | |
380 blank seq | |
381 -> blank = buffer_start(&blankFrag, 0x20); | |
382 -> blank seq, blank = buffer_add(&blankFrag, 0x20); | |
383 | |
384 | |
385 | |
386 | |
387 { /* ----- Embedded C --------------------------------------------*/ | |
388 | |
389 | |
390 #include <stdio.h> | |
391 #include <string.h> | |
392 #include <malloc.h> | |
393 #include <assert.h> | |
394 #include <ctype.h> | |
395 #include <assert.h> | |
396 #include <err.h> | |
397 #include "uintarray.h" | |
398 #include "support.h" | |
399 #include "buffer.h" | |
400 #include "stringdict.h" | |
401 #include "must.h" | |
402 | |
403 int verbose = 0; | |
404 | |
405 int total1sttextline = 0; | |
406 int total1sttextlineb = 0; | |
407 int total1sttableline = 0; | |
408 int total1stlist1line = 0; | |
409 int total1stlist2line = 0; | |
410 int total1stlisttabline = 0; | |
411 int total1stcodeline = 0; | |
412 | |
413 int title_count =0; | |
414 int title_line_count = 0; | |
415 | |
416 char *helpentStr; | |
417 struct buffer title; | |
418 struct buffer title1; | |
419 struct buffer titleLine; | |
420 struct buffer titleLine1; | |
421 struct stringdict *titleDict; | |
422 struct stringdict *titleDict1; // upper case | |
423 struct stringdict *titleLineDict; | |
424 struct stringdict *titleLineDict1; // upper case | |
425 struct buffer topicFrag; | |
426 struct buffer tabFrag; | |
427 struct buffer blankFrag; | |
428 struct buffer topicBody; | |
429 struct stringdict *topicBodyDict; | |
430 struct uintarray titleToTitleLine; | |
431 struct intstack paragType; | |
432 | |
433 enum paragTypes {Tnone=0, Ttext=1, Ttable=2, Tlist1=3, Tlist2=4, | |
434 Tlisttab=5, Tcode=6}; | |
435 | |
436 char *charToEntity(const char *instring); | |
437 void putTitle(void); | |
438 void appendTitle(void); | |
439 void saveTitleLine(void); | |
440 void appendEnd(int c); | |
441 void removeFinalNewline(void); | |
442 void saveTopicBody(void); | |
443 void printDict(const struct stringdict *dictionary); | |
444 void writeSortedHtml(FILE *output); | |
445 void writeFullTopics(FILE *output, const struct stringdict *dictionary, | |
446 const struct stringdict *dictionary1, | |
447 const struct stringdict *dictionaryb); | |
448 void writeTitles(FILE *output, const struct stringdict *dictionary, | |
449 const struct stringdict *dictionary1); | |
450 int processLinkString(FILE *filein, FILE *fileout); | |
451 | |
452 | |
453 // replace &, <, > in S with entities | |
454 char *charToEntity(const char *s) { | |
455 char *ret; | |
456 int i, j, len=0; | |
457 | |
458 for (i=0; s[i]; i++) { | |
459 if (s[i] == '&') len += 5; /* & */ | |
460 else if (s[i] == '<') len += 4; /* < */ | |
461 else if (s[i] == '>') len += 4; /* > */ | |
462 else len++; | |
463 } | |
464 | |
465 ret = malloc(len+1); | |
466 if (!ret) { | |
467 errx(1, "Out of memory"); | |
468 } | |
469 | |
470 for (i=j=0; s[i]; i++) { | |
471 if (s[i] == '&') { strcpy(ret+j, "&"); j += 5; } | |
472 else if (s[i] == '<' ) { strcpy(ret+j, "<"); j += 4; } | |
473 else if (s[i] == '>' ) { strcpy(ret+j, ">"); j += 4; } | |
474 else ret[j++] = s[i]; | |
475 } | |
476 ret[j] = 0; | |
477 | |
478 return ret; | |
479 } | |
480 | |
481 // Save title both ways, make map entry for title<--->title line | |
482 void saveTitle(void) { | |
483 if (stringdict_exists(titleDict, title.text)) { | |
484 fprintf( stderr, "Warning: Repeated title %s\n", title.text ); | |
485 } | |
486 #if 0 | |
487 else if (!strcmp(title.text, "Secret of Life")) { | |
488 // Do not save "Secret of Life" title | |
489 return; | |
490 } | |
491 #endif | |
492 else { | |
493 // Save title in dictionary | |
494 unsigned titleIndex = stringdict_intern(titleDict, title.text); | |
495 | |
496 // Save title in upper case dictionary | |
497 stringdict_intern(titleDict1, title1.text); | |
498 | |
499 // count() should give next index | |
500 unsigned titleLineIndex = stringdict_count(titleLineDict); | |
501 | |
502 // use an array for this (the keys are array indexes anyway) | |
503 if (titleIndex >= uintarray_num(&titleToTitleLine)) { | |
504 unsigned x, old = uintarray_num(&titleToTitleLine); | |
505 uintarray_setsize(&titleToTitleLine, titleIndex+1); | |
506 for (x=old; x<titleIndex; x++) { | |
507 uintarray_set(&titleToTitleLine, x, (unsigned) -1); | |
508 } | |
509 } | |
510 // Store indices in map | |
511 uintarray_set(&titleToTitleLine, titleIndex, titleLineIndex); | |
512 } | |
513 } | |
514 | |
515 | |
516 void putTitle(void) { | |
517 // Save title itself in both reg. and upper case title dicts | |
518 saveTitle(); | |
519 buffer_append(&titleLine, title.text); | |
520 buffer_append(&titleLine1, title1.text); | |
521 } | |
522 | |
523 | |
524 void appendTitle() { | |
525 // Save title itself in both reg. and upper case title dicts | |
526 saveTitle(); | |
527 buffer_append(&titleLine, ", "); | |
528 buffer_append(&titleLine1, ", "); | |
529 buffer_append(&titleLine, title.text); | |
530 buffer_append(&titleLine1, title1.text); | |
531 } | |
532 | |
533 | |
534 void saveTitleLine() { | |
535 #if 0 | |
536 static int foundSoL=0; | |
537 if (stringdict_count(titleLineDict)==0 && | |
538 strcmp(titleLine.text, "Secret of Life")!=0 && foundSoL==0) { | |
539 fprintf(stderr, "Warning: Secret of Life does not lead file!\n"); | |
540 } | |
541 #endif | |
542 | |
543 #if 0 | |
544 if (!strcmp(titleLine.text, "Secret of Life")) { | |
545 // Don't save title line in dicts. | |
546 // Should be at beginning of help file | |
547 assert(stringdict_count(titleLineDict)==0); | |
548 foundSoL = 1; | |
549 if (verbose) { | |
550 printf( "\n Found Secret of Life!\n\n" ); | |
551 } | |
552 } | |
553 else | |
554 #endif | |
555 if ( stringdict_exists(titleLineDict, titleLine.text) ) { | |
556 fprintf( stderr, "Warning: Repeated title line %s\n", | |
557 titleLine.text ); | |
558 } | |
559 else { | |
560 // Save title line in dictionary | |
561 stringdict_intern(titleLineDict, titleLine.text); | |
562 // Save title line in upper case dictionary | |
563 stringdict_intern(titleLineDict1, titleLine1.text); | |
564 } | |
565 buffer_clear(&titleLine); | |
566 buffer_clear(&titleLine1); | |
567 } | |
568 | |
569 | |
570 // Append the latter part of the line | |
571 void appendEnd(int c) { | |
572 buffer_add(&topicBody, c); | |
573 buffer_append(&topicBody, topicFrag.text); | |
574 buffer_append(&topicBody, "\n" ); | |
575 buffer_clear(&topicFrag); | |
576 } | |
577 | |
578 // Append a cell to the table row | |
579 void appendTableCell(int c) { | |
580 // Could insert <pre> </pre> or <code> </code> tags here for cell | |
581 buffer_append(&topicBody, "<code> " ); | |
582 buffer_add(&topicBody, c); | |
583 buffer_append(&topicBody, topicFrag.text); | |
584 buffer_append(&topicBody, "</code>" ); | |
585 //buffer_append(&topicBody, "\n" ); | |
586 buffer_clear(&topicFrag); | |
587 } | |
588 | |
589 void removeFinalNewline(void) { | |
590 int x = topicBody.len; | |
591 assert(topicBody.text[x-2]=='\n' && topicBody.text[x-1]=='\n'); | |
592 topicBody.text[x-1] = 0; | |
593 } | |
594 | |
595 void saveTopicBody(void) { | |
596 #if 0 | |
597 // do not save Secret of Life topic body | |
598 if (stringdict_count(titleLineDict) != 0) { | |
599 #endif | |
600 // save topic body | |
601 stringdict_intern(topicBodyDict, topicBody.text); | |
602 #if 0 | |
603 } | |
604 #endif | |
605 buffer_clear(&topicBody); | |
606 } | |
607 | |
608 /* | |
609 void startTable(void) { | |
610 // If we don't currently have table, start a new one | |
611 if (paragType.top() != Ttable) { | |
612 // Start table | |
613 paragType.push( Ttable ); | |
614 } | |
615 } | |
616 */ | |
617 | |
618 void finishList(int listtype){ | |
619 //printf( "\nfinishList() - top type = %d, listtype = %d, " | |
620 // "stack size = %d\n" | |
621 // " titleLineDict size = %d\n", | |
622 // paragType.top(), listtype, paragType.size(), | |
623 // titleLineDict.size() ); | |
624 assert(intstack_top(¶gType) == listtype); | |
625 intstack_pop(¶gType); | |
626 buffer_append(&topicBody, "\n</ul>"); | |
627 } | |
628 | |
629 void printDict(const struct stringdict *dictionary) { | |
630 unsigned i; | |
631 for (i=0; i<stringdict_count(dictionary); i++) { | |
632 printf("%4d: %s\n", i, stringdict_getbynum(dictionary, i)); | |
633 } | |
634 } | |
635 | |
636 char *SqueezeWS(const char *Input) { | |
637 /* return a (strdup()-like) copy of Input, with whitespace squeezed out */ | |
638 char *copy; | |
639 int cnt, outcnt; | |
640 | |
641 copy = must_malloc(strlen(Input)+1); | |
642 | |
643 for (cnt=0, outcnt=0; Input[cnt]; cnt++) { | |
644 unsigned char ch = Input[cnt]; | |
645 if (!isspace(ch)) { | |
646 copy[outcnt]=ch; | |
647 outcnt++; | |
648 } | |
649 } | |
650 copy[outcnt]=0; | |
651 | |
652 return copy; | |
653 } | |
654 | |
655 void writeFullTopics(FILE *output, | |
656 const struct stringdict *dictionary, /* title lines */ | |
657 const struct stringdict *dictionary1, /* UC titlelines*/ | |
658 const struct stringdict *dictionaryb) /* topic bodies */ | |
659 { | |
660 unsigned i; | |
661 | |
662 #if 0 | |
663 /* Write "Secret of Life" topic at beginning of topics */ | |
664 //fprintf(output, "Secret of Life>\n\n"); | |
665 //fprintf(output, "No help message for this topic.\n##\n"); | |
666 #endif | |
667 | |
668 assert( stringdict_count(dictionary) == stringdict_count(dictionary1) ); | |
669 struct permutation *perm = mySort(dictionary1); // Sort dictionary1 | |
670 | |
671 | |
672 /* Write out topics in a definition list <dl> */ | |
673 fprintf( output, "\n\n<dl>\n\n" ); | |
674 | |
675 // write dictionary, sorted according to dict1 | |
676 for (i = 0; i < stringdict_count(dictionary); i++) { | |
677 //fprintf(output, "<dt><b><a name=\"%04d\">%s</a></b></dt>\n" | |
678 // "<dd>%s\n</dd><br/>\n\n", | |
679 // perm->v[i], | |
680 // stringdict_getbynum(dictionary, perm->v[i]), | |
681 // stringdict_getbynum(dictionaryb, perm->v[i]) ); | |
682 | |
683 char *anchorname=SqueezeWS(stringdict_getbynum(dictionary, perm->v[i])); | |
684 fprintf(output, "<dt><b><a name=\"%s\">%s</a></b></dt>\n" | |
685 "<dd>%s\n</dd>\n\n", | |
686 anchorname, | |
687 stringdict_getbynum(dictionary, perm->v[i]), | |
688 stringdict_getbynum(dictionaryb, perm->v[i]) ); | |
689 free(anchorname); | |
690 } | |
691 fprintf( output, "\n\n</dl>\n\n" ); | |
692 permutation_destroy(perm); | |
693 } | |
694 | |
695 void writeTitles(FILE *output, | |
696 const struct stringdict *dictionary, /* titles */ | |
697 const struct stringdict *dictionary1) /* uppercase titles */ | |
698 { | |
699 assert( stringdict_count(dictionary) == stringdict_count(dictionary1) ); | |
700 struct permutation *perm = mySort(dictionary1); // Sort dictionary1 | |
701 | |
702 /* Write 2-column table of titles */ | |
703 /* | |
704 // n_t is true title count w/o Secret of Life | |
705 int n_t = stringdict_count(dictionary); | |
706 // we better have some titles | |
707 assert( n_t >= 2 ); | |
708 // n_t1 is #titles in 1st column | |
709 int n_t1 = n_t%2 ? n_t/2 +1 : n_t/2; | |
710 // n_t2 is #titles in 2nd column | |
711 int n_t2 = n_t%2; | |
712 int i; | |
713 fprintf( output, "\n\n<table width=\"100%%\" " | |
714 "style=\"margin-left: auto ; margin-right: auto\" \n" | |
715 " cellpadding=\"15\" cellspacing=\"5\" >\n" | |
716 "<tr align=\"left\">\n" | |
717 "<td valign=\"top\" style=\"white-space: nowrap\">" | |
718 "\n\n\n"); | |
719 | |
720 // Write out dictionary sorted acc. to dictionary1 | |
721 // write out the first half, sorted | |
722 for (i = 0; i < n_t1; i++) { | |
723 fprintf(output, " \xA9%s\xAA\n<br/>", | |
724 stringdict_getbynum(dictionary, perm->v[i])); | |
725 } | |
726 | |
727 fprintf(output, "</td>\n\n"); | |
728 fprintf(output, "<td valign=\"top\" style=\"white-space: nowrap\">\n\n"); | |
729 | |
730 // write out the last half, sorted | |
731 for ( i = n_t1; i < n_t; i++) { | |
732 fprintf(output, " \xA9%s\xAA\n<br/>", | |
733 stringdict_getbynum(dictionary, perm->v[i])); | |
734 } | |
735 | |
736 fprintf(output, "</td>\n</tr>\n</table>\n\n<hr><br/><br/>\n\n" ); | |
737 */ | |
738 | |
739 /* Write 1-column list of titles */ | |
740 | |
741 // n_t is true title count w/o Secret of Life | |
742 unsigned n_t = stringdict_count(dictionary); | |
743 // we better have some titles | |
744 assert( n_t >= 2 ); | |
745 unsigned i; | |
746 | |
747 fprintf(output, "<h2>Help Topic Index</h2>\n\n" ); | |
748 // Write out the index, sorted acc. to dictionary1 | |
749 for (i = 0; i < n_t; i++) { | |
750 fprintf(output, "\xA9%s\xAA\n<br/>", | |
751 stringdict_getbynum(dictionary, perm->v[i])); | |
752 } | |
753 } | |
754 | |
755 void writeSortedHtml( FILE *output ) { | |
756 /* Leading HTML */ | |
757 | |
758 #ifdef XML_OUTPUT | |
759 fprintf(output, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" | |
760 "<?xml-stylesheet type=\"text/xsl\" href=\"../ag_web.xml\"?>\n" | |
761 "\n" | |
762 "<body rootdir=\"..\" navname=\"Documentation: AnaGram Help\">\n"); | |
763 | |
764 #else | |
765 fprintf(output, "<html>\n<head>\n"); | |
766 fprintf(output, "<title>AnaGram Help Topics - HTML version</title>\n"); | |
767 fprintf(output, "</head>\n\n\n"); | |
768 fprintf(output, "<body bgcolor=\"#ffffff\" text=\"#000000\""); | |
769 fprintf(output, " link=\"#0033CC\" vlink=\"#CC0033\" alink=\"#CC0099\">"); | |
770 fprintf(output, "\n\n\n"); | |
771 #endif | |
772 | |
773 /* Write page title */ | |
774 #ifdef XML_OUTPUT | |
775 fprintf(output, "<h1>AnaGram Help</h1>\n\n"); | |
776 #else | |
777 fprintf(output, "<hr><h2>AnaGram Help Topics - HTML Version</h2><hr>\n\n"); | |
778 #endif | |
779 /* Write 2-column table of titles */ | |
780 writeTitles( output, titleDict, titleDict1 ); | |
781 | |
782 /* Write full topics in single- column table */ | |
783 //fprintf( output, "\n\n<table width=\"100%%\">\n<tr><td>\n<p>\n\n"); | |
784 //writeFullTopics( output, titleLineDict, titleLineDict1, topicBodyDict ); | |
785 //fprintf( output, "</td></tr>\n</table>\n" ); | |
786 | |
787 /* Write full topics directly to the output page */ | |
788 writeFullTopics( output, titleLineDict, titleLineDict1, topicBodyDict ); | |
789 | |
790 #ifdef XML_OUTPUT | |
791 fprintf(output,"\n</body>\n"); | |
792 #else | |
793 /* Ending HTML */ | |
794 fprintf( output, "\n<p><br/><address><a " | |
795 "NAME=\"copyright\">AnaGram Help Topics, HTML version.</a>\n" | |
796 "<br> Copyright © Parsifal Software, 2001.<br>\n" | |
797 "All Rights Reserved.</address>" | |
798 "\n\n</body>\n</html>\n\n" ); | |
799 #endif | |
800 } | |
801 | |
802 int processLinkString( FILE *filein, FILE *fileout ) { | |
803 struct buffer linkString; // lower case | |
804 struct buffer linkString1; // upper case version | |
805 unsigned index; | |
806 int c; | |
807 int wspaceFlag =0; | |
808 | |
809 buffer_init(&linkString); | |
810 buffer_init(&linkString1); | |
811 | |
812 while ( (c=fgetc(filein)) != EOF ) { | |
813 | |
814 if ( c != 0xAA) { // test for end of link char | |
815 if ( c == 0x20 || c == 0x0D || c == 0x0A ) { | |
816 // don't append these chars | |
817 wspaceFlag = 1; | |
818 } | |
819 else { | |
820 if (wspaceFlag) { | |
821 // Replace space, cr, lf with single space | |
822 buffer_add(&linkString, 0x20); | |
823 buffer_add(&linkString1, toupper(0x20)); | |
824 } | |
825 buffer_add(&linkString, c); | |
826 buffer_add(&linkString1, toupper(c)); | |
827 wspaceFlag = 0; | |
828 } | |
829 } | |
830 else { | |
831 // end of link - look up using upper case string | |
832 if (!stringdict_exists(titleDict1, linkString1.text)) { | |
833 // try match w/o final S | |
834 if ( linkString1.text[linkString1.len - 1] == 'S' ) { | |
835 linkString1.text[linkString1.len - 1] = 0; | |
836 if (stringdict_exists(titleDict1, linkString1.text)) { | |
837 goto matched; // Eccch - a goto! | |
838 } | |
839 } | |
840 | |
841 fprintf(stderr, "Can't find this link in titleDict1: %s\n", | |
842 linkString1.text); | |
843 return 21; | |
844 } | |
845 | |
846 /* find corresp. index in title line direc. */ | |
847 matched: | |
848 | |
849 index = stringdict_findbyname(titleDict1, linkString1.text); | |
850 | |
851 unsigned ilink = uintarray_get(&titleToTitleLine, index); | |
852 assert(ilink != (unsigned) -1); | |
853 | |
854 // Write out string, linked to title line | |
855 char *linkname=SqueezeWS(stringdict_getbynum(titleLineDict, ilink)); | |
856 //fprintf(fileout, "<a href=\"#%04d\">%s</a>", ilink, linkString.text); | |
857 fprintf( fileout, "<a href=\"#%s\">%s</a>", linkname, linkString.text); | |
858 free(linkname); | |
859 | |
860 buffer_cleanup(&linkString); | |
861 buffer_cleanup(&linkString1); | |
862 | |
863 return 0; // normal return - have found and written link | |
864 } | |
865 } | |
866 // Error - unexpected end of file | |
867 fprintf(stderr, "Error: EOF detected while searching for end of link.\n"); | |
868 fprintf(stderr, " Current link string is: %s\n", linkString.text ); | |
869 return 23; | |
870 } | |
871 | |
872 static void init(void) { | |
873 buffer_init(&title); | |
874 buffer_init(&title1); | |
875 buffer_init(&titleLine); | |
876 buffer_init(&titleLine1); | |
877 titleDict = stringdict_create(); | |
878 titleDict1 = stringdict_create(); | |
879 titleLineDict = stringdict_create(); | |
880 titleLineDict1 = stringdict_create(); | |
881 topicBodyDict = stringdict_create(); | |
882 buffer_init(&topicFrag); | |
883 buffer_init(&tabFrag); | |
884 buffer_init(&blankFrag); | |
885 buffer_init(&topicBody); | |
886 intstack_init(¶gType); | |
887 uintarray_init(&titleToTitleLine); | |
888 } | |
889 | |
890 /* -- Main Program -- */ | |
891 | |
892 int main(int argc, char *argv[]) { | |
893 | |
894 FILE *input; | |
895 | |
896 long fileLength; | |
897 size_t stringLength; | |
898 char *helpsrcString; | |
899 | |
900 init(); | |
901 | |
902 if (verbose) { | |
903 printf( "\n This program reads a help.src-type file, " | |
904 "replaces &, <, > with entities,\n" | |
905 "sorts in a case-insensitive manner and writes " | |
906 "to output file as HTML\n" | |
907 "with a preceding list of the help topics. \n\n" ); | |
908 } | |
909 | |
910 /* Check for enough arguments */ | |
911 if (argc != 3) { | |
912 fprintf(stderr, "Usage: mhh6 helpdata.src help.html\n"); | |
913 return 1; | |
914 } | |
915 | |
916 /* Open input file */ | |
917 input = fopen(argv[1],"r"); | |
918 if (input == NULL) { | |
919 fprintf(stderr, "Cannot open %s\n", argv[1]); | |
920 return 2; | |
921 } | |
922 | |
923 /* find out how big the input file is */ | |
924 if (fseek(input, SEEK_SET, SEEK_END)) { | |
925 fprintf(stderr, "Strange problems with %s\n", argv[1]); | |
926 return 3; | |
927 } | |
928 fileLength = ftell(input); | |
929 if (fileLength < 0 ) { // -1L is error return | |
930 fprintf(stderr, "Error getting file length (%ld) of %s\n", | |
931 fileLength, argv[1]); | |
932 return 4; | |
933 } | |
934 | |
935 /* fseek to beginning of file */ | |
936 if (fseek(input, 0, SEEK_SET)) { | |
937 fprintf(stderr, "Strange problems with %s\n", argv[1]); | |
938 return 5; | |
939 } | |
940 | |
941 /* Allocate storage for input string */ | |
942 helpsrcString = must_malloc(fileLength + 1); | |
943 | |
944 /* read file */ | |
945 stringLength = fread(helpsrcString, 1, (unsigned)fileLength, input); | |
946 if (stringLength == 0) { | |
947 fprintf(stderr, "Unable to read %s\n", argv[1]); | |
948 free(helpsrcString); | |
949 fclose(input); | |
950 return 7; | |
951 } | |
952 // Terminate string with null | |
953 helpsrcString[stringLength] = 0; | |
954 | |
955 /* first, replace < > & with entities */ | |
956 helpentStr = charToEntity( helpsrcString ); | |
957 | |
958 /* no more need for input string or file */ | |
959 free(helpsrcString); | |
960 fclose(input); | |
961 | |
962 /* initialize stack of parag types */ | |
963 intstack_push(¶gType, Tnone); | |
964 | |
965 /* call parser */ | |
966 PCB.pointer = (unsigned char *)(const char *)helpentStr; | |
967 mhh6(); | |
968 | |
969 /* Print file statistics */ | |
970 if (verbose) { | |
971 printf("No. of title lines in line dict.= %d\n", | |
972 stringdict_count(titleLineDict) ); | |
973 printDict(titleLineDict); // print title lines | |
974 printf( "\n\n" ); | |
975 | |
976 printf( "title count = %d, includes Secret of Life \n\n", title_count ); | |
977 printf( "title line count = %d, includes Secret of Life \n\n", | |
978 title_line_count ); | |
979 printf( "total1sttextline = %d, \n", total1sttextline ); | |
980 printf( "total1sttextlineb = %d \n", total1sttextlineb ); | |
981 printf( "total1sttableline = %d \n", total1sttableline ); | |
982 printf( "total1stlist1line = %d \n", total1stlist1line ); | |
983 printf( "total1stlist2line = %d \n", total1stlist2line ); | |
984 printf( "total1stlisttabline = %d \n", total1stlisttabline ); | |
985 printf( "total1stcodeline = %d \n", total1stcodeline ); | |
986 } | |
987 | |
988 /* check for error */ | |
989 if (verbose) { | |
990 printf( "PCB.exit_flag = %d (%d for success)\n", PCB.exit_flag, | |
991 AG_SUCCESS_CODE); | |
992 } | |
993 if (PCB.exit_flag != AG_SUCCESS_CODE) { | |
994 fprintf(stderr, "File %s: error at line %d, column %d\n", | |
995 argv[1], | |
996 PCB.line, | |
997 PCB.column); | |
998 return 8; | |
999 } | |
1000 | |
1001 // Write sorted title lines & topics as HTML to intermediate file | |
1002 FILE *intermed; | |
1003 const char *filename = "intermed.html"; | |
1004 /* Open intermediate file */ | |
1005 intermed = fopen(filename ,"w+"); // create intermediate text file | |
1006 if (intermed == NULL) { | |
1007 fprintf(stderr, "Cannot open %s\n", filename); | |
1008 return 9; | |
1009 } | |
1010 if (verbose) { | |
1011 printf( "Writing sorted title lines & topic bodies to " | |
1012 "intermediate file in HTML format...\n"); | |
1013 } | |
1014 writeSortedHtml(intermed); | |
1015 rewind(intermed); | |
1016 | |
1017 /* Create output HTML file, inserting links */ | |
1018 FILE *output; | |
1019 /* Open output file */ | |
1020 output = fopen(argv[2] ,"w"); | |
1021 if (output == NULL) { | |
1022 fprintf(stderr, "Cannot open %s\n", argv[2]); | |
1023 return 10; | |
1024 } | |
1025 | |
1026 if (verbose) { | |
1027 printf( "Writing output file with HTML links...\n"); | |
1028 } | |
1029 | |
1030 int c = 0; | |
1031 int ctest = 0; | |
1032 | |
1033 while ( (c=fgetc(intermed)) != EOF ){ | |
1034 | |
1035 if ( c == 0xA9 ) { // begins link string | |
1036 // printf( "\n Found beginning of link" ); | |
1037 int itest = processLinkString(intermed, output); | |
1038 if (itest !=0) return itest; // error return | |
1039 } | |
1040 else { | |
1041 ctest = fputc( c, output ); // write out current character | |
1042 if (ctest == EOF) return 11; | |
1043 } | |
1044 } | |
1045 | |
1046 fclose(intermed); | |
1047 fclose(output); | |
1048 | |
1049 | |
1050 /* done */ | |
1051 if (verbose) { | |
1052 printf( "All done.\n" ); | |
1053 } | |
1054 return 0; // normal return | |
1055 | |
1056 } /* -- End of main() function -- */ | |
1057 | |
1058 } /* ---- End of embedded C ----------------------------------------- */ | |
1059 | |
1060 |