dthelp: compiler warning and coverity warning fixes
[oweals/cde.git] / cde / programs / dthelp / parser / pass1 / helptag / help.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: help.c /main/5 1998/04/06 13:18:57 mgreess $ */
24 /*   Copyright (c) 1986, 1987, 1988, 1989 Hewlett-Packard Co. */
25 /* Miscellaneous Procedures for HP Tag/TeX translator */
26
27 #include <stdint.h>
28
29 #include "userinc.h"
30 #include "globdec.h"
31
32 #include "LocaleXlate.h"
33 #include "XlationSvc.h"
34
35 void assert_hometopic_exists(M_NOPAR)
36 {
37 static const char hometopic[] = "-HOMETOPIC";
38 char id[SDLNAMESIZ + sizeof(hometopic)];
39 char *string =
40     GetDefaultHeaderString("UntitledElementDefaultHeadingString",
41                            M_SDATA,
42                            "Untitled");
43 if (nohometopic)
44     {
45     char    *pc;
46
47     sprintf(id, "%s%s", sdlReservedName, hometopic);
48     mb_starthelpnode("_HOMETOPIC", id, 1);
49     nohometopic = FALSE;
50     pc = NULL;
51     if (savedtitle)
52         pc = MakeMByteString(savedtitle);
53     fprintf(outfile,
54             "<HEAD CLASS=\"HEAD\" ABBREV=\"%s\"></HEAD>\n</VIRPAGE>\n",
55             pc ? pc : string);
56     if (pc)
57         m_free(pc, "multi-byte string");
58     }
59 m_free(string, "GetDefaultHeaderString return");
60 }
61
62 /* Determine base name for files (i.e., input name without extension).
63    Open output and error files */
64 void fbasename(M_NOPAR)
65 {
66 char *p, *q;
67 int n;
68 char save;
69 char fileListErr[] = "filelist.err";
70
71 m_errfile = NULL;
72 if (m_argc < 2)
73     {
74     m_error("Specify input file");
75     exit(TRUE);
76     }
77
78 if ((m_argc > 2) && (strchr(m_argv[2], 'f') || strchr(m_argv[2], 'F')))
79     filelist = TRUE;
80
81 /* Get installation directory */
82 #define CONTRIB "/usr/dt/bin/"
83
84 /* get our path if we can */
85 /* A hacked up ``which'', just to find our directory */
86 /* fills ``install'' with path to ourself */
87 {
88 char *path, *cp;
89 char buf[200];
90 char patbuf[BUFSIZ];
91 int quit, none;
92
93 quit = 0;
94 none = 1;
95
96 if ( *(m_argv[0]) == '/' )
97     {
98     /* fully qualified path to ourself was specified */
99     if (access(m_argv[0],1) == 0)
100         {
101         /* if full path name exists and is executable */
102         /* get the dirname */
103         for (p = m_argv[0]; *p ; p++) ; /* end of string, (the hard way) */
104         /* backup to dirsep */
105         for (; ; p--)
106             {
107             if (p < m_argv[0]) m_error("Internal Error.");
108             if (*p == dirsep) break; 
109             }
110         p++; /* just past the dirsep */
111         save = *p;
112         *p = M_EOS;
113         install = (char *) m_malloc(strlen(m_argv[0]) + 1,
114                                     "installation directory");
115         strcpy(install, m_argv[0]);
116         *p = save;
117
118         none = 0; /* we've got it. */
119         }
120     else
121         {
122         m_error("Internal Error (which).");
123         }
124     }
125 else
126     {
127     /* not fully specified, check each component of path for ourself */
128     strcpy(patbuf, getenv("PATH"));
129     path = patbuf;
130     cp = path;
131
132     while(1)
133         {
134         cp = strchr(path, ':');
135         if (cp == NULL)
136         quit++;
137         else
138         *cp = '\0';
139         sprintf(buf, "%s/%s", path, m_argv[0]);
140
141         if (access(buf, 1) == 0)
142             {
143             install = (char*) m_malloc(strlen(path) + 1,
144                                        "installation directory");
145             strcpy(install, path);
146             none = 0;
147             }
148         /* else, not an error if we can't find a particular one. */
149
150         path = ++cp;
151         if (quit || !none)
152             {
153             break; /* either out of paths, or we found it. */
154             }
155         }  /* end while */
156     }
157
158 if (none)
159     {
160     /* can't get it, use default */
161     install = (char *) m_malloc(strlen(CONTRIB) + 1,
162                                 "installation directory");
163     strcpy(install, CONTRIB);
164     }
165 /* else -- we've got it */
166 }
167
168 /* Set default working directory (from input filename) */
169 for (p = strchr(m_argv[1], M_EOS); p > m_argv[1] ; p--)
170     if (*(p - 1) == dirsep)
171         break;
172 if (p > m_argv[1])
173     {
174     save = *p;
175     *p = M_EOS;
176     work = (char *) m_malloc(strlen(m_argv[1]) + 1, "working directory");
177     strcpy(work, m_argv[1]);
178     indir = (char *) m_malloc(strlen(m_argv[1]) + 1, "input directory");
179     strcpy(indir, m_argv[1]);
180     *p = save;
181     }
182 else
183     {
184     indir = NULL;
185     }
186
187 /* Build base name */
188 q = strchr(m_argv[1], M_EOS);
189 while ((q > m_argv[1]) && (*q != '.') && (*q != dirsep))
190     q--;
191 defaultext = (LOGICAL) (*q != '.');
192 if (! defaultext) *q = M_EOS;
193 nodirbase = (char *) m_malloc(strlen(p) + 1,
194                               "basename without directory");
195 strcpy(nodirbase, p);
196 /* Get working directory option, if specified */
197 n = strlen(p);
198 base = (char *) m_malloc(n + strlen(".htg") + 1, "basename");
199 strcpy(base, p);
200 base[n] = '.';
201 baseext = base + n + 1;
202 if (! defaultext)
203     if (*(q + 1))
204         *q = '.';
205
206 options(TRUE); /* pluck only length changing optins */
207 if (usingshortnames)
208     {
209     /* Build short versions of basename */
210     /* set up global helpbase and helpext */
211     helpbase = (char *) m_malloc(strlen(work)            +
212                                      BASENAME_LIMIT      +
213                                      PRE_EXTENSION_LIMIT +
214                                      strlen(".ext")      +
215                                      1,
216                                  "help basename");
217     strcpy(helpbase, work);
218     strncat(helpbase, nodirbase, BASENAME_LIMIT);
219     helpext = helpbase + strlen(helpbase);
220     }
221 else
222     { /* Build long names */
223     /* set up global helpbase and helpext */
224     helpbase = (char *) m_malloc(strlen(work)            +
225                                      strlen(nodirbase)   +
226                                      PRE_EXTENSION_LIMIT +
227                                      strlen(".ext")      +
228                                      1,
229                                  "help basename");
230     strcpy(helpbase, work);
231     strcat(helpbase, nodirbase);
232     helpext = helpbase + strlen(helpbase);
233     }
234
235 /* Open error files */
236 if (filelist)
237     {
238     p = mb_malloc(strlen(work)+sizeof(fileListErr));
239     strcpy(p, work);
240     strcat(p, fileListErr);
241     m_openchk(&m_errfile, p, "w");
242     mb_free(&p);
243     }
244 else
245     {
246     strcpy(helpext, ".err");
247     m_openchk(&m_errfile, helpbase, "w");
248     }
249 }
250
251
252 /* This procedure starts a CHAPTER */
253 void chapstart(id)
254 M_WCHAR *id;
255 {
256 M_WCHAR *p, *q, *wc;
257 int i;
258 char *mbyte, *pc;
259 int   length;
260
261 char *chapterPrefixString =
262   GetDefaultHeaderString("ChapterElementDefaultHeadingString",
263                          M_SDATA,
264                          "Chapter");
265 char *chapterSuffixString =
266   GetDefaultHeaderString("ChapterSuffixElementDefaultHeadingString",
267                          M_SDATA,
268                          "");
269
270 rsectseq = FALSE;
271 chapst = FALSE;
272 chapinc = 0;
273 chapter++;
274 m_itoa(chapter, chapstring);
275
276 savid = checkid(id);
277 iderr = FALSE;
278
279 figno = 0;
280 tableno = 0;
281 footnoteno = 1;
282 fprintf(stderr,
283         "\n%s %s%s. ",
284         chapterPrefixString,
285         chapstring,
286         chapterSuffixString);
287 m_free(chapterPrefixString, "GetDefaultHeaderString return");
288 if (*chapterSuffixString)
289     m_free(chapterSuffixString, "GetDefaultHeaderString return");
290 }
291
292
293 /* Called at end of manual to report terms that occurred in the document
294    but not entered in the glossary */
295 void checkgloss(M_NOPAR)
296 {
297 int n;
298 M_WCHAR id[MAXTERM + 1];
299 M_TRIE *node[MAXTERM + 1];
300 M_TRIE *current;
301
302 if (! gtree.data) return;
303 n = 0;
304 current = gtree.data;
305 while (TRUE)
306     {
307     id[n] = current->symbol;
308     node[n] = current->next;
309     if (! id[n])
310         {
311         if ((intptr_t) current->data >= 0)
312             m_err1("No glossary definition for %s", id);
313         current = current->next;
314         while (! current)
315             {
316             n--;
317             if (n < 0) return;
318             current = node[n];
319             }
320         }
321     else
322         {
323         current = current->data;
324         n++;
325         }
326     }
327 }
328
329                 
330 /* End Error Message macro \starterrmsg call, check to see if Error Message
331    head is user specified or default */
332 void checkmsghead(M_NOPAR)
333 {
334 char *string =
335     GetDefaultHeaderString("MessagesElementDefaultHeadingString",
336                            M_SDATA,
337                            "Messages");
338 if (emsghead == DEFHEAD)
339     {  /* head not output yet */
340     fprintf(outfile, "<HEAD CLASS=\"HEAD\">%s</HEAD>\n", string);
341     emsghead = FALSE;
342     }
343 else if (emsghead == USERHEAD)
344     {  /* user specified head */
345     emsghead = FALSE;
346     }
347 m_free(string, "GetDefaultHeaderString return");
348 }  /* end checkmsghead() */
349
350
351 /* construct a qualified file name */
352 #if defined(M_PROTO)
353 static int mb_getqualified(char *qualname, char *unqualname)
354 #else
355 static int mb_getqualified(qualname, unqualname)
356 char *qualname;
357 char *unqualname;
358 #endif
359 {
360 #if defined(hpux) || defined(_AIX) || defined(sun) || defined(USL) || defined(__uxp__) || defined(__osf__) || defined(linux) || defined(CSRG_BASED)
361 FILE *f;
362 #endif
363 char fn[FNAMELEN];
364 char tokstr [ 20 ], *gp, *p, *pp, *fnp, curdir[FNAMELEN-1];
365 int roomleft = FNAMELEN - 1;
366
367 if (!unqualname)
368     {
369     *qualname = M_EOS;
370     return( 0 );
371     }
372
373 if (strlen(unqualname) < (size_t) FNAMELEN)
374     strcpy(fn, unqualname );
375 else
376     {
377     m_mberr1("Internal Error. File name too long for qualifying: %s",
378              unqualname);
379     return (-1);
380     }
381
382 fnp = fn;
383
384 #if defined(hpux) || defined(_AIX) || defined(sun) || defined(USL) || defined(__uxp__) || defined(__osf__) || defined(linux) || defined(CSRG_BASED)
385 qualname[0] = '\0';
386 gp = qualname + strlen(qualname);
387 roomleft = roomleft - strlen(qualname);
388
389 /* if path is from root, tack that on, else tack on the current
390  directory (for the referenced drive, if MS-DOS) */
391 /* We assume FNAMELEN is at least three (3), so no range checking here */
392 if ( *fnp == CSEP )
393     {
394     strcat(qualname, SSEP);
395     roomleft--;
396     ++fnp;
397     }
398 else
399     {
400     f = popen("/bin/pwd", "r");
401     fscanf(f, "%s", gp);
402     pclose(f);
403     if (strlen(gp) >= (size_t) roomleft)
404         {
405         m_mberr1("Internal error: possible stray pointer in getqualified(): %s",
406                  gp);
407         return(-1);
408         }
409     strcat(qualname,SSEP);
410     roomleft--;
411     }
412 #else
413 /* if MS-DOS, force to upper case, then get drive spec */
414 strupr ( fn );
415 if ( fn[1] == ':' ) {
416 strncpy ( qualname, fn, 2 );
417 fnp += 2;
418 }
419 else {
420 getcwd(qualname, roomleft);
421 }
422 qualname[2] = '\0';
423 gp = qualname + strlen ( qualname );
424 roomleft = roomleft - strlen ( qualname );
425 /* if path is from root, tack that on, else tack on the current
426  directory (for the referenced drive, if MS-DOS) */
427 if ( *fnp == CSEP ) {
428 strcat ( qualname, SSEP );
429 roomleft--;
430 ++fnp;
431 }
432 else {
433 /* assume current directory always !!! */
434 *gp = CSEP;
435 getcwd(curdir, FNAMELEN-1);
436 if (*curdir != *qualname) {
437   m_err1("Relative directory %s for non-current drive, can't qualify",
438           unqualname);
439   return (-1);
440   }
441 if (strlen(curdir) > 3) {
442   if ((strlen(curdir+3)+1) < roomleft) {  /* "1" for SSEP */
443     strcpy( gp+1, curdir+3 );
444     strcat ( qualname, SSEP );
445     roomleft = roomleft - strlen(curdir+3) - 1;  /* "1" for SSEP */
446     }
447   else {
448     m_err1("Internal error. File name too long for qualifying: %s",
449       unqualname);
450     return (-1);
451     }
452   }
453 }
454 #endif
455
456 strcpy(tokstr, " \r\n\t");
457 strcat(tokstr, SSEP);
458 p = NULL;
459 do  {
460     p = strtok(( p == NULL ) ? fnp : NULL, tokstr);
461     if ( p == NULL ) break;
462     if ( *p == '.' ) /* alias */
463         {
464         if ( *(p+1) == '.' ) /* parent */
465             {
466             *strrchr(qualname, CSEP) = '\0';
467             pp = strrchr(qualname, CSEP);
468             if (pp == NULL) /* FAIL */
469                 {
470                 m_mberr1("Internal error. Failed in qualifying %s", unqualname);
471                 return ( -1 );
472                 }
473             else
474                 {
475                 *(pp+1) = '\0';
476                 }
477             }
478         }
479     else
480         {
481         if ((strlen(p)+1) < (size_t) roomleft)
482             {  /* "1" for SSEP */
483             strcat(qualname, p);
484             strcat(qualname, SSEP);
485             roomleft = roomleft - strlen(p) - 1;
486             }
487         else
488             {
489             m_mberr1("Internal error. File name too long for qualifying: %s",
490                      unqualname);
491             return (-1);
492             }
493         }
494     }
495 while (1);
496 *strrchr(qualname, CSEP) = '\0';
497
498 #if defined(hpux) || defined(_AIX) || defined(sun) || defined(USL) || defined(__uxp__) || defined(__osf__) || defined(linux) || defined(CSRG_BASED)
499 #else
500 strupr ( qualname );
501 #endif
502
503 return ( 0 );
504 }  /* end mb_getqualified */
505
506
507 int getqualified (qualname, unqualname)
508 M_WCHAR *qualname;
509 M_WCHAR *unqualname;
510 {
511 int retval;
512 char mb_qualname[FNAMELEN],
513      mb_unqualname[FNAMELEN];
514
515 wcstombs(mb_qualname, qualname, FNAMELEN);
516 wcstombs(mb_unqualname, unqualname, FNAMELEN);
517
518 retval = mb_getqualified(mb_qualname, mb_unqualname);
519
520 mbstowcs(qualname, mb_qualname, FNAMELEN);
521 mbstowcs(unqualname, mb_unqualname, FNAMELEN);
522
523 return retval;
524 }
525
526
527 /* handle the common link and graphic code for <p> and <image> */
528 void
529 handle_link_and_graphic(parent,
530                         gentity,
531                         gposition,
532                         ghyperlink,
533                         glinktype,
534                         gdescription)
535 M_WCHAR *parent, *gentity, *gposition, *ghyperlink, *glinktype, *gdescription;
536 {
537 unsigned char etype, wheredef;
538 char *mb_content, *ssi, id[32];
539 static M_WCHAR empty = M_EOS;
540 char *leftright;
541
542 /* handle graphic specific code */
543 /* initialize some stuff first:
544 - file is the entity name,
545 - f_file is the content of the entity, used only if f_content nonNULL
546 - f_content is f_file with the relative pathname, initialized to NULL,
547 - f_contqual is fully qualified f_file, assigned ONLY IF
548   f_content nonNULL
549 */
550 file_ent = FALSE;
551 f_content = NULL;
552 f_contqual[0] = M_EOS;
553
554 /* get the position, default to left */
555 leftright = "LEFT";
556 if (gposition)
557     {
558     M_WCHAR *wc_left, *wc_right;
559
560     wc_right = MakeWideCharString(QRIGHT);
561     if (!m_wcupstrcmp(gposition, wc_right))
562         {
563         leftright = "RIGHT";
564         }
565     else
566         {
567         wc_left = MakeWideCharString(QLEFT);
568         if (m_wcupstrcmp(gposition, wc_left))
569             {
570             m_err1("Invalid value for gposition: `%s'", gposition);
571             }
572         m_free(wc_left,"wide character string");
573         }
574     m_free(wc_right,"wide character string");
575     }
576
577 /* check ENTITY and determine the figure type  */
578 if (gentity)
579     {
580     m_lookent(gentity, &etype, &f_file, &wheredef);
581     if (etype != M_SYSTEM)
582         {
583         M_WCHAR *wc_entsystem, *wc_entkw, *wc_stago, *wc_tagc;
584
585         wc_entsystem = MakeWideCharString(m_entsystem);
586         wc_entkw = MakeWideCharString(m_entkw);
587         wc_stago = MakeWideCharString(m_stago);
588         wc_tagc = MakeWideCharString(m_tagc);
589         m_err6(
590             "%s not a %s %s, as required for the ENTITY parameter of %s%s%s",
591                gentity,
592                wc_entsystem,
593                wc_entkw,
594                wc_stago,
595                m_parent(0),
596                wc_tagc);
597         m_free(wc_entsystem,"wide character string");
598         m_free(wc_entkw,"wide character string");
599         m_free(wc_stago,"wide character string");
600         m_free(wc_tagc,"wide character string");
601         }
602     else
603         {
604         file_ent = TRUE;
605         f_content = searchforfile(f_file);
606         if (f_content)
607             {
608             if (getqualified(f_contqual, f_content))
609                 {
610                 /* unsuccessful qual */
611                 if (w_strlen(f_content) < FNAMELEN)
612                     w_strcpy(f_contqual, f_content);
613                 else
614                     {
615                     m_err1("Internal error. File name too long: %s",
616                            f_content);
617                     m_exit(m_errexit);
618                     }
619                 }
620             }
621         else
622             {
623             m_err2("Can't find file %s (declared in entity %s)",
624                    f_file,
625                    gentity);
626             }
627         }
628     if (!f_content) f_content = &empty;
629
630     mb_content = MakeMByteString(f_content);
631     sprintf(id, "%s%d", sdlReservedName, NextId());
632     ssi = MakeMByteString(m_parent(0));
633     fprintf(outfile, "<HEAD SSI=\"%s-GRAPHIC-%s\">", ssi, leftright);
634     if (ghyperlink)
635         HandleLink(ghyperlink, glinktype, gdescription);
636     fprintf(outfile, "<SNREF>\n<REFITEM RID=\"%s\" ", id);
637     fputs("CLASS=\"FIGURE\"", outfile);
638     AddToSNB(id, mb_content);
639     m_free(mb_content,"multi-byte string");
640     }
641
642 /* and finish the position now */
643 if (gposition)
644     {
645     fprintf(outfile, " SSI=\"GRPH-%s\"", leftright);
646     }
647
648 if (gentity)
649     {
650     fputs("></REFITEM></SNREF>", outfile);
651     if (ghyperlink)
652         fputs("</LINK>", outfile);
653     fputs("</HEAD>", outfile);
654     }
655
656 if (!ghyperlink && (glinktype || gdescription))
657     {
658     m_eprefix();
659     fprintf(stderr,
660            "Error: %sP%s ghyperlink was undefined.\n",
661            m_stago,
662            m_tagc);
663     fprintf(m_errfile,
664            "Error: %sP%s ghyperlink was undefined.\n",
665            m_stago,
666            m_tagc);
667     fprintf(stderr,
668      "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
669            QJUMP,
670            QJUMPNEWVIEW,
671            QDEFINITION,
672            QEXECUTE,
673            QAPPDEFINED,
674            QMAN);
675     fprintf(m_errfile,
676      "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
677            QJUMP,
678            QJUMPNEWVIEW,
679            QDEFINITION,
680            QEXECUTE,
681            QAPPDEFINED,
682            QMAN);
683     m_errline("Use ``ghyperlink='' if the value contains non-alphabetics");
684     m_esuffix();
685     }
686 }
687
688 /* Process an item in a list */
689 #if defined(M_PROTO)
690 void Item(M_WCHAR *id)
691 #else
692 void Item(id)
693 M_WCHAR *id;
694 #endif
695 {
696 char orderString[32];
697 static char *ROMAN0[] =
698     {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
699 static char *ROMAN10[] =
700     {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
701 static char *ROMAN100[] =
702     {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
703 static char ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
704 static char *roman0[] =
705     {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
706 static char *roman10[] =
707     {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
708 static char *roman100[] =
709     {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
710 static char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
711 static char numbers[] = "0123456789";
712 static char romanString[]  = "ROMAN";
713 static char alphaString[]  = "ALPHA";
714 static char arabicString[] = "ARABIC";
715 int      count, metaCount;
716 char    *item_id;
717 char     label_id[SDLNAMESIZ+10];
718 int      listtype;
719 char    *type;
720 char    *loose;
721 char    *first;
722 LOGICAL  isBullet, isLoose, isFirst;
723 int     *pThisBulletId;
724 char     ssi[BIGBUF];
725
726 if (listitems[list].firstitem)
727     {
728     listitems[list].firstitem = FALSE;
729     }
730
731 count = ++lastlist->lastlist->count;
732 if (count > 999) count = 999; /* holy cow!  Big list. */
733 isFirst = FALSE;
734 if (count == 1)
735     {
736     isFirst = TRUE;
737     first = "FIRST-";
738     }
739 else
740     first = "";
741
742 isLoose = FALSE;
743 if (lastlist->lastlist->space == TIGHT)
744     loose = "TIGHT";
745 else
746     {
747     isLoose = TRUE;
748     loose = "LOOSE";
749     }
750
751 isBullet = FALSE;
752 listtype = lastlist->lastlist->type;
753 if (listtype == BULLET)
754     isBullet = TRUE;
755
756 if ((listtype != PLAIN) && (listtype != MILSPEC))
757     { /* don't emit label for type==PLAIN and type==MILSPEC */
758     if (isBullet)
759         {
760         if (isLoose)
761             {
762             if (isFirst)
763                 pThisBulletId = &firstLooseBulletId;
764             else
765                 {
766                 looseBulletIdIndex = (- looseBulletIdIndex) + 1;
767                 pThisBulletId = &looseBulletId[looseBulletIdIndex];
768                 }
769             }
770         else
771             {
772             if (isFirst)
773                 pThisBulletId = &firstBulletId;
774             else
775                 {
776                 bulletIdIndex = (- bulletIdIndex) + 1;
777                 pThisBulletId = &bulletId[bulletIdIndex];
778                 }
779             }
780         if (*pThisBulletId)
781             { /* use an existing block containing a bullet */
782             strcpy(label_id, sdlReservedName);
783             m_itoa(*pThisBulletId, label_id + SDLNAMESIZ - 1);
784             }
785         else
786             {
787             *pThisBulletId = NextId();
788             strcpy(label_id, sdlReservedName);
789             m_itoa(*pThisBulletId, label_id + SDLNAMESIZ - 1);
790             if (needFData)
791                 {
792                 fputs("<FDATA>\n", outfile);
793                 needFData = FALSE;
794                 }
795             fprintf(outfile,
796                     "<BLOCK ID=\"%s\" CLASS=\"ITEM\" TIMING=\"ASYNC\" ",
797                     label_id);
798             fprintf(outfile,
799                     "SSI=\"%s%s-BULLET\">\n<P><SPC NAME=\"[bull  ]\">",
800                     first,
801                     loose);
802             fputs("</P>\n</BLOCK>\n", outfile);
803             }
804         }
805     else
806         {
807         strcpy(label_id, sdlReservedName);
808         m_itoa(NextId(), label_id + SDLNAMESIZ - 1);
809         if (needFData)
810             {
811             fputs("<FDATA>\n", outfile);
812             needFData = FALSE;
813             }
814         fprintf(outfile, "<BLOCK ID=\"%s\" CLASS=\"ITEM\" SSI=\"", label_id);
815         }
816     }
817
818 item_id = NULL;
819 if (listtype == ORDER)
820     {
821     orderString[0] = '\0';
822     switch (lastlist->lastlist->order)
823         {
824         case UROMAN:
825             strcpy(orderString, ROMAN100[count / 100]);
826             strcat(orderString, ROMAN10[(count / 10) % 10]);
827             strcat(orderString, ROMAN0[count % 10]);
828             type = romanString;
829             break;
830         case UALPHA:
831             metaCount = 1;
832             while ((count -= 26) > 0) metaCount++;
833             count = lastlist->lastlist->count;
834             if (count > 999) count = 999;
835             count -= 1;
836             count %= 26;
837             while (--metaCount >= 0) strncat(orderString, &ALPHABET[count], 1);
838             type = alphaString;
839             break;
840         case ARABIC:
841             if (metaCount = (count / 100))
842                 strncat(orderString, &numbers[metaCount], 1);
843             if (metaCount || ((count / 10) % 10))
844                 strncat(orderString, &numbers[(count / 10) % 10], 1);
845             strncat(orderString, &numbers[count % 10], 1);
846             type = arabicString;
847             break;
848         case LROMAN:
849             strcpy(orderString, roman100[count / 100]);
850             strcat(orderString, roman10[(count / 10) % 10]);
851             strcat(orderString, roman0[count % 10]);
852             type = romanString;
853             break;
854         case LALPHA:
855             metaCount = 1;
856             while ((count -= 26) > 0) metaCount++;
857             count = lastlist->lastlist->count;
858             if (count > 999) count = 999;
859             count -= 1;
860             count %= 26;
861             while (--metaCount >= 0) strncat(orderString, &alphabet[count], 1);
862             type = alphaString;
863             break;
864         }
865     fprintf(outfile,
866             "%s%s-%s\">\n<P>%s%c",
867             first,
868             loose,
869             type,
870             orderString, 
871             lastlist->lastlist->punct == DOTPUNCT ? '.' : ')' );
872     if (id)
873         {
874         char buffer[400];
875         M_WCHAR *wc;
876
877         sprintf(buffer, "Item %s", orderString);
878         wc = MakeWideCharString(buffer);
879         w_strcpy(xrefstring, wc);
880         m_free(wc,"wide character string");
881
882         xstrlen = w_strlen(xrefstring);
883         m_getline(&xrffile, &xrfline);
884         if (xrffile == NULL)
885             {
886             /* set to primary input */
887             xrffile = inputname;
888             }
889
890         setid(id,
891              TRUE,
892              FALSE,
893              inchapter,
894              chapstring,
895              xrffile,
896              xrfline, TRUE);
897
898         item_id = MakeMByteString(id);
899         }
900     }
901 else
902     { /* Bullet, Check or Plain list */
903     if (id) m_error("Cross-reference ID in non-ORDER list not allowed");
904     /* already handled Bullet */
905     if (listtype == CHECK)
906         {
907         fprintf(outfile,
908                 "%s%s-CHECK\">\n<P><SPC NAME=\"[check ]\">",
909                 first,
910                 loose);
911         }
912     /* don't emit label for listtype==PLAIN and listtype==MILSPEC */
913     }
914
915 if ((listtype != PLAIN) && (listtype != MILSPEC) && (listtype != BULLET))
916     fputs("</P>\n</BLOCK>\n", outfile);
917
918 sprintf(ssi, "%s%s", first, loose);
919 if ((listtype == PLAIN) || (listtype == MILSPEC))
920     PushForm("ITEM", ssi, item_id);
921 else
922     PushForm2("ITEM", ssi, label_id, item_id);
923
924 if (item_id)
925     m_free(item_id, "multi-byte string");
926 }
927
928
929 /* Start a rsect */
930 void rsectstart(id)
931 M_WCHAR *id;
932 {
933 savid = checkid(id);
934 iderr = FALSE;
935 rsectseq = TRUE;
936 chapst = TRUE;
937 }  /* END procedure rsectstart  */
938
939
940 /* Called at the end of a chapter, appendix, or section to end an open
941    sequence of rsects */
942 void rseqend(M_NOPAR)
943 {
944 if (rsectseq)
945     --thisnodelevel;
946 rsectseq = FALSE;
947 }
948
949
950 /* Follow search path to find a file, returning qualified name */
951 M_WCHAR *searchforfile(file)
952 M_WCHAR *file;
953 {
954 M_WCHAR *filename;
955 SEARCH  *searchp;
956 char    *mb_file, mb_filename[2048];
957 int     dir_leng,file_leng;
958
959 mb_file = MakeMByteString(file);
960 if (! access(mb_file, READABLE))
961     {
962     filename = (M_WCHAR *)
963         m_malloc(w_strlen(file) + 1, "figure/icon filename");
964     w_strcpy(filename, file);
965     m_free(mb_file,"multi-byte string");
966     return(filename);
967     }
968
969 file_leng = strlen(mb_file);
970 for (searchp = path; searchp ; searchp = searchp->next)
971     {
972     if (((dir_leng = strlen(searchp->directory)) + file_leng) >= 2048)
973         {
974         M_WCHAR *wc;
975
976         wc = MakeWideCharString(searchp->directory);
977         m_err2("%s and %s overflow the file name space", wc, file);
978         m_free(wc,"wide character string");
979         continue;
980         }
981     strcpy(mb_filename, searchp->directory);
982     strcpy(mb_filename+dir_leng, mb_file);
983     if (! access(mb_filename, READABLE))
984         {
985         m_free(mb_file,"multi-byte string");
986         return(MakeWideCharString(mb_filename));
987         }
988     }
989
990 m_free(mb_file,"multi-byte string");
991 return(NULL);
992 }
993
994
995 /* Start a new helpnode */
996 #if defined(M_PROTO)
997 void starthelpnode(M_WCHAR *ssi,
998                    M_WCHAR *id,
999                    int      level)
1000 #else
1001 void starthelpnode(ssi, id, level)
1002 M_WCHAR *ssi;
1003 M_WCHAR *id;
1004 int      level;
1005 #endif
1006 {
1007 int i;
1008 char *mbyte, *mb_ssi;
1009 char mb_nodeid[NODEID_LENGTH+1], nodenum[32];
1010
1011 if (outfile != m_outfile)
1012     {
1013     m_error("Internal warning:  Outfile has been redirected.");
1014     m_errcnt--;
1015     }
1016
1017 fflush(m_outfile);
1018
1019 mb_ssi = MakeMByteString(ssi);
1020
1021 /* we can't use the bullet block across virpage boundaries */
1022 bulletId[0]        = 0;
1023 bulletId[1]        = 0;
1024 looseBulletId[0]   = 0;
1025 looseBulletId[1]   = 0;
1026 firstBulletId      = 0;
1027 firstLooseBulletId = 0;
1028
1029 /* might as well always start with id 0 (we flip first) */
1030 bulletIdIndex      = 1;
1031 looseBulletIdIndex = 1;
1032
1033 if ((id == NULL) || (*id == 0))
1034     {
1035     strcpy(mb_nodeid, sdlReservedName);
1036     m_itoa(NextId(), nodenum);
1037     strcpy(mb_nodeid + SDLNAMESIZ - 1, nodenum);
1038     mbstowcs(nodeid, mb_nodeid, NODEID_LENGTH);
1039     }
1040 else
1041     {
1042     w_strncpy(nodeid, id, NODEID_LENGTH);
1043     wcstombs(mb_nodeid, id, NODEID_LENGTH);
1044     }
1045
1046 fprintf(outfile,
1047 "<VIRPAGE ID=\"%s\" LEVEL=\"%d\" LANGUAGE=\"%s\" CHARSET=\"%s\" DOC-ID=\"%s\" SSI=\"%s\">\n",
1048         mb_nodeid,
1049         level,
1050         GetLanguage(),
1051         GetCharset(),
1052         docId,
1053         mb_ssi);
1054 m_free(mb_ssi,"multi-byte string");
1055 snbstart = ftell(outfile);
1056 } /* End starthelpnode(id) */
1057
1058
1059 #if defined(M_PROTO)
1060 void mb_starthelpnode(char   *ssi,
1061                       char   *id,
1062                       int     level)
1063 #else
1064 void mb_starthelpnode(ssi, id, level)
1065 char   *ssi;
1066 char   *id;
1067 int     level;
1068 #endif
1069 {
1070 M_WCHAR *wc_ssi, *wc_id;
1071
1072 wc_ssi = NULL;
1073 if (ssi)
1074     wc_ssi = MakeWideCharString(ssi);
1075 wc_id = NULL;
1076 if (id)
1077     wc_id  = MakeWideCharString(id);
1078 starthelpnode(wc_ssi, wc_id, level);
1079 if (wc_ssi)
1080     m_free(wc_ssi,"wide character string");
1081 if (wc_id)
1082     m_free(wc_id,"wide character string");
1083 }
1084
1085
1086 /* Start a labeled list */
1087 void StartLabList(spacing, longlabel)
1088 M_WCHAR *spacing;
1089 M_WCHAR *longlabel;
1090 {
1091        char *mb_spacing;
1092 static char  def_spacing[] = "LOOSE";
1093        char  ssi[32];
1094
1095 if (list >= MAXLISTLEV)
1096     m_error("Nesting of <LIST> and <LABLIST> too deep");
1097
1098 if (spacing)
1099     mb_spacing = MakeMByteString(spacing);
1100 else
1101     mb_spacing = def_spacing;
1102
1103 sprintf(ssi, "LABELED-%s", mb_spacing);
1104 PushForm("LIST", ssi, NULL);
1105
1106 if (mb_spacing != def_spacing)
1107     mb_free(&mb_spacing);
1108
1109 list++;
1110
1111 listitems[list].firstitem = TRUE;
1112 listitems[list].longlabel = vlonglabel(longlabel);
1113
1114 if (list <= MAXLISTLEV)
1115     {
1116     if (vspacing(spacing) == TIGHT)
1117         {
1118         lablisttight[list] = TRUE;
1119         }
1120     else
1121         {
1122         lablisttight[list] = FALSE;
1123         }
1124     }
1125 }
1126
1127
1128 /* Start a list */
1129 #if defined(M_PROTO)
1130 void StartList(M_WCHAR *type,
1131                M_WCHAR *order,
1132                M_WCHAR *spacing,
1133                M_WCHAR *cont)
1134 #else
1135 void StartList(type, order, spacing, cont)
1136 M_WCHAR *type, *order, *spacing, *cont;
1137 #endif
1138 {
1139 LIST *nextlist;
1140 CONTCHAIN *chain;
1141 CONTCHAIN *xchain;
1142 M_WCHAR *wc;
1143 char *mb_spacing;
1144 static char def_spacing[]  = "LOOSE";
1145 char *list_type;
1146 char  ssi[BIGBUF];
1147
1148 if (spacing)
1149     {
1150     mb_spacing = MakeMByteString(spacing);
1151     }
1152 else
1153     {
1154     mb_spacing = def_spacing;
1155     }
1156
1157 list++;
1158
1159 if (list > MAXLISTLEV)
1160     m_error("Nesting of <LIST> and <LABLIST> too deep");
1161
1162 if (! lastlist->started && cont)
1163     {
1164     m_error("No previous list to continue");
1165     cont = NULL;
1166     }
1167
1168 if (cont)
1169     {
1170     if (order && (vordertype(order) != lastlist->order))
1171         {
1172         m_error("Unable to continue a list and change the numbering scheme");
1173         cont = NULL;
1174         }
1175
1176     if (type && (vtype(type) != lastlist->type))
1177         {
1178         m_error("Unable to continue a list and change its type");
1179         cont = NULL;
1180         }
1181     }
1182
1183 if (! cont)
1184     { /* clear old list? */
1185     for (chain = lastlist->chain; chain ; chain = xchain)
1186         {
1187         xchain = chain->next;
1188         m_free(chain, "list chain");
1189         }
1190     lastlist->chain = NULL;
1191     lastlist->count = 0;
1192     }
1193
1194 /* If outermost list, initialize according to current defaults */
1195 if (! cont && lastlist == &outlist)
1196     {
1197     outlist.type       = vtype(NULL);
1198     outlist.order      = vordertype(NULL);
1199     outlist.count      = 0;
1200     outlist.space      = vspacing(NULL);
1201     outlist.punct      = DOTPUNCT;
1202     }
1203
1204 if (type) lastlist->type = vtype(type);
1205
1206 if (order)
1207     {
1208     lastlist->type = ORDER;
1209     lastlist->order = vordertype(order);
1210     }
1211
1212 switch (lastlist->type)
1213     {
1214     case MILSPEC:
1215     case PLAIN:
1216         list_type = "PLAIN";
1217         break;
1218     case CHECK:
1219         list_type = "CHECK";
1220         break;
1221     case ORDER:
1222         list_type = "ORDER";
1223         break;
1224     case BULLET:
1225     default:
1226         list_type = "BULLET";
1227     }
1228 sprintf(ssi, "%s-%s", list_type, mb_spacing);
1229
1230 PushForm("LIST", ssi, NULL);
1231
1232 if (mb_spacing != def_spacing)
1233     m_free(mb_spacing, "multi-byte string");
1234
1235
1236 lastlist->space = LOOSE;
1237 if (spacing && ! m_wcmbupstrcmp(spacing, QTIGHT)) lastlist->space = TIGHT;
1238
1239 if (type && order && m_wcmbupstrcmp(type, QORDER))
1240   m_err2("Incompatible specification for list: %s and %s", type, order);
1241
1242 if (lastlist->type == ORDER)
1243     {
1244     chain = (CONTCHAIN *) m_malloc(sizeof(CONTCHAIN), "list chain");
1245     chain->next = lastlist->chain;
1246     lastlist->chain = chain;
1247     chain->where = ftell(outfile);
1248     }
1249
1250 lastlist->started         = TRUE;
1251 listitems[list].firstitem = TRUE;
1252
1253 /* Prepare for sublist */
1254 nextlist = (LIST *) m_malloc(sizeof(LIST), "list structure");
1255 nextlist->lastlist = lastlist;
1256 nextlist->type = lastlist->type;
1257 nextlist->punct = lastlist->punct;
1258 if (lastlist->type == ORDER)
1259     {
1260     nextlist->order = lastlist->order + 1;
1261     if (nextlist->order > LROMAN)
1262         {
1263         nextlist->order = ARABIC;
1264         nextlist->punct = PARENPUNCT;
1265         }
1266     }
1267 else nextlist->order = lastlist->order;
1268 nextlist->count = 0;
1269 nextlist->space = lastlist->space;
1270 nextlist->started = FALSE;
1271 nextlist->where = FIRST;
1272 nextlist->chain = NULL;
1273 lastlist = nextlist;
1274 }
1275
1276
1277 void EndList()
1278 {
1279 LIST *curlist ;
1280 CONTCHAIN *chain, *xchain ;
1281 char *ncols;
1282
1283 curlist = lastlist->lastlist ;
1284
1285 if ((curlist->type == PLAIN) || (curlist->type == MILSPEC))
1286     PopForm();
1287 else
1288     PopForm2();
1289
1290 list-- ;
1291
1292 for (chain = lastlist->chain ; chain ; chain = xchain)
1293     {
1294     xchain = chain->next ;
1295     m_free(chain, "list chain") ;
1296     }
1297 m_free(lastlist, "list structure") ;
1298 lastlist = curlist ;
1299 for (chain = lastlist->chain ; chain ; chain = chain->next)
1300     {
1301     if (lastlist->count > 999)
1302         {
1303         m_error("Unable to support more than 999 items in an ordered list") ;
1304         lastlist->count = 999 ;
1305         }
1306     }
1307 if (lastlist->type == BULLET) bulcount-- ;
1308 }
1309
1310
1311 /* Open and initialize TeX file */
1312 void texinit(M_NOPAR)
1313 {
1314 LOGICAL init = TRUE;
1315 unsigned char type;
1316 M_WCHAR *content;
1317 unsigned char wheredef;
1318 M_WCHAR *name;
1319 M_WCHAR *qfile;
1320 LOGICAL icon;
1321 SEARCH *searchp;
1322 char *p;
1323 int ic;
1324 int i;
1325 M_WCHAR wsl;
1326 M_WCHAR *wc;
1327
1328 /* Check .XRF file */
1329 strcpy(helpext, ".xrh");
1330 xrf = fopen(helpbase, "r");
1331 if (! xrf) rebuild = TRUE;
1332 else
1333     {
1334     fscanf(xrf, "\\gobble\001");
1335     for (p = m_signon; *p ; p++)
1336         {
1337         ic = getc(xrf);
1338         if (ic != (int) *p)
1339             {
1340             m_errline(
1341         "Output files from different version of Tag, regenerating. . .\n");
1342             fclose(xrf);
1343             xrf = NULL;
1344             rebuild = TRUE;
1345             break;
1346             }
1347         }
1348     }
1349 if (xrf)
1350     while ((ic = getc(xrf)) != EOF)
1351         if (ic == '\n') break;
1352 if (xrf && ic !=EOF)
1353     while ((ic = getc(xrf)) != EOF)
1354         if (ic == '\n') break;
1355
1356 rebuild = TRUE;
1357
1358 /* Open output files */
1359 strcpy(helpext, ".sdl");
1360 m_openchk(&m_outfile, helpbase, "w");
1361 outfile = m_outfile;
1362
1363 savehelpfilename = (M_WCHAR *)m_malloc(strlen(helpbase)+1, "help file name");
1364 mbstowcs(savehelpfilename, helpbase, strlen(helpbase) + 1);
1365
1366 /* index file */
1367 strcpy(helpext, ".idx");
1368 m_openchk(&indexfp, helpbase, "wb");
1369
1370 /* system notation block file */
1371 strcpy(helpext, ".snb");
1372 m_openchk(&snbfp, helpbase, "wb");
1373
1374 while (name = m_cyclent(init, &type, &content, &wheredef))
1375     {
1376     init = FALSE;
1377     qfile = NULL;
1378     icon = FALSE;
1379
1380     if (type == M_SYSTEM)
1381         qfile = searchforfile(content);
1382
1383     if (qfile) m_free(qfile, "figure filename");
1384
1385     if (type == M_SYSTEM)
1386         {
1387         mbtowc(&wsl, "/", 1);
1388
1389         if (w_strchr(content, wsl))
1390             {
1391             m_err2("Avoid directory names in FILE entity %s: %s",
1392                    name,
1393                    content);
1394             m_errline("(Use the SEARCH option instead)\n");
1395             }
1396         }
1397     }
1398
1399 /* Include cross-reference file */
1400 strcpy(helpext, ".xrh");
1401 loadxref();
1402 postpreamble = ftell(outfile);
1403 }
1404
1405
1406 /* Lookup localized header string entity as defined (by default) in
1407    locallang.ent.  If the the header string was not found, or it was
1408    not of type "desiredType", return the default.
1409
1410    If the entity is of type file (M_SYSTEM) then if the content is not
1411    empty search the path for the file.  If the file is found, return
1412    its name else return an empty string.
1413
1414    If this routine returns anything other than the empty string (""),
1415    the string returned must be m_free'd.
1416 */
1417 char *
1418 #if defined(M_PROTO)
1419 GetDefaultHeaderString(
1420     char          *elementName,
1421     unsigned char  desiredType,
1422     char          *defaultString )
1423 #else
1424 GetDefaultHeaderString(elementName, desiredType, defaultString)
1425 char          *elementName;
1426 unsigned char  desiredType;
1427 char          *defaultString;
1428 #endif
1429 {
1430 unsigned char type,wheredef;
1431 M_WCHAR *content;
1432 M_WCHAR *path;
1433 M_WCHAR *wc_elementName;
1434 char    *mb_content;
1435 char    *retval;
1436
1437 wc_elementName = MakeWideCharString(elementName);
1438 if (m_lookent(wc_elementName, &type, &content, &wheredef))
1439     {
1440     if (type == desiredType)
1441         {
1442         if (type == M_SDATA)
1443             {
1444             m_free(wc_elementName,"wide character string");
1445             mb_content = MakeMByteString(content);
1446             if (!*mb_content)
1447                 {
1448                 m_free(mb_content,"multi-byte string");
1449                 return "";
1450                 }
1451             else
1452                 return mb_content;
1453             }
1454         if (*content)
1455             {
1456             path = searchforfile(content);
1457             if (!path)
1458                 {
1459                 m_err2("Can't find file %s (declared in entity %s)",
1460                        content,
1461                        wc_elementName);
1462                 m_free(wc_elementName,"wide character string");
1463                 return("");
1464                 }
1465             else
1466                 {
1467                 m_free(wc_elementName,"wide character string");
1468                 return MakeMByteString(path);
1469                 }
1470             }
1471         m_free(wc_elementName,"wide character string");
1472         return "";
1473         }
1474     }
1475
1476 m_free(wc_elementName,"wide character string");
1477 if (*defaultString)
1478     {
1479     retval = m_malloc(strlen(defaultString) + 1,
1480                       "GetDefaultHeaderString return");
1481     return strcpy(retval, defaultString);
1482     }
1483
1484 return "";
1485 }
1486
1487
1488 /* A function that takes a language/charset pair and:
1489  *     if they are standard, leave them unchanged but get local
1490  *                           versions and setlocale(3) using those
1491  *     if they are local, setlocale(3) with them and replace them with
1492  *                        standard versions.
1493 */
1494 static void
1495 #if defined(M_PROTO)
1496 SetStdLocale(char *pLang, char *pCharset)
1497 #else
1498 SetStdLocale(pLang, pCharset)
1499 char *pLang;
1500 char *pCharset;
1501 #endif
1502 {
1503 static const char *cString   = "C";
1504 static const char *isoString = "ISO-8859-1";
1505 _DtXlateDb  myDb = NULL;
1506 char        myPlatform[_DtPLATFORM_MAX_LEN+1];
1507 char        myLocale[256]; /* arbitrarily large */
1508 char       *locale;
1509 char       *lang;
1510 char       *charset;
1511 int         execVer;
1512 int         compVer;
1513 int         isStd;
1514
1515 strcpy(myLocale, pLang);
1516 if (*pCharset)
1517     {
1518     strcat(myLocale, ".");
1519     strcat(myLocale, pCharset);
1520     }
1521
1522 if ((_DtLcxOpenAllDbs(&myDb) != 0) ||
1523     (_DtXlateGetXlateEnv(myDb,myPlatform,&execVer,&compVer) != 0))
1524     {
1525     fprintf(stderr,
1526             "Warning: could not open locale translation database.\n");
1527     if (m_errfile != stderr)
1528         fprintf(m_errfile,
1529                 "Warning: could not open locale translation database.\n");
1530     strcpy(pLang, cString);
1531     strcpy(pCharset, isoString);
1532     if (myDb != 0)
1533         _DtLcxCloseDb(&myDb);
1534     return;
1535     }
1536
1537 isStd = !_DtLcxXlateOpToStd(myDb,
1538                             "CDE",
1539                             0,
1540                             DtLCX_OPER_STD,
1541                             myLocale,
1542                             NULL,
1543                             NULL,
1544                             NULL,
1545                             NULL);
1546
1547 if (isStd)
1548     { /* already standard - get local versions and set locale */
1549     if (_DtLcxXlateStdToOp(myDb,
1550                            myPlatform,
1551                            compVer,
1552                            DtLCX_OPER_SETLOCALE,
1553                            myLocale,
1554                            NULL,
1555                            NULL,
1556                            NULL,
1557                            &locale))
1558         {
1559         fprintf(stderr,
1560                 "Warning: could not translate CDE locale to local\n");
1561         if (m_errfile != stderr)
1562             fprintf(m_errfile,
1563                     "Warning: could not translate CDE locale to local\n");
1564         strcpy(pLang, cString);
1565         strcpy(pCharset, isoString);
1566         _DtLcxCloseDb(&myDb);
1567         return;
1568         }
1569     else
1570         {
1571         setlocale(LC_CTYPE, locale);
1572         mb_free(&locale);
1573         }
1574     }
1575 else
1576     { /* already local - set locale and get standard versions */
1577     if (_DtLcxXlateOpToStd(myDb,
1578                            myPlatform,
1579                            compVer,
1580                            DtLCX_OPER_SETLOCALE,
1581                            myLocale,
1582                            NULL,
1583                            &lang,
1584                            &charset,
1585                            NULL))
1586         {
1587         fprintf(stderr,
1588                 "Warning: could not translate local locale to CDE\n");
1589         if (m_errfile != stderr)
1590             fprintf(m_errfile,
1591                     "Warning: could not translate local locale to CDE\n");
1592         strcpy(pLang, cString);
1593         strcpy(pCharset, isoString);
1594         _DtLcxCloseDb(&myDb);
1595         return;
1596         }
1597     setlocale(LC_CTYPE, myLocale);
1598
1599     if (*lang)
1600         {
1601         strcpy(pLang, lang);
1602         mb_free(&lang);
1603         }
1604     else
1605         strcpy(pLang, cString);
1606
1607     if (*charset)
1608         {
1609         strcpy(pCharset, charset);
1610         mb_free(&charset);
1611         }
1612     else
1613         strcpy(pCharset, isoString);
1614     }
1615
1616 _DtLcxCloseDb(&myDb);
1617 free(charset);
1618 free(lang);
1619 }
1620
1621
1622 /* A function that takes the return value from a call to setlocale()
1623  * and extracts the langterr.charset data from it in a vendor neutral
1624  * fashion.
1625 */
1626 static char *
1627 #if defined(M_PROTO)
1628 GetStdLocale()
1629 #else
1630 GetStdLocale()
1631 #endif
1632 {
1633 static char buffer[256];
1634 static char *cString   = "C";
1635 _DtXlateDb  myDb = NULL;
1636 char        myPlatform[_DtPLATFORM_MAX_LEN+1];
1637 char       *opLocale;
1638 char       *stdLocale;
1639 int         execVer;
1640 int         compVer;
1641
1642 if ((_DtLcxOpenAllDbs(&myDb) == 0) &&
1643     (_DtXlateGetXlateEnv(myDb,myPlatform,&execVer,&compVer) != 0))
1644     {
1645     fprintf(stderr,
1646             "Warning: could not open locale translation database.\n");
1647     if (m_errfile != stderr)
1648         fprintf(m_errfile,
1649                 "Warning: could not open locale translation database.\n");
1650     return cString;
1651     }
1652
1653 if (_DtLcxXlateOpToStd(myDb,
1654                        myPlatform,
1655                        compVer,
1656                        DtLCX_OPER_SETLOCALE,
1657                        setlocale(LC_ALL, NULL),
1658                        &stdLocale,
1659                        NULL,
1660                        NULL,
1661                        NULL))
1662     {
1663     fprintf(stderr,
1664             "Warning: could not translate local locale to CDE\n");
1665     if (m_errfile != stderr)
1666         fprintf(m_errfile,
1667                 "Warning: could not translate local locale to CDE\n");
1668     _DtLcxCloseDb(&myDb);
1669     return cString;
1670     }
1671
1672 if (_DtLcxXlateStdToOp(myDb,
1673                        myPlatform,
1674                        compVer,
1675                        DtLCX_OPER_SETLOCALE,
1676                        stdLocale,
1677                        NULL,
1678                        NULL,
1679                        NULL,
1680                        &opLocale))
1681     {
1682     fprintf(stderr,
1683             "Warning: could not translate CDE locale to local\n");
1684     if (m_errfile != stderr)
1685         fprintf(m_errfile,
1686                 "Warning: could not translate CDE locale to local\n");
1687     mb_free(&stdLocale);
1688     _DtLcxCloseDb(&myDb);
1689     return cString;
1690     }
1691
1692 _DtLcxCloseDb(&myDb);
1693
1694 strcpy(buffer, opLocale);
1695 mb_free(&stdLocale);
1696 mb_free(&opLocale);
1697 return buffer;
1698 }
1699
1700
1701 /*
1702  * Look for a entities by the name of "LanguageElementDefaultLocale".
1703  * and "LanguageElementDefaultCharset".  If not found, get the user's
1704  * locale.  If LanguageElementDefaultCharset was set, use that in
1705  * place of the charset of the local (if any).  Call SetStdLocale()
1706  * to insure the language and charset are in the normalized form.
1707  * SetStdLocale() will also set the current locale to the local
1708  * versions of the language and charset.
1709 */
1710 void
1711 SetDefaultLocale()
1712 {
1713 unsigned char type,wheredef;
1714 M_WCHAR *elementName;
1715 M_WCHAR *content;
1716 char    *locale;
1717 char    *charset;
1718 char    *dotPtr;
1719 char    *tmpStr;
1720 char     stdLang[256];    /* arbitrarily large */
1721 char     stdCharset[256]; /* arbitrarily large */
1722
1723 locale        = NULL;
1724 charset       = NULL;
1725 dotPtr        = NULL;
1726 stdLang[0]    = 0;
1727 stdCharset[0] = 0;
1728
1729 elementName = MakeWideCharString("LanguageElementDefaultLocale");
1730 if (m_lookent(elementName, &type, &content, &wheredef))
1731     {
1732     if (type == M_SDATA)
1733         {
1734         locale = MakeMByteString(content);
1735         }
1736     }
1737 m_free(elementName,"wide character string");
1738
1739 if (!locale)
1740     {
1741     tmpStr = GetStdLocale();
1742     locale = mb_malloc(strlen(tmpStr)+1);
1743     strcpy(locale, tmpStr);
1744     }
1745
1746 dotPtr = strchr(locale, '.');
1747
1748 if (helpcharset)
1749     {
1750     charset = MakeMByteString(helpcharset);
1751     m_free(helpcharset, "help charset");
1752     helpcharset = NULL;
1753     }
1754 else
1755     {
1756     elementName = MakeWideCharString("LanguageElementDefaultCharset");
1757     if (m_lookent(elementName, &type, &content, &wheredef))
1758         {
1759         if (type == M_SDATA)
1760             {
1761             charset = MakeMByteString(content);
1762             }
1763         }
1764     m_free(elementName,"wide character string");
1765     }
1766
1767 if (!charset)
1768     {
1769     if (dotPtr)
1770         charset = dotPtr + 1;
1771     }
1772 if (dotPtr)
1773     *dotPtr = '\0';
1774
1775 strcpy(stdLang, locale);
1776 if (charset)
1777     strcpy(stdCharset, charset);
1778 SetStdLocale(stdLang, stdCharset);
1779
1780 if (*stdCharset)
1781     helpcharset = MakeWideCharString(stdCharset);
1782 helplang = MakeWideCharString(stdLang);
1783
1784 mb_free(&locale);
1785 if (charset && (charset != (dotPtr+1)))
1786     mb_free(&charset);
1787 }
1788
1789
1790 #if defined(M_PROTO)
1791 void paragraph(M_WCHAR *indent,
1792                M_WCHAR *id,
1793                M_WCHAR *gentity,
1794                M_WCHAR *gposition,
1795                M_WCHAR *ghyperlink,
1796                M_WCHAR *glinktype,
1797                M_WCHAR *gdescription)
1798 #else
1799 void paragraph(indent,
1800                id,
1801                gentity,
1802                gposition,
1803                ghyperlink,
1804                glinktype,
1805                gdescription)
1806 M_WCHAR *indent;
1807 M_WCHAR *id;
1808 M_WCHAR *gentity;
1809 M_WCHAR *gposition;
1810 M_WCHAR *ghyperlink;
1811 M_WCHAR *glinktype;
1812 M_WCHAR *gdescription;
1813 #endif
1814 {
1815 char *firstString, *indentString;
1816
1817 if (id)
1818     {
1819     savid = checkid(id);
1820     }
1821 chapst = TRUE;
1822 inSdlP = TRUE;
1823 if (!inBlock)
1824     StartBlock(NULL, NULL, NULL);
1825 fputs("<P", outfile);
1826 if (id)
1827     {
1828     char *mb_id;
1829
1830     mb_id = MakeMByteString(id);
1831     fprintf(outfile, " ID=\"%s\"", mb_id);
1832     m_free(mb_id,"multi-byte string");
1833     }
1834
1835 firstString = "";
1836 if (firstPInBlock)
1837     {
1838     firstString = "1";
1839     firstPInBlock = FALSE;
1840     }
1841
1842 indentString = "";
1843 if (indent)
1844     indentString = "-INDENT";
1845
1846 fprintf(outfile, " SSI=\"P%s%s\">", firstString, indentString);
1847
1848 handle_link_and_graphic(m_parent(0),
1849                         gentity,
1850                         gposition,
1851                         ghyperlink,
1852                         glinktype,
1853                         gdescription);
1854
1855 }
1856
1857 #if defined(M_PROTO)
1858 void figure(
1859        M_WCHAR *number,
1860        M_WCHAR *tonumber,
1861        M_WCHAR *id,
1862        M_WCHAR *file,
1863        M_WCHAR *figpos,
1864        M_WCHAR *cappos,
1865        M_WCHAR *ghyperlink,
1866        M_WCHAR *glinktype,
1867        M_WCHAR *gdescription)
1868 #else
1869 void figure(
1870        number,
1871        tonumber,
1872        id,
1873        file,
1874        figpos,
1875        cappos,
1876        ghyperlink,
1877        glinktype,
1878        gdescription)
1879 M_WCHAR *number;
1880 M_WCHAR *tonumber;
1881 M_WCHAR *id;
1882 M_WCHAR *file;
1883 M_WCHAR *figpos;
1884 M_WCHAR *cappos;
1885 M_WCHAR *border;
1886 M_WCHAR *ghyperlink;
1887 M_WCHAR *glinktype;
1888 M_WCHAR *gdescription;
1889 #endif
1890 {
1891 char snb_id[32];
1892 unsigned char etype,wheredef;
1893 char *string = 
1894     GetDefaultHeaderString("FigureElementDefaultHeadingString",
1895                            M_SDATA,
1896                            "Figure");
1897
1898 if (needFData)
1899     {
1900     fputs("<FDATA>\n", outfile);
1901     needFData = FALSE;
1902     }
1903 if (!inBlock)
1904     StartBlock(NULL, NULL, NULL);
1905
1906 inSdlP = TRUE;
1907 fputs("<P SSI=\"FIGURE\">\n", outfile);
1908
1909 if (ghyperlink)
1910     {
1911     HandleLink(ghyperlink, glinktype, gdescription);
1912     }
1913 else if (glinktype || gdescription)
1914     {
1915     m_eprefix();
1916     fprintf(stderr,
1917             "Error: %sP%s ghyperlink was undefined.\n",
1918             m_stago,
1919             m_tagc);
1920     fprintf(m_errfile,
1921             "Error: %sP%s ghyperlink was undefined.\n",
1922             m_stago,
1923             m_tagc);
1924     fprintf(stderr,
1925     "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
1926             QJUMP,
1927             QJUMPNEWVIEW,
1928             QDEFINITION,
1929             QEXECUTE,
1930             QAPPDEFINED,
1931             QMAN);
1932     fprintf(m_errfile,
1933     "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
1934             QJUMP,
1935             QJUMPNEWVIEW,
1936             QDEFINITION,
1937             QEXECUTE,
1938             QAPPDEFINED,
1939             QMAN);
1940     m_errline("Use ``ghyperlink='' if the value contains non-alphabetics");
1941     m_esuffix();
1942     }
1943 /* end of link specific code */
1944
1945 figcaption = FALSE;
1946 ftonumber = (!tonumber || (vnumber(tonumber) == NUMBER));
1947 if (id && ! ftonumber)
1948     {
1949     m_error("Figures with ID's must be numbered");
1950     ftonumber = NUMBER;
1951     }
1952 if (ftonumber) figno++;
1953
1954 if (number)
1955     {
1956     char *mb_number;
1957
1958     mb_number = MakeMByteString(number);
1959     figno = atoi(mb_number);
1960     m_free(mb_number,"multi-byte string");
1961     if (! ftonumber)
1962     m_err1("Explicit figure number %s inconsistent with NONUMBER option",
1963            number);
1964     }
1965 svheadlen = 0;
1966 *savehead = M_EOS;
1967 if (id)
1968     {
1969     char mb_xrefstring[400];
1970
1971     sprintf(mb_xrefstring, "%s %d", string, figno);
1972     mbstowcs(xrefstring, mb_xrefstring, 400);
1973     xstrlen = w_strlen(xrefstring);
1974     m_getline(&xrffile, &xrfline);
1975     if (xrffile == NULL)
1976         {
1977         /* set to primary input source */
1978         xrffile = inputname;
1979         }
1980     setid(id, TRUE, FALSE, inchapter, chapstring, xrffile, xrfline, TRUE);
1981     }
1982
1983 /* initialize some stuff first:
1984 - file is the entity name,
1985 - f_file is the content of the entity,
1986 used only if f_content nonNULL
1987 - f_content is f_file with the relative pathname, initialized to NULL,
1988 - f_contqual is fully qualified f_file, assigned ONLY IF
1989 f_content nonNULL
1990 */
1991 file_ent = FALSE;
1992 f_content = NULL;
1993 f_contqual[0] = M_EOS;
1994
1995 /* check ENTITY and determine the figure type  */
1996 if (file)
1997     {
1998     m_lookent(file, &etype, &f_file, &wheredef);
1999     if (etype != M_SYSTEM)
2000         {
2001         M_WCHAR *wc_stago, *wc_tagc;
2002         M_WCHAR *wc_entsystem, *wc_entkw;
2003
2004         wc_stago = MakeWideCharString(m_stago);
2005         wc_tagc  = MakeWideCharString(m_tagc);
2006         wc_entsystem  = MakeWideCharString(m_entsystem);
2007         wc_entkw  = MakeWideCharString(m_entkw);
2008         m_err6("%s not a %s %s, as required for the ENTITY parameter of %s%s%s",
2009                file,
2010                wc_entsystem,
2011                wc_entkw,
2012                wc_stago,
2013                m_parent(0),
2014                wc_tagc);
2015         m_free(wc_stago,"wide character string");
2016         m_free(wc_tagc,"wide character string");
2017         m_free(wc_entsystem,"wide character string");
2018         m_free(wc_entkw,"wide character string");
2019         }
2020     else
2021         {
2022         file_ent = TRUE;
2023         f_content = searchforfile(f_file);
2024         if (f_content)
2025             {
2026             if (getqualified(f_contqual, f_content))
2027                 {
2028                 /* unsuccessful qual */
2029                 if (w_strlen(f_content) < FNAMELEN)
2030                     w_strcpy(f_contqual, f_content);
2031                 else
2032                     {
2033                     m_err1("Internal error. File name too long: %s",
2034                            f_content);
2035                     m_exit(m_errexit);
2036                     }
2037                 }
2038             }
2039         else
2040             {
2041             m_err2("Can't find file %s (declared in entity %s)",
2042                    f_file,
2043                    file);
2044             }
2045         }
2046     }
2047
2048 sprintf(snb_id, "%s%d", sdlReservedName, NextId());
2049
2050 {
2051 static M_WCHAR empty = M_EOS;
2052 char *mb_content;
2053
2054 if (!f_content) f_content = &empty;
2055
2056 mb_content = MakeMByteString(f_content);
2057 AddToSNB(snb_id, mb_content);
2058 m_free(mb_content,"multi-byte string");
2059 }
2060
2061 fputs("<SNREF", outfile);
2062
2063 if (id)
2064     {
2065     char *mb_id;
2066
2067     mb_id = MakeMByteString(id);
2068     fprintf(outfile, " ID=\"%s\"", mb_id);
2069     m_free(mb_id,"multi-byte string");
2070     }
2071 fprintf(outfile, ">\n<REFITEM RID=\"%s\" CLASS=\"FIGURE\" SSI=\"FIG", snb_id);
2072
2073
2074 /* if caption position is not specified, have it track the figure position */
2075 if (!cappos)
2076     cappos = figpos;
2077
2078 if (figpos)
2079     switch (vcenter(figpos))
2080         {
2081         case LEFT:
2082             fputs("-LEFT", outfile);
2083             break;
2084         case CENTER:
2085             fputs("-CENTER", outfile);
2086             break;
2087         case RIGHT:
2088             fputs("-RIGHT", outfile);
2089             break;
2090         }
2091 fputs("\">\n", outfile);
2092
2093 capposition = "";
2094 if (cappos)
2095     switch (vcenter(cappos))
2096         {
2097         case LEFT:
2098             capposition = "-LEFT";
2099             break;
2100         case CENTER:
2101             capposition = "-CENTER";
2102             break;
2103         case RIGHT:
2104             capposition = "-RIGHT";
2105             break;
2106         }
2107
2108 if (ftonumber)
2109     {
2110     fprintf(outfile,
2111             "<HEAD TYPE=\"LINED\" CLASS=\"CAPTION\" SSI=\"NUMBER%s\">%s %d.",
2112             capposition,
2113             string,
2114             figno);
2115     }
2116 m_free(string, "default header string return");
2117 }
2118
2119 #if defined(M_PROTO)
2120 void endterm(M_WCHAR *base, M_WCHAR *gloss, char *linktype)
2121 #else
2122 void endterm( base, gloss, linktype)
2123 M_WCHAR *base;
2124 M_WCHAR *gloss;
2125 char    *linktype;
2126 #endif
2127 {
2128 M_WCHAR *p;
2129 M_WCHAR  dterm[MAXTERM+1];
2130 M_WCHAR  wnl, wsp;
2131 char     buffer[BIGBUF];
2132 int      idn;
2133
2134 if (!(m_mblevel("HEAD")       ||
2135       m_mblevel("EXAMPLESEG") ||
2136       m_mblevel("ANNOTATION")
2137      )
2138    )
2139     {
2140     /* Don't re-enable output yet if in a <HEAD>, <EX> or <ANNOTATION> */
2141     tooutput = TRUE;
2142     }
2143
2144 mbtowc(&wnl, "\n", 1);
2145 mbtowc(&wsp, " ", 1);
2146
2147 /* terminate the term string */
2148 if (termp - term > MAXTERM) termp = &term[MAXTERM];
2149 *termp = M_EOS;
2150
2151 /* make a copy - will transform to match definition transformations */
2152 w_strcpy(dterm, term);
2153 termp = dterm + (termp - term);
2154
2155 /* Check if it should be entered into the glossary structure */
2156 if (vgloss(gloss) == GLOSS)
2157     {
2158     /* strip possible newlines out of base form */
2159     if (base)
2160         {
2161         for (p = base; *p ; p++)
2162             {
2163             if ((p - base) >= MAXTERM)
2164                 {
2165                 if ((p - base) == MAXTERM)
2166                     {
2167                     M_WCHAR *wc_stago, *wc_tagc;
2168
2169                     wc_stago = MakeWideCharString(m_stago);
2170                     wc_tagc  = MakeWideCharString(m_tagc);
2171                     m_err2("Too many characters in BASEFORM for %sTERM%s",
2172                            wc_stago,
2173                            wc_tagc);
2174                     m_free(wc_stago,"wide character string");
2175                     m_free(wc_tagc,"wide character string");
2176
2177                     *p = M_EOS;
2178                     }
2179                 }
2180             else
2181                 {
2182                 if (*p == wnl) *p = wsp;
2183                 }
2184             }
2185         }
2186
2187     /* strip possible newlines out of dterm */
2188     for (p = dterm; *p ; p++)
2189         {
2190         if (*p == wnl) *p = wsp;
2191         }
2192
2193     /* trim possible last space */
2194     if (termp - dterm > 1 && *(termp-1) == wsp)
2195         {
2196         *(termp-1) = M_EOS;
2197         }
2198
2199     idn = (intptr_t) m_lookfortrie(base ? base : dterm, &gtree);
2200     if (idn < 0)
2201         idn = -idn;
2202     if (!idn)
2203         {
2204         idn = NextId();
2205         m_ntrtrie(base ? base : dterm, &gtree, (void *) (intptr_t) idn);
2206         }
2207     }
2208
2209 /* Handle the output */
2210 if (vgloss(gloss) == GLOSS)
2211     {
2212     sprintf(buffer,
2213             "<LINK WINDOW=\"%s\" RID=\"%s%d\">",
2214             linktype,
2215             sdlReservedName,
2216             idn);
2217     mb_strcode(buffer, outfile);
2218     }
2219
2220 mb_strcode("<KEY CLASS=\"TERM\">", outfile);
2221
2222 #if 0
2223 if (m_mblevel("EXAMPLESEG"))
2224     {
2225     /* Are we in one of these?  May need to number a line. */
2226     for(p = term; *p; p++)
2227         {
2228         exoutchar(*p);
2229         }
2230     }
2231 else
2232 #endif
2233     multi_cr_flag = FALSE;
2234     strcode(term, outfile);
2235
2236 mb_strcode("</KEY>", outfile);
2237
2238 if (vgloss(gloss) == GLOSS)
2239     {
2240     mb_strcode("</LINK>", outfile);
2241     }
2242
2243 if (echo) mb_echohead("++");
2244 }
2245
2246 #if defined(M_PROTO)
2247 M_WCHAR wc_toupper(M_WCHAR wc)
2248 #else
2249 M_WCHAR wc_toupper(wc)
2250 M_WCHAR wc;
2251 #endif
2252 {
2253 if ((wc >= 0) && (wc <= 255))
2254     {
2255     return _toupper(wc);
2256     }
2257 return wc;
2258 }
2259
2260 #if defined(M_PROTO)
2261 M_WCHAR *wc_stringtoupper(M_WCHAR *wcp)
2262 #else
2263 M_WCHAR *wc_stringtoupper(wcp)
2264 M_WCHAR *wcp;
2265 #endif
2266 {
2267 M_WCHAR *newstring, *nsp;
2268
2269 nsp = newstring =
2270     m_malloc(w_strlen(wcp) + 1, "wide character upper case string");
2271
2272 while (*wcp)
2273     {
2274     *nsp = wc_toupper(*wcp);
2275     nsp++;
2276     wcp++;
2277     }
2278 *nsp = 0;
2279
2280 return(newstring);
2281 }
2282
2283 int NextId()
2284 {
2285 static id = 0;
2286
2287 return ++id;
2288 }
2289
2290 char *GetLanguage()
2291 {
2292 static char *pLang = NULL;
2293
2294 if (!pLang)
2295     {
2296     pLang = MakeMByteString(helplang);
2297     }
2298
2299 return pLang;
2300 }
2301
2302 char *GetCharset()
2303 {
2304 static char *pCharset = NULL;
2305
2306 if (!pCharset)
2307     {
2308     pCharset = MakeMByteString(helpcharset);
2309     }
2310
2311 return pCharset;
2312 }
2313
2314
2315 #if defined(M_PROTO)
2316 void HandleLink(M_WCHAR *hyperlink, M_WCHAR *type, M_WCHAR *description)
2317 #else
2318 void HandleLink(hyperlink, type, description)
2319 M_WCHAR *hyperlink;
2320 M_WCHAR *type;
2321 M_WCHAR *description;
2322 #endif
2323 {
2324 char *mb_hyperlink, mb_undefined[64];
2325 char buffer[BIGBUF];
2326 static M_WCHAR wsp = 0;
2327
2328 if (!wsp)
2329     {
2330     mbtowc(&wsp, " ", 1);
2331     }
2332
2333 strcpy(mb_undefined, sdlReservedName);
2334 strcpy(mb_undefined + SDLNAMESIZ - 1, "-UNDEFINED");
2335
2336 mb_strcode("<LINK ", outfile);
2337 global_linktype = 0; /* default to type jump */
2338 if (type)
2339     {
2340     /* type is set, choose which is correct */
2341     if (m_wcmbupstrcmp(type, QJUMP))
2342         { /* not type jump */
2343         if (!m_wcmbupstrcmp(type, QJUMPNEWVIEW))
2344             { mb_strcode("WINDOW=\"NEW\" ", outfile); global_linktype = 1;}
2345         else if (!m_wcmbupstrcmp(type, QDEFINITION))
2346             { mb_strcode("WINDOW=\"POPUP\" ", outfile); global_linktype = 2;}
2347         else if (!m_wcmbupstrcmp(type, QEXECUTE))
2348             { global_linktype = 3;}
2349         else if (!m_wcmbupstrcmp(type, QMAN))
2350             { mb_strcode("WINDOW=\"POPUP\" ", outfile); global_linktype = 4;}
2351         else if (!m_wcmbupstrcmp(type, QAPPDEFINED))
2352             { global_linktype = 5;}
2353         }
2354     }
2355 mb_strcode("RID=\"", outfile);
2356 if (hyperlink)
2357     {
2358     mb_hyperlink = MakeMByteString(hyperlink);
2359     if (*mb_hyperlink == '_') /* must be metainfo */
2360         {
2361         strcpy(buffer, sdlReservedName);
2362         buffer[SDLNAMESIZ-1] = '-';
2363         strcpy(buffer+SDLNAMESIZ, mb_hyperlink+1);
2364         mb_free(&mb_hyperlink);
2365         }
2366     }
2367 else
2368     {
2369     m_eprefix();
2370     fprintf(stderr,
2371             "Error: %sLINK%s hyperlink was undefined.\n",
2372             m_stago,
2373             m_tagc);
2374     fprintf(m_errfile,
2375             "Error: %sLINK%s hyperlink was undefined.\n",
2376             m_stago,
2377             m_tagc);
2378     fprintf(stderr,
2379     "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
2380             QJUMP,
2381             QJUMPNEWVIEW,
2382             QDEFINITION,
2383             QEXECUTE,
2384             QAPPDEFINED,
2385             QMAN);
2386     fprintf(m_errfile,
2387     "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
2388             QJUMP,
2389             QJUMPNEWVIEW,
2390             QDEFINITION,
2391             QEXECUTE,
2392             QAPPDEFINED,
2393             QMAN);
2394     m_errline("Use ``hyperlink='' if the value contains non-alphabetics");
2395     m_esuffix();
2396     mb_hyperlink = mb_undefined;
2397     }
2398
2399 if ((global_linktype <= 2) && hyperlink && (!w_strchr(hyperlink, wsp)))
2400     {
2401     if (mb_hyperlink)
2402         sprintf(buffer, "%s", mb_hyperlink);
2403     }
2404 else
2405     {
2406     char tmpsnb[BIGBUF];
2407     int  snblen;
2408
2409     int nextId = NextId();
2410     sprintf(buffer, "%s%d", sdlReservedName, nextId);
2411     if (!savesnb && snbstart)
2412         {
2413         fprintf(snbfp, "%d\n", snbstart);
2414         snbstart = 0;
2415         }
2416     switch (global_linktype)
2417         {
2418         case 0: /* jump */
2419         case 1: /* jump new */
2420         case 2: /* definition */
2421             sprintf(tmpsnb,
2422                     "<CROSSDOC ID=\"%s%d\" XID",
2423                     sdlReservedName,
2424                     nextId);
2425             break;
2426         case 3: /* execute */
2427             sprintf(tmpsnb,
2428                     "<SYS-CMD ID=\"%s%d\" COMMAND",
2429                     sdlReservedName,
2430                     nextId);
2431             break;
2432         case 4: /* man */
2433             sprintf(tmpsnb,
2434                     "<MAN-PAGE ID=\"%s%d\" XID",
2435                     sdlReservedName,
2436                     nextId);
2437             break;
2438         case 5: /* app defined */
2439             sprintf(tmpsnb,
2440                     "<CALLBACK ID=\"%s%d\" DATA",
2441                     sdlReservedName,
2442                     nextId);
2443             break;
2444         }
2445     if (savesnb)
2446         {
2447         snblen = strlen(savesnb);
2448         savesnb = mb_realloc(savesnb, snblen + strlen(tmpsnb) + 1);
2449         strcpy(savesnb + snblen, tmpsnb);
2450         sprintf(tmpsnb, "=\"%s\">\n", mb_hyperlink);
2451         snblen = strlen(savesnb);
2452         savesnb = mb_realloc(savesnb, snblen + strlen(tmpsnb) + 1);
2453         strcpy(savesnb + snblen, tmpsnb);
2454         }
2455     else
2456         {
2457         fputs(tmpsnb, snbfp);
2458         fprintf(snbfp, "=\"%s\">\n", mb_hyperlink);
2459         }
2460     }
2461 mb_strcode(buffer, outfile);
2462 mb_strcode("\"", outfile);
2463 if (mb_hyperlink && (mb_hyperlink != mb_undefined))
2464     m_free(mb_hyperlink,"multi-byte string");
2465 if (description)
2466     {
2467     char *mb_description;
2468
2469     mb_description = MakeMByteString(description);
2470     sprintf(buffer, " DESCRIPT=\"%s\"", mb_description);
2471     mb_strcode(buffer, outfile);
2472     m_free(mb_description,"multi-byte string");
2473     }
2474 mb_strcode(">", outfile);
2475 }
2476
2477
2478 #if defined(M_PROTO)
2479 char *mb_realloc(char *ptr, long size)
2480 #else
2481 char *mb_realloc(ptr, size)
2482 char *ptr;
2483 long  size;
2484 #endif
2485 {
2486 void   *vptr;
2487 size_t  ssize;
2488
2489 ssize = (size_t) size;
2490 vptr = realloc((void *) ptr, ssize);
2491
2492 #if DEBUG_MB_MALLOC
2493 if (ptr != vptr)
2494     {
2495     fprintf(stdout, "realloc 0x%p 0x%p\n", ptr, vptr);
2496     fflush(stdout);
2497     }
2498 #endif
2499
2500 return (char *) vptr;
2501 }
2502
2503
2504 #if defined(M_PROTO)
2505 char *mb_malloc(long size)
2506 #else
2507 char *mb_malloc(size)
2508 long  size;
2509 #endif
2510 {
2511 char   *cptr;
2512 size_t  ssize;
2513
2514 ssize = (size_t) size;
2515 cptr = (char *) malloc(ssize);
2516
2517 #if DEBUG_MB_MALLOC
2518 fprintf(stdout, "malloc 0x%p\n", cptr);
2519 fflush(stdout);
2520 #endif
2521
2522 *cptr = '\0';
2523 return cptr;
2524 }
2525
2526
2527 #if defined(M_PROTO)
2528 void mb_free(char **pptr)
2529 #else
2530 void  *mb_free(pptr)
2531 char **pptr;
2532 #endif
2533 {
2534
2535 #if DEBUG_MB_MALLOC
2536 fprintf(stdout, "free 0x%p\n", *pptr);
2537 fflush(stdout);
2538 #endif
2539
2540 free((void *) *pptr);
2541 *pptr = NULL;
2542 }
2543
2544 #if defined(M_PROTO)
2545 static void AddToRowVec(int *length, char **rowvec, char *id)
2546 #else
2547 static void AddToRowVec(length, rowvec, id)
2548 int   *length;
2549 char **rowvec;
2550 char  *id;
2551 #endif
2552 {
2553 char tempRowVec[BIGBUF];
2554 int  rowVecLen;
2555
2556 sprintf(tempRowVec, "<FROWVEC CELLS=\"%s\">\n", id);
2557 rowVecLen = strlen(tempRowVec);
2558 *rowvec = mb_realloc(*rowvec, *length + rowVecLen);
2559 strcpy(*rowvec + *length - 1, tempRowVec);
2560 *length += rowVecLen;
2561 }
2562
2563
2564 #if defined(M_PROTO)
2565 void Add2ToRowVec(int *length, char **rowvec, char *id1, char *id2)
2566 #else
2567 void Add2ToRowVec(length, rowvec, id1, id2)
2568 int   *length;
2569 char **rowvec;
2570 char  *id1, *id2;
2571 #endif
2572 {
2573 char tempRowVec[BIGBUF];
2574 int  rowVecLen;
2575
2576 sprintf(tempRowVec, "<FROWVEC CELLS=\"%s %s\">\n", id1, id2);
2577 rowVecLen = strlen(tempRowVec);
2578 *rowvec = mb_realloc(*rowvec, *length + rowVecLen);
2579 strcpy(*rowvec + *length - 1, tempRowVec);
2580 *length += rowVecLen;
2581 }
2582
2583
2584 #if defined(M_PROTO)
2585 void StartEx(M_WCHAR *notes, M_WCHAR *lines, M_WCHAR *textsize)
2586 #else
2587 void StartEx(*notes, *lines, *textsize)
2588 M_WCHAR *notes;
2589 M_WCHAR *lines;
2590 M_WCHAR *textsize;
2591 #endif
2592 {
2593 exTextSize = vextextsize(textsize);
2594 stackex = vstack(notes);
2595
2596 StartBlock(NULL, "EX", NULL);
2597
2598 tonumexlines = (LOGICAL) (vnumber(lines) == NUMBER);
2599 firstAnnot   = TRUE;
2600 exLineNum    = 1;
2601 oldExLineNum = 1;
2602 saveex       = mb_malloc(1);
2603 svexlen      = 1;
2604 }
2605
2606
2607 #if defined(M_PROTO)
2608 void EndEx()
2609 #else
2610 void EndEx()
2611 #endif
2612 {
2613 char *annotation;
2614 int   annotLen;
2615 char *ssi;
2616 char  buffer[BIGBUF];
2617 int   length;
2618
2619 if (saveexseg)
2620     {
2621     if (exTextSize == SMALLEST)
2622         ssi = "SMLST";
2623     else if (exTextSize == SMALLER)
2624         ssi = "SMLR";
2625     else
2626         ssi = "NML";
2627     length = sprintf(buffer, "<P TYPE=\"LITERAL\" SSI=\"EX-%s\">", ssi);
2628
2629     if (tonumexlines)
2630         {
2631         length += sprintf(buffer + length,
2632                           "<HEAD TYPE=\"LINED\" SSI=\"EX-NUM\">");
2633         while (oldExLineNum <= exLineNum)
2634             {
2635             length += sprintf(buffer + length, "%2d:\n", oldExLineNum);
2636             oldExLineNum++;
2637             }
2638         length += sprintf(buffer + length, "</HEAD>");
2639         }
2640
2641     if (svheadlen)
2642         {
2643         annotation = MakeMByteString(savehead);
2644         annotLen = strlen(annotation);
2645         }
2646     else
2647         {
2648         annotation = "";
2649         annotLen   = 0;
2650         }
2651     saveex = mb_realloc(saveex,
2652                         svexlen + length + (svexseglen - 1) + annotLen + 5);
2653
2654     strcpy(saveex + svexlen - 1, buffer);
2655     svexlen += length;
2656
2657     if (svheadlen)
2658         {
2659         strcpy(saveex + svexlen - 1, annotation);
2660         svexlen += annotLen;
2661         }
2662
2663     strcpy(saveex + svexlen - 1, saveexseg);
2664     svexlen += svexseglen - 1;
2665
2666     strcpy(saveex + svexlen - 1, "</P>\n");
2667     svexlen += 5;
2668     mb_free(&saveexseg);
2669
2670     if (svheadlen)
2671         m_free(annotation, "multi-byte string");
2672     }
2673 }
2674
2675
2676 #if defined(M_PROTO)
2677 void StartNCW(char *which)
2678 #else
2679 void StartNCW(which)
2680 char *which;
2681 #endif
2682 {
2683 notehead = FALSE;
2684 PushForm(NULL, which, NULL);
2685 }
2686
2687
2688 #if defined(M_PROTO)
2689 void StartBlock(char *pclass, char *ssi, char *id)
2690 #else
2691 void StartBlock(pclass, ssi, id)
2692 char *pclass, *ssi, *id;
2693 #endif
2694 {
2695 char  localId[32];
2696 char *realId;
2697
2698 if (needFData)
2699     {
2700     fputs("<FDATA>\n", outfile);
2701     needFData = FALSE;
2702     }
2703
2704 if (inBlock)
2705     fputs("</BLOCK>\n", outfile);
2706
2707 realId = id;
2708 if (formStackBase && (formStackTop >= formStackBase))
2709     { /* there is a <form> in progress */
2710     if (!id)
2711         {
2712         sprintf(localId, "%s%d", sdlReservedName, NextId());
2713         realId = localId;
2714         }
2715     AddToRowVec(&(formStackTop->vecLen), &(formStackTop->rowVec), realId);
2716     }
2717
2718 fputs("<BLOCK", outfile);
2719 if (realId)
2720     fprintf(outfile, " ID=\"%s\"", realId);
2721 if (pclass)
2722     fprintf(outfile, " CLASS=\"%s\"", pclass);
2723 if (ssi)
2724     fprintf(outfile, " SSI=\"%s\"", ssi);
2725 fputs(">\n", outfile);
2726
2727 inBlock = TRUE;
2728 firstPInBlock = TRUE;
2729 }
2730
2731
2732 #if defined(M_PROTO)
2733 void StartNCWtext(char *which, char *iconFile, char *headingString)
2734 #else
2735 void StartNCWtext(which, iconFile, headingString)
2736 char *which;
2737 char *iconFile;
2738 char *headingString;
2739 #endif
2740 {
2741 char *icon, *heading;
2742
2743 /* Write default head if no user-specified head was encountered */
2744 if (! notehead)
2745     {
2746     heading = GetDefaultHeaderString(headingString, M_SDATA, which);
2747     fprintf(outfile, "<HEAD SSI=\"NCW\">%s", heading);
2748     fputs("</HEAD>\n", outfile);
2749     notehead = TRUE;
2750     m_free(heading, "default header string return");
2751     }
2752
2753 icon = GetDefaultHeaderString(iconFile, M_SYSTEM, "");
2754 if (*icon)
2755     {
2756     char id[32];
2757
2758     sprintf(id, "%s%d", sdlReservedName, NextId());
2759     fprintf(outfile,
2760             "<HEAD SSI=\"NCW-ICON\"><SNREF>\n<REFITEM RID=\"%s\" ",
2761             id);
2762     fputs("CLASS=\"ICON\" SSI=\"NCW-ICON\">", outfile);
2763     fputs("</REFITEM>\n</SNREF></HEAD>\n", outfile);
2764     AddToSNB(id, icon);
2765     m_free(icon, "icon name");
2766     }
2767 }
2768
2769
2770 #if defined(M_PROTO)
2771 void AddToSNB(char *id, char *xid)
2772 #else
2773 void AddToSNB(id, xid)
2774 char *id;
2775 char *xid;
2776 #endif
2777 {
2778 char tmpsnb[BIGBUF];
2779 int  snblen;
2780
2781 if (savesnb)
2782     {
2783     sprintf(tmpsnb, "<GRAPHIC ID=\"%s\" XID=\"%s\">\n", id, xid);
2784     snblen = strlen(savesnb);
2785     savesnb = mb_realloc(savesnb, snblen + strlen(tmpsnb) + 1);
2786     strcpy(savesnb + snblen, tmpsnb);
2787     }
2788 else
2789     {
2790     if (snbstart)
2791         {
2792         fprintf(snbfp, "%d\n", snbstart);
2793         snbstart = 0;
2794         }
2795     fprintf(snbfp, "<GRAPHIC ID=\"%s\" XID=\"%s\">\n", id, xid);
2796     }
2797 }
2798
2799
2800 #if defined(M_PROTO)
2801 void IncludeToss()
2802 #else
2803 void IncludeToss()
2804 #endif
2805 {
2806 char     pathbuf[BIGBUF];
2807 char    *try = pathbuf;
2808 int      tryleng = sizeof(pathbuf);
2809 int      pathleng;
2810 int      fileleng;
2811 SEARCH  *thispath;
2812 char    *mb_inputname;
2813 M_WCHAR *wc_try, *wc_outputname;
2814 int      tossfile;
2815 char     filebuf[BIGBUF];
2816 size_t   bytesread;
2817 char   **tossline = toss;
2818
2819 /* the code below assume the extensions are .htg, .tss and .sdl */
2820 /* or at least that all extensions are 3 character plus a dot   */
2821
2822 fileleng = w_strlen(inputname);
2823 mb_inputname = mb_malloc(fileleng + 1);
2824 wcstombs(mb_inputname, inputname, fileleng);
2825 strcpy(mb_inputname + fileleng - 4, ".tss");
2826
2827 thispath = path;
2828 tossfile = -1;
2829 while (thispath)
2830     {
2831     pathleng = strlen(thispath->directory);
2832     if ((pathleng + fileleng) >= tryleng)
2833         {
2834         tryleng = pathleng + fileleng + 1;
2835         if (try == pathbuf)
2836             try = mb_malloc(tryleng);
2837         else
2838             try = mb_realloc(try, tryleng);
2839         }
2840     strcpy(try, thispath->directory);
2841     strcpy(try + pathleng, mb_inputname);
2842     tossfile = open(try, O_RDONLY);
2843     if (tossfile >= 0) break;
2844     thispath = thispath->next;
2845     }
2846
2847 if (tossfile >= 0)
2848     {
2849     fputs("<TOSS>\n", outfile);
2850     while ((bytesread = read(tossfile, filebuf, sizeof(filebuf))) > 0)
2851         if (fwrite(filebuf,
2852                    sizeof(*filebuf),
2853                    bytesread,
2854                    outfile) != bytesread) break;
2855     if (bytesread != 0)
2856         {
2857         strcpy(mb_inputname + fileleng - 4, ".sdl");
2858         wc_outputname = MakeWideCharString(mb_inputname);
2859         wc_try = MakeWideCharString(try);
2860         m_err2("error copying %s to output (%s) as the <toss> element",
2861                wc_try,
2862                wc_outputname);
2863         m_free(wc_try, "wide character toss input name");
2864         m_free(wc_outputname, "wide character output name");
2865         }
2866     close(tossfile);
2867     fputs("</TOSS>\n", outfile);
2868     }
2869 else
2870     {
2871     while (*tossline)
2872         {
2873         fputs(*tossline++, outfile);
2874         fputs("\n", outfile);
2875         }
2876     }
2877
2878 if (try != pathbuf) mb_free(&try);
2879 }
2880
2881 /* Below is a modified version of m_cyclent() that returns a pointer
2882  * to the entity content rather than its value.  Returning a pointer
2883  * to the entity's content field allows it to be modified.
2884 */
2885 /* Cyclent.c contains procedure m_cyclent(), callable by interface
2886    designers, to cycle through all defined entities, returning information
2887    about them */
2888 #if defined(M_PROTO)
2889 M_WCHAR *CycleEnt(LOGICAL init,
2890                   unsigned char *type,
2891                   M_WCHAR ***content,
2892                   unsigned char *wheredef)
2893 #else
2894 M_WCHAR *m_cyclent(init, type, content, wheredef)
2895   LOGICAL init ;
2896   unsigned char *type ;
2897   M_WCHAR ***content ;
2898   unsigned char *wheredef ;
2899 #endif
2900 {
2901 static M_TRIE *current ;
2902 static M_TRIE *ancestor[M_NAMELEN + 1] ;
2903 static length = 0 ;
2904 static M_WCHAR name[M_NAMELEN + 1] ;
2905
2906 if (init)
2907     {
2908     current = m_enttrie->data ;
2909     length = 0 ;
2910     }
2911
2912 if (length < 0) return(NULL) ;
2913
2914 while (current->symbol)
2915     {
2916     ancestor[length] = current ;
2917     name[length++] = current->symbol ;
2918     current = current->data ;
2919     }
2920 name[length] = M_EOS ;
2921
2922 *type     =  ((M_ENTITY *)  current->data)->type ;
2923 *content  = &(((M_ENTITY *) current->data)->content) ;
2924 *wheredef =  ((M_ENTITY *)  current->data)->wheredef ;
2925
2926 while (length >= 0)
2927     {
2928     if (current->next)
2929         {
2930         current = current->next ;
2931         break ;
2932         }
2933     length-- ;
2934     if (length < 0) break ;
2935     current = ancestor[length] ;
2936     }
2937
2938 return(name) ;
2939 }
2940
2941 /* A routine to examine all defined entities looking for ones of type
2942  * M_SDATA.  When found, if the entity's content is of the form
2943  * [......] (six characters surrounded by square brackets), its
2944  * content is modified to be <SPC NAME="[......]"> so that it may be
2945  * emitted into the SDL output.
2946 */
2947 void ModifyEntities()
2948 {
2949 unsigned char type;
2950 unsigned char wheredef;
2951 M_WCHAR **content;
2952 M_WCHAR  *name;
2953 char     *mb_content;
2954 M_WCHAR  *newContent;
2955 static char mb_newContent[] = "<SPC NAME=\"[123456]\">";
2956
2957 name = CycleEnt(TRUE, &type, &content, &wheredef);
2958 if (!name) return;
2959
2960 mb_newContent[21] = '\0';
2961
2962 do  {
2963     if ((type == M_SDATA) && *content)
2964         {
2965         mb_content = MakeMByteString(*content);
2966         if ((strlen(mb_content) == 8) &&
2967             (mb_content[0] == '[')    &&
2968             (mb_content[7] == ']'))
2969             {
2970             strncpy(mb_newContent+11, mb_content, 8);
2971             if (wheredef == M_DPARSER)
2972                 m_free(*content, "old SDATA entity content");
2973             *content = MakeWideCharString(mb_newContent);
2974             }
2975         m_free(mb_content, "multi-byte SDATA entity content");
2976         }
2977     }
2978 while (name = CycleEnt(FALSE, &type, &content, &wheredef));
2979 }
2980
2981
2982 #if defined(M_PROTO)
2983 void PushForm(char *class, char *ssi, char *id)
2984 #else
2985 void PushForm(class, ssi, id)
2986      char *class;
2987      char *ssi;
2988      char *id;
2989 #endif
2990 {
2991 char  localId[SDLNAMESIZ+10];
2992 char *realId;
2993 int   stackSize;
2994
2995 if (needFData)
2996     {
2997     fputs("<FDATA>\n", outfile);
2998     needFData = FALSE;
2999     }
3000
3001 if (inBlock)
3002     {
3003     fputs("</BLOCK>\n", outfile);
3004     inBlock = FALSE;
3005     }
3006
3007 realId = id;
3008 if (formStackBase && (formStackTop >= formStackBase))
3009     { /* there is a <form> in progress */
3010     if (!id)
3011         {
3012         sprintf(localId, "%s%d", sdlReservedName, NextId());
3013         realId = localId;
3014         }
3015     AddToRowVec(&(formStackTop->vecLen), &(formStackTop->rowVec), realId);
3016     }
3017
3018 if (formStackTop == formStackMax)
3019     {
3020     if (!formStackBase)
3021         {
3022         formStackBase = (FORMINFO *) malloc(10 * sizeof(FORMINFO));
3023         formStackTop  = formStackBase;
3024         formStackMax  = formStackBase + 9;
3025         }
3026     else
3027         {
3028         stackSize = formStackMax - formStackBase + 1;
3029         formStackBase =
3030             realloc(formStackBase, (stackSize + 10) * sizeof(FORMINFO));
3031         formStackTop = formStackBase + stackSize;
3032         formStackMax = formStackBase + (stackSize + 9);
3033         }
3034     }
3035 else
3036     formStackTop++;
3037
3038 formStackTop->rowVec = mb_malloc(1);
3039 formStackTop->vecLen = 1;
3040
3041 fputs("<FORM", outfile);
3042 if (realId)
3043     fprintf(outfile, " ID=\"%s\"", realId);
3044 if (class)
3045     fprintf(outfile, " CLASS=\"%s\"", class);
3046 if (ssi)
3047     fprintf(outfile, " SSI=\"%s\"", ssi);
3048 fputs(">\n", outfile);
3049 needFData = TRUE;
3050 }
3051
3052
3053 #if defined(M_PROTO)
3054 void PushForm2(char *class, char *ssi, char *id1, char *id2)
3055 #else
3056 void PushForm2(class, ssi, id1, id2)
3057      char *class;
3058      char *ssi;
3059      char *id1;
3060      char *id2;
3061 #endif
3062 {
3063 char id[32];
3064 int  stackSize;
3065 int  formId;
3066
3067 if (needFData)
3068     {
3069     fputs("<FDATA>\n", outfile);
3070     needFData = FALSE;
3071     }
3072
3073 if (inBlock)
3074     {
3075     fputs("</BLOCK>\n", outfile);
3076     inBlock = FALSE;
3077     }
3078
3079 if (!id2)
3080     {
3081     sprintf(id, "%s%d", sdlReservedName, formId = NextId());
3082     id2 = id;
3083     }
3084
3085 if (formStackBase && (formStackTop >= formStackBase))
3086     { /* there is a <form> in progress */
3087     Add2ToRowVec(&(formStackTop->vecLen),
3088                  &(formStackTop->rowVec),
3089                  id1,
3090                  id2);
3091     }
3092
3093 if (formStackTop == formStackMax)
3094     {
3095     if (!formStackBase)
3096         {
3097         formStackBase = (FORMINFO *) malloc(10 * sizeof(FORMINFO));
3098         formStackTop  = formStackBase;
3099         formStackMax  = formStackBase + 9;
3100         }
3101     else
3102         {
3103         stackSize = formStackMax - formStackBase + 1;
3104         formStackBase =
3105             realloc(formStackBase, (stackSize + 10) * sizeof(FORMINFO));
3106         formStackTop = formStackBase + stackSize;
3107         formStackMax = formStackBase + (stackSize + 9);
3108         }
3109     }
3110 else
3111     formStackTop++;
3112
3113 formStackTop->rowVec = mb_malloc(1);
3114 formStackTop->vecLen = 1;
3115
3116 fprintf(outfile, "<FORM ID=\"%s\"", id2);
3117 if (class)
3118     fprintf(outfile, " CLASS=\"%s\"", class);
3119 if (ssi)
3120     fprintf(outfile, " SSI=\"%s\"", ssi);
3121 fputs(">\n", outfile);
3122 needFData = TRUE;
3123 }
3124
3125 void PopForm()
3126 {
3127 if (inBlock)
3128     {
3129     fputs("</BLOCK>\n", outfile);
3130     inBlock = FALSE;
3131     }
3132
3133 fprintf(outfile,
3134         "</FDATA>\n<FSTYLE>\n%s</FSTYLE>\n</FORM>\n",
3135         formStackTop->rowVec);
3136
3137 mb_free(&(formStackTop->rowVec));
3138 --formStackTop;
3139 }
3140
3141 void PopForm2()
3142 {
3143 if (inBlock)
3144     {
3145     fputs("</BLOCK>\n", outfile);
3146     inBlock = FALSE;
3147     }
3148
3149 fprintf(outfile,
3150         "</FDATA>\n<FSTYLE NCOLS=\"2\">\n%s</FSTYLE>\n</FORM>\n",
3151         formStackTop->rowVec);
3152
3153 mb_free(&(formStackTop->rowVec));
3154 --formStackTop;
3155 }
3156
3157 /* look to see if there's an open form with no data; if so, add a data
3158  * block and close the form.  This situation will happen when a form
3159  * is pushed but the source doesn't go to text either because the text
3160  * is explicitly optional or due to the fact that text can be null.
3161 */
3162 void PopFormMaybe()
3163 {
3164 if ((formStackTop >= formStackBase) && (formStackTop->vecLen == 1))
3165     {
3166     StartBlock(NULL, NULL, NULL);
3167     PopForm();
3168     }
3169 }
3170
3171 void EmitSavedAnchors()
3172 {
3173 char buffer[BIGBUF];
3174
3175 if (parTextId)
3176     {
3177     sprintf(buffer,
3178             "<ANCHOR ID=\"%s%d\">",
3179             sdlReservedName,
3180             parTextId);
3181     mb_strcode(buffer, outfile);
3182     parTextId = 0;
3183     }
3184 }
3185
3186 void CloseVirpage()
3187 {
3188 if (parTextId)
3189     {
3190     fputs("<BLOCK>\n<P>", outfile);
3191     EmitSavedAnchors();
3192     fputs("</P>\n</BLOCK>", outfile);
3193     }
3194 fputs("</VIRPAGE>\n", outfile);
3195 }