dthelp: compiler warning and coverity warning fixes
[oweals/cde.git] / cde / programs / dthelp / parser / canon1 / 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:11 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 /* osf has the same function defined, change the routine name to fbasename() */
65 void fbasename(M_NOPAR)
66 {
67 char *p, *q;
68 int n;
69 char save;
70 char fileListErr[] = "filelist.err";
71
72 m_errfile = NULL;
73 if (m_argc < 2)
74     {
75     m_error("Specify input file");
76     exit(TRUE);
77     }
78
79 if ((m_argc > 2) && (strchr(m_argv[2], 'f') || strchr(m_argv[2], 'F')))
80     filelist = TRUE;
81
82 /* Get installation directory */
83 #define CONTRIB "/usr/dt/bin/"
84
85 /* get our path if we can */
86 /* A hacked up ``which'', just to find our directory */
87 /* fills ``install'' with path to ourself */
88 {
89 char *path, *cp;
90 char buf[200];
91 char patbuf[BUFSIZ];
92 int quit, none;
93
94 quit = 0;
95 none = 1;
96
97 if ( *(m_argv[0]) == '/' )
98     {
99     /* fully qualified path to ourself was specified */
100     if (access(m_argv[0],1) == 0)
101         {
102         /* if full path name exists and is executable */
103         /* get the dirname */
104         for (p = m_argv[0]; *p ; p++) ; /* end of string, (the hard way) */
105         /* backup to dirsep */
106         for (; ; p--)
107             {
108             if (p < m_argv[0]) m_error("Internal Error.");
109             if (*p == dirsep) break; 
110             }
111         p++; /* just past the dirsep */
112         save = *p;
113         *p = M_EOS;
114         install = (char *) m_malloc(strlen(m_argv[0]) + 1,
115                                     "installation directory");
116         strcpy(install, m_argv[0]);
117         *p = save;
118
119         none = 0; /* we've got it. */
120         }
121     else
122         {
123         m_error("Internal Error (which).");
124         }
125     }
126 else
127     {
128     /* not fully specified, check each component of path for ourself */
129     strcpy(patbuf, getenv("PATH"));
130     path = patbuf;
131     cp = path;
132
133     while(1)
134         {
135         cp = strchr(path, ':');
136         if (cp == NULL)
137         quit++;
138         else
139         *cp = '\0';
140         sprintf(buf, "%s/%s", path, m_argv[0]);
141
142         if (access(buf, 1) == 0)
143             {
144             install = (char*) m_malloc(strlen(path) + 1,
145                                        "installation directory");
146             strcpy(install, path);
147             none = 0;
148             }
149         /* else, not an error if we can't find a particular one. */
150
151         path = ++cp;
152         if (quit || !none)
153             {
154             break; /* either out of paths, or we found it. */
155             }
156         }  /* end while */
157     }
158
159 if (none)
160     {
161     /* can't get it, use default */
162     install = (char *) m_malloc(strlen(CONTRIB) + 1,
163                                 "installation directory");
164     strcpy(install, CONTRIB);
165     }
166 /* else -- we've got it */
167 }
168
169 /* Set default working directory (from input filename) */
170 for (p = strchr(m_argv[1], M_EOS); p > m_argv[1] ; p--)
171     if (*(p - 1) == dirsep)
172         break;
173 if (p > m_argv[1])
174     {
175     save = *p;
176     *p = M_EOS;
177     work = (char *) m_malloc(strlen(m_argv[1]) + 1, "working directory");
178     strcpy(work, m_argv[1]);
179     indir = (char *) m_malloc(strlen(m_argv[1]) + 1, "input directory");
180     strcpy(indir, m_argv[1]);
181     *p = save;
182     }
183 else
184     {
185     indir = NULL;
186     }
187
188 /* Build base name */
189 q = strchr(m_argv[1], M_EOS);
190 while ((q > m_argv[1]) && (*q != '.') && (*q != dirsep))
191     q--;
192 defaultext = (LOGICAL) (*q != '.');
193 if (! defaultext) *q = M_EOS;
194 nodirbase = (char *) m_malloc(strlen(p) + 1,
195                               "basename without directory");
196 strcpy(nodirbase, p);
197 /* Get working directory option, if specified */
198 n = strlen(p);
199 base = (char *) m_malloc(n + strlen(".ctg") + 1, "basename");
200 strcpy(base, p);
201 base[n] = '.';
202 baseext = base + n + 1;
203 if (! defaultext)
204     if (*(q + 1))
205         *q = '.';
206
207 options(TRUE); /* pluck only length changing optins */
208 if (usingshortnames)
209     {
210     /* Build short versions of basename */
211     /* set up global helpbase and helpext */
212     helpbase = (char *) m_malloc(strlen(work)            +
213                                      BASENAME_LIMIT      +
214                                      PRE_EXTENSION_LIMIT +
215                                      strlen(".ext")      +
216                                      1,
217                                  "help basename");
218     strcpy(helpbase, work);
219     strncat(helpbase, nodirbase, BASENAME_LIMIT);
220     helpext = helpbase + strlen(helpbase);
221     }
222 else
223     { /* Build long names */
224     /* set up global helpbase and helpext */
225     helpbase = (char *) m_malloc(strlen(work)            +
226                                      strlen(nodirbase)   +
227                                      PRE_EXTENSION_LIMIT +
228                                      strlen(".ext")      +
229                                      1,
230                                  "help basename");
231     strcpy(helpbase, work);
232     strcat(helpbase, nodirbase);
233     helpext = helpbase + strlen(helpbase);
234     }
235
236 /* Open error files */
237 if (filelist)
238     {
239     p = mb_malloc(strlen(work)+sizeof(fileListErr));
240     strcpy(p, work);
241     strcat(p, fileListErr);
242     m_openchk(&m_errfile, p, "w");
243     mb_free(&p);
244     }
245 else
246     {
247     strcpy(helpext, ".err");
248     m_openchk(&m_errfile, helpbase, "w");
249     }
250 }
251
252
253 /* This procedure starts a CHAPTER */
254 void chapstart(id)
255 M_WCHAR *id;
256 {
257 M_WCHAR *p, *q, *wc;
258 int i;
259 char *mbyte, *pc;
260 int   length;
261
262 char *chapterPrefixString =
263   GetDefaultHeaderString("ChapterElementDefaultHeadingString",
264                          M_SDATA,
265                          "Chapter");
266 char *chapterSuffixString =
267   GetDefaultHeaderString("ChapterSuffixElementDefaultHeadingString",
268                          M_SDATA,
269                          "");
270
271 rsectseq = FALSE;
272 chapst = FALSE;
273 chapinc = 0;
274 chapter++;
275 m_itoa(chapter, chapstring);
276
277 savid = checkid(id);
278 iderr = FALSE;
279
280 figno = 0;
281 tableno = 0;
282 footnoteno = 1;
283 fprintf(stderr,
284         "\n%s %s%s. ",
285         chapterPrefixString,
286         chapstring,
287         chapterSuffixString);
288 m_free(chapterPrefixString, "GetDefaultHeaderString return");
289 if (*chapterSuffixString)
290     m_free(chapterSuffixString, "GetDefaultHeaderString return");
291 }
292
293
294 /* Called at end of manual to report terms that occurred in the document
295    but not entered in the glossary */
296 void checkgloss(M_NOPAR)
297 {
298 int n;
299 M_WCHAR id[MAXTERM + 1];
300 M_TRIE *node[MAXTERM + 1];
301 M_TRIE *current;
302
303 if (! gtree.data) return;
304 n = 0;
305 current = gtree.data;
306 while (TRUE)
307     {
308     id[n] = current->symbol;
309     node[n] = current->next;
310     if (! id[n])
311         {
312         if ((intptr_t) current->data >= 0)
313             m_err1("No glossary definition for %s", id);
314         current = current->next;
315         while (! current)
316             {
317             n--;
318             if (n < 0) return;
319             current = node[n];
320             }
321         }
322     else
323         {
324         current = current->data;
325         n++;
326         }
327     }
328 }
329
330                 
331 /* End Error Message macro \starterrmsg call, check to see if Error Message
332    head is user specified or default */
333 void checkmsghead(M_NOPAR)
334 {
335 char *string =
336     GetDefaultHeaderString("MessagesElementDefaultHeadingString",
337                            M_SDATA,
338                            "Messages");
339 if (emsghead == DEFHEAD)
340     {  /* head not output yet */
341     fprintf(outfile, "<HEAD CLASS=\"HEAD\">%s</HEAD>\n", string);
342     emsghead = FALSE;
343     }
344 else if (emsghead == USERHEAD)
345     {  /* user specified head */
346     emsghead = FALSE;
347     }
348 m_free(string, "GetDefaultHeaderString return");
349 }  /* end checkmsghead() */
350
351
352 /* construct a qualified file name */
353 #if defined(M_PROTO)
354 static int mb_getqualified(char *qualname, char *unqualname)
355 #else
356 static int mb_getqualified(qualname, unqualname)
357 char *qualname;
358 char *unqualname;
359 #endif
360 {
361 #if defined(hpux) || defined(_AIX) || defined(sun) || defined(USL) || defined(__uxp__) || defined(__osf__) || defined(linux) || defined(CSRG_BASED)
362
363 FILE *f;
364 #endif
365 char fn[FNAMELEN];
366 char tokstr [ 20 ], *gp, *p, *pp, *fnp, curdir[FNAMELEN-1];
367 int roomleft = FNAMELEN - 1;
368
369 if (!unqualname)
370     {
371     *qualname = M_EOS;
372     return( 0 );
373     }
374
375 if (strlen(unqualname) < (size_t) FNAMELEN)
376     strcpy(fn, unqualname );
377 else
378     {
379     m_mberr1("Internal Error. File name too long for qualifying: %s",
380              unqualname);
381     return (-1);
382     }
383
384 fnp = fn;
385
386 #if defined(hpux) || defined(_AIX) || defined(sun) || defined(USL) || defined(__uxp__) || defined(__osf__) || defined(linux) || defined(CSRG_BASED)
387 qualname[0] = '\0';
388 gp = qualname + strlen(qualname);
389 roomleft = roomleft - strlen(qualname);
390
391 /* if path is from root, tack that on, else tack on the current
392  directory (for the referenced drive, if MS-DOS) */
393 /* We assume FNAMELEN is at least three (3), so no range checking here */
394 if ( *fnp == CSEP )
395     {
396     strcat(qualname, SSEP);
397     roomleft--;
398     ++fnp;
399     }
400 else
401     {
402     f = popen("/bin/pwd", "r");
403     fscanf(f, "%s", gp);
404     pclose(f);
405     if (strlen(gp) >= (size_t) roomleft)
406         {
407         m_mberr1("Internal error: possible stray pointer in getqualified(): %s",
408                  gp);
409         return(-1);
410         }
411     strcat(qualname,SSEP);
412     roomleft--;
413     }
414 #else
415 /* if MS-DOS, force to upper case, then get drive spec */
416 strupr ( fn );
417 if ( fn[1] == ':' ) {
418 strncpy ( qualname, fn, 2 );
419 fnp += 2;
420 }
421 else {
422 getcwd(qualname, roomleft);
423 }
424 qualname[2] = '\0';
425 gp = qualname + strlen ( qualname );
426 roomleft = roomleft - strlen ( qualname );
427 /* if path is from root, tack that on, else tack on the current
428  directory (for the referenced drive, if MS-DOS) */
429 if ( *fnp == CSEP ) {
430 strcat ( qualname, SSEP );
431 roomleft--;
432 ++fnp;
433 }
434 else {
435 /* assume current directory always !!! */
436 *gp = CSEP;
437 getcwd(curdir, FNAMELEN-1);
438 if (*curdir != *qualname) {
439   m_err1("Relative directory %s for non-current drive, can't qualify",
440           unqualname);
441   return (-1);
442   }
443 if (strlen(curdir) > 3) {
444   if ((strlen(curdir+3)+1) < roomleft) {  /* "1" for SSEP */
445     strcpy( gp+1, curdir+3 );
446     strcat ( qualname, SSEP );
447     roomleft = roomleft - strlen(curdir+3) - 1;  /* "1" for SSEP */
448     }
449   else {
450     m_err1("Internal error. File name too long for qualifying: %s",
451       unqualname);
452     return (-1);
453     }
454   }
455 }
456 #endif
457
458 strcpy(tokstr, " \r\n\t");
459 strcat(tokstr, SSEP);
460 p = NULL;
461 do  {
462     p = strtok(( p == NULL ) ? fnp : NULL, tokstr);
463     if ( p == NULL ) break;
464     if ( *p == '.' ) /* alias */
465         {
466         if ( *(p+1) == '.' ) /* parent */
467             {
468             *strrchr(qualname, CSEP) = '\0';
469             pp = strrchr(qualname, CSEP);
470             if (pp == NULL) /* FAIL */
471                 {
472                 m_mberr1("Internal error. Failed in qualifying %s", unqualname);
473                 return ( -1 );
474                 }
475             else
476                 {
477                 *(pp+1) = '\0';
478                 }
479             }
480         }
481     else
482         {
483         if ((strlen(p)+1) < (size_t) roomleft)
484             {  /* "1" for SSEP */
485             strcat(qualname, p);
486             strcat(qualname, SSEP);
487             roomleft = roomleft - strlen(p) - 1;
488             }
489         else
490             {
491             m_mberr1("Internal error. File name too long for qualifying: %s",
492                      unqualname);
493             return (-1);
494             }
495         }
496     }
497 while (1);
498 *strrchr(qualname, CSEP) = '\0';
499
500 #if defined(hpux) || defined(_AIX) || defined(sun) || defined(USL) || defined(__uxp__) || defined(__osf__) || defined(linux) || defined(CSRG_BASED)
501 #else
502 strupr ( qualname );
503 #endif
504
505 return ( 0 );
506 }  /* end mb_getqualified */
507
508
509 int getqualified (qualname, unqualname)
510 M_WCHAR *qualname;
511 M_WCHAR *unqualname;
512 {
513 int retval;
514 char mb_qualname[FNAMELEN],
515      mb_unqualname[FNAMELEN];
516
517 wcstombs(mb_qualname, qualname, FNAMELEN);
518 wcstombs(mb_unqualname, unqualname, FNAMELEN);
519
520 retval = mb_getqualified(mb_qualname, mb_unqualname);
521
522 mbstowcs(qualname, mb_qualname, FNAMELEN);
523 mbstowcs(unqualname, mb_unqualname, FNAMELEN);
524
525 return retval;
526 }
527
528
529 /* handle the common link and graphic code for <p> and <image> */
530 void
531 handle_link_and_graphic(parent,
532                         gentity,
533                         gposition,
534                         ghyperlink,
535                         glinktype,
536                         gdescription)
537 M_WCHAR *parent, *gentity, *gposition, *ghyperlink, *glinktype, *gdescription;
538 {
539 unsigned char etype, wheredef;
540 char *mb_content, *ssi, id[32];
541 static M_WCHAR empty = M_EOS;
542 char *leftright;
543
544 /* handle graphic specific code */
545 /* initialize some stuff first:
546 - file is the entity name,
547 - f_file is the content of the entity, used only if f_content nonNULL
548 - f_content is f_file with the relative pathname, initialized to NULL,
549 - f_contqual is fully qualified f_file, assigned ONLY IF
550   f_content nonNULL
551 */
552 file_ent = FALSE;
553 f_content = NULL;
554 f_contqual[0] = M_EOS;
555
556 /* get the position, default to left */
557 leftright = "LEFT";
558 if (gposition)
559     {
560     M_WCHAR *wc_left, *wc_right;
561
562     wc_right = MakeWideCharString(QRIGHT);
563     if (!m_wcupstrcmp(gposition, wc_right))
564         {
565         leftright = "RIGHT";
566         }
567     else
568         {
569         wc_left = MakeWideCharString(QLEFT);
570         if (m_wcupstrcmp(gposition, wc_left))
571             {
572             m_err1("Invalid value for gposition: `%s'", gposition);
573             }
574         m_free(wc_left,"wide character string");
575         }
576     m_free(wc_right,"wide character string");
577     }
578
579 /* check ENTITY and determine the figure type  */
580 if (gentity)
581     {
582     m_lookent(gentity, &etype, &f_file, &wheredef);
583     if (etype != M_SYSTEM)
584         {
585         M_WCHAR *wc_entsystem, *wc_entkw, *wc_stago, *wc_tagc;
586
587         wc_entsystem = MakeWideCharString(m_entsystem);
588         wc_entkw = MakeWideCharString(m_entkw);
589         wc_stago = MakeWideCharString(m_stago);
590         wc_tagc = MakeWideCharString(m_tagc);
591         m_err6(
592             "%s not a %s %s, as required for the ENTITY parameter of %s%s%s",
593                gentity,
594                wc_entsystem,
595                wc_entkw,
596                wc_stago,
597                m_parent(0),
598                wc_tagc);
599         m_free(wc_entsystem,"wide character string");
600         m_free(wc_entkw,"wide character string");
601         m_free(wc_stago,"wide character string");
602         m_free(wc_tagc,"wide character string");
603         }
604     else
605         {
606         file_ent = TRUE;
607         f_content = searchforfile(f_file);
608         if (f_content)
609             {
610             if (getqualified(f_contqual, f_content))
611                 {
612                 /* unsuccessful qual */
613                 if (w_strlen(f_content) < FNAMELEN)
614                     w_strcpy(f_contqual, f_content);
615                 else
616                     {
617                     m_err1("Internal error. File name too long: %s",
618                            f_content);
619                     m_exit(m_errexit);
620                     }
621                 }
622             }
623         else
624             {
625             m_err2("Can't find file %s (declared in entity %s)",
626                    f_file,
627                    gentity);
628             }
629         }
630     if (!f_content) f_content = &empty;
631
632     mb_content = MakeMByteString(f_content);
633     sprintf(id, "%s%d", sdlReservedName, NextId());
634     ssi = MakeMByteString(m_parent(0));
635     fprintf(outfile, "<HEAD SSI=\"%s-GRAPHIC-%s\">", ssi, leftright);
636     if (ghyperlink)
637         HandleLink(ghyperlink, glinktype, gdescription);
638     fprintf(outfile, "<SNREF>\n<REFITEM RID=\"%s\" ", id);
639     fputs("CLASS=\"FIGURE\"", outfile);
640     AddToSNB(id, mb_content);
641     m_free(mb_content,"multi-byte string");
642     }
643
644 /* and finish the position now */
645 if (gposition)
646     {
647     fprintf(outfile, " SSI=\"GRPH-%s\"", leftright);
648     }
649
650 if (gentity)
651     {
652     fputs("></REFITEM></SNREF>", outfile);
653     if (ghyperlink)
654         fputs("</LINK>", outfile);
655     fputs("</HEAD>", outfile);
656     }
657
658 if (!ghyperlink && (glinktype || gdescription))
659     {
660     m_eprefix();
661     fprintf(stderr,
662            "Error: %sP%s ghyperlink was undefined.\n",
663            m_stago,
664            m_tagc);
665     fprintf(m_errfile,
666            "Error: %sP%s ghyperlink was undefined.\n",
667            m_stago,
668            m_tagc);
669     fprintf(stderr,
670      "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
671            QJUMP,
672            QJUMPNEWVIEW,
673            QDEFINITION,
674            QEXECUTE,
675            QAPPDEFINED,
676            QMAN);
677     fprintf(m_errfile,
678      "Beware of using a reserved value such as:\n%s, %s, %s, %s, %s, or %s.\n",
679            QJUMP,
680            QJUMPNEWVIEW,
681            QDEFINITION,
682            QEXECUTE,
683            QAPPDEFINED,
684            QMAN);
685     m_errline("Use ``ghyperlink='' if the value contains non-alphabetics");
686     m_esuffix();
687     }
688 }
689
690 /* Process an item in a list */
691 #if defined(M_PROTO)
692 void Item(M_WCHAR *id)
693 #else
694 void Item(id)
695 M_WCHAR *id;
696 #endif
697 {
698 char orderString[32];
699 static char *ROMAN0[] =
700     {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
701 static char *ROMAN10[] =
702     {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
703 static char *ROMAN100[] =
704     {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
705 static char ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
706 static char *roman0[] =
707     {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
708 static char *roman10[] =
709     {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
710 static char *roman100[] =
711     {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
712 static char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
713 static char numbers[] = "0123456789";
714 static char romanString[]  = "ROMAN";
715 static char alphaString[]  = "ALPHA";
716 static char arabicString[] = "ARABIC";
717 int      count, metaCount;
718 char    *item_id;
719 char     label_id[SDLNAMESIZ+10];
720 int      listtype;
721 char    *type;
722 char    *loose;
723 char    *first;
724 LOGICAL  isBullet, isLoose, isFirst;
725 int     *pThisBulletId;
726 char     ssi[BIGBUF];
727
728 if (listitems[list].firstitem)
729     {
730     listitems[list].firstitem = FALSE;
731     }
732
733 count = ++lastlist->lastlist->count;
734 if (count > 999) count = 999; /* holy cow!  Big list. */
735 isFirst = FALSE;
736 if (count == 1)
737     {
738     isFirst = TRUE;
739     first = "FIRST-";
740     }
741 else
742     first = "";
743
744 isLoose = FALSE;
745 if (lastlist->lastlist->space == TIGHT)
746     loose = "TIGHT";
747 else
748     {
749     isLoose = TRUE;
750     loose = "LOOSE";
751     }
752
753 isBullet = FALSE;
754 listtype = lastlist->lastlist->type;
755 if (listtype == BULLET)
756     isBullet = TRUE;
757
758 if ((listtype != PLAIN) && (listtype != MILSPEC))
759     { /* don't emit label for type==PLAIN and type==MILSPEC */
760     if (isBullet)
761         {
762         if (isLoose)
763             {
764             if (isFirst)
765                 pThisBulletId = &firstLooseBulletId;
766             else
767                 {
768                 looseBulletIdIndex = (- looseBulletIdIndex) + 1;
769                 pThisBulletId = &looseBulletId[looseBulletIdIndex];
770                 }
771             }
772         else
773             {
774             if (isFirst)
775                 pThisBulletId = &firstBulletId;
776             else
777                 {
778                 bulletIdIndex = (- bulletIdIndex) + 1;
779                 pThisBulletId = &bulletId[bulletIdIndex];
780                 }
781             }
782         if (*pThisBulletId)
783             { /* use an existing block containing a bullet */
784             strcpy(label_id, sdlReservedName);
785             m_itoa(*pThisBulletId, label_id + SDLNAMESIZ - 1);
786             }
787         else
788             {
789             *pThisBulletId = NextId();
790             strcpy(label_id, sdlReservedName);
791             m_itoa(*pThisBulletId, label_id + SDLNAMESIZ - 1);
792             if (needFData)
793                 {
794                 fputs("<FDATA>\n", outfile);
795                 needFData = FALSE;
796                 }
797             fprintf(outfile,
798                     "<BLOCK ID=\"%s\" CLASS=\"ITEM\" TIMING=\"ASYNC\" ",
799                     label_id);
800             fprintf(outfile,
801                     "SSI=\"%s%s-BULLET\">\n<P><SPC NAME=\"[bull  ]\">",
802                     first,
803                     loose);
804             fputs("</P>\n</BLOCK>\n", outfile);
805             }
806         }
807     else
808         {
809         strcpy(label_id, sdlReservedName);
810         m_itoa(NextId(), label_id + SDLNAMESIZ - 1);
811         if (needFData)
812             {
813             fputs("<FDATA>\n", outfile);
814             needFData = FALSE;
815             }
816         fprintf(outfile, "<BLOCK ID=\"%s\" CLASS=\"ITEM\" SSI=\"", label_id);
817         }
818     }
819
820 item_id = NULL;
821 if (listtype == ORDER)
822     {
823     orderString[0] = '\0';
824     switch (lastlist->lastlist->order)
825         {
826         case UROMAN:
827             strcpy(orderString, ROMAN100[count / 100]);
828             strcat(orderString, ROMAN10[(count / 10) % 10]);
829             strcat(orderString, ROMAN0[count % 10]);
830             type = romanString;
831             break;
832         case UALPHA:
833             metaCount = 1;
834             while ((count -= 26) > 0) metaCount++;
835             count = lastlist->lastlist->count;
836             if (count > 999) count = 999;
837             count -= 1;
838             count %= 26;
839             while (--metaCount >= 0) strncat(orderString, &ALPHABET[count], 1);
840             type = alphaString;
841             break;
842         case ARABIC:
843             if (metaCount = (count / 100))
844                 strncat(orderString, &numbers[metaCount], 1);
845             if (metaCount || ((count / 10) % 10))
846                 strncat(orderString, &numbers[(count / 10) % 10], 1);
847             strncat(orderString, &numbers[count % 10], 1);
848             type = arabicString;
849             break;
850         case LROMAN:
851             strcpy(orderString, roman100[count / 100]);
852             strcat(orderString, roman10[(count / 10) % 10]);
853             strcat(orderString, roman0[count % 10]);
854             type = romanString;
855             break;
856         case LALPHA:
857             metaCount = 1;
858             while ((count -= 26) > 0) metaCount++;
859             count = lastlist->lastlist->count;
860             if (count > 999) count = 999;
861             count -= 1;
862             count %= 26;
863             while (--metaCount >= 0) strncat(orderString, &alphabet[count], 1);
864             type = alphaString;
865             break;
866         }
867     fprintf(outfile,
868             "%s%s-%s\">\n<P>%s%c",
869             first,
870             loose,
871             type,
872             orderString, 
873             lastlist->lastlist->punct == DOTPUNCT ? '.' : ')' );
874     if (id)
875         {
876         char buffer[400];
877         M_WCHAR *wc;
878
879         sprintf(buffer, "Item %s", orderString);
880         wc = MakeWideCharString(buffer);
881         w_strcpy(xrefstring, wc);
882         m_free(wc,"wide character string");
883
884         xstrlen = w_strlen(xrefstring);
885         m_getline(&xrffile, &xrfline);
886         if (xrffile == NULL)
887             {
888             /* set to primary input */
889             xrffile = inputname;
890             }
891
892         setid(id,
893              TRUE,
894              FALSE,
895              inchapter,
896              chapstring,
897              xrffile,
898              xrfline, TRUE);
899
900         item_id = MakeMByteString(id);
901         }
902     }
903 else
904     { /* Bullet, Check or Plain list */
905     if (id) m_error("Cross-reference ID in non-ORDER list not allowed");
906     /* already handled Bullet */
907     if (listtype == CHECK)
908         {
909         fprintf(outfile,
910                 "%s%s-CHECK\">\n<P><SPC NAME=\"[check ]\">",
911                 first,
912                 loose);
913         }
914     /* don't emit label for listtype==PLAIN and listtype==MILSPEC */
915     }
916
917 if ((listtype != PLAIN) && (listtype != MILSPEC) && (listtype != BULLET))
918     fputs("</P>\n</BLOCK>\n", outfile);
919
920 sprintf(ssi, "%s%s", first, loose);
921 if ((listtype == PLAIN) || (listtype == MILSPEC))
922     PushForm("ITEM", ssi, item_id);
923 else
924     PushForm2("ITEM", ssi, label_id, item_id);
925
926 if (item_id)
927     m_free(item_id, "multi-byte string");
928 }
929
930
931 /* Start a rsect */
932 void rsectstart(id)
933 M_WCHAR *id;
934 {
935 savid = checkid(id);
936 iderr = FALSE;
937 rsectseq = TRUE;
938 chapst = TRUE;
939 }  /* END procedure rsectstart  */
940
941
942 /* Called at the end of a chapter, appendix, or section to end an open
943    sequence of rsects */
944 void rseqend(M_NOPAR)
945 {
946 if (rsectseq)
947     --thisnodelevel;
948 rsectseq = FALSE;
949 }
950
951
952 /* Follow search path to find a file, returning qualified name */
953 M_WCHAR *searchforfile(file)
954 M_WCHAR *file;
955 {
956 M_WCHAR *filename;
957 SEARCH  *searchp;
958 char    *mb_file, mb_filename[2048];
959 int     dir_leng,file_leng;
960
961 mb_file = MakeMByteString(file);
962 if (! access(mb_file, READABLE))
963     {
964     filename = (M_WCHAR *)
965         m_malloc(w_strlen(file) + 1, "figure/icon filename");
966     w_strcpy(filename, file);
967     m_free(mb_file,"multi-byte string");
968     return(filename);
969     }
970
971 file_leng = strlen(mb_file);
972 for (searchp = path; searchp ; searchp = searchp->next)
973     {
974     if (((dir_leng = strlen(searchp->directory)) + file_leng) >= 2048)
975         {
976         M_WCHAR *wc;
977
978         wc = MakeWideCharString(searchp->directory);
979         m_err2("%s and %s overflow the file name space", wc, file);
980         m_free(wc,"wide character string");
981         continue;
982         }
983     strcpy(mb_filename, searchp->directory);
984     strcpy(mb_filename+dir_leng, mb_file);
985     if (! access(mb_filename, READABLE))
986         {
987         m_free(mb_file,"multi-byte string");
988         return(MakeWideCharString(mb_filename));
989         }
990     }
991
992 m_free(mb_file,"multi-byte string");
993 return(NULL);
994 }
995
996
997 /* Start a new helpnode */
998 #if defined(M_PROTO)
999 void starthelpnode(M_WCHAR *ssi,
1000                    M_WCHAR *id,
1001                    int      level)
1002 #else
1003 void starthelpnode(ssi, id, level)
1004 M_WCHAR *ssi;
1005 M_WCHAR *id;
1006 int      level;
1007 #endif
1008 {
1009 int i;
1010 char *mbyte, *mb_ssi;
1011 char mb_nodeid[NODEID_LENGTH+1], nodenum[32];
1012
1013 if (outfile != m_outfile)
1014     {
1015     m_error("Internal warning:  Outfile has been redirected.");
1016     m_errcnt--;
1017     }
1018
1019 fflush(m_outfile);
1020
1021 mb_ssi = MakeMByteString(ssi);
1022
1023 /* we can't use the bullet block across virpage boundaries */
1024 bulletId[0]        = 0;
1025 bulletId[1]        = 0;
1026 looseBulletId[0]   = 0;
1027 looseBulletId[1]   = 0;
1028 firstBulletId      = 0;
1029 firstLooseBulletId = 0;
1030
1031 /* might as well always start with id 0 (we flip first) */
1032 bulletIdIndex      = 1;
1033 looseBulletIdIndex = 1;
1034
1035 if ((id == NULL) || (*id == 0))
1036     {
1037     strcpy(mb_nodeid, sdlReservedName);
1038     m_itoa(NextId(), nodenum);
1039     strcpy(mb_nodeid + SDLNAMESIZ - 1, nodenum);
1040     mbstowcs(nodeid, mb_nodeid, NODEID_LENGTH);
1041     }
1042 else
1043     {
1044     w_strncpy(nodeid, id, NODEID_LENGTH);
1045     wcstombs(mb_nodeid, id, NODEID_LENGTH);
1046     }
1047
1048 fprintf(outfile,
1049 "<VIRPAGE ID=\"%s\" LEVEL=\"%d\" LANGUAGE=\"%s\" CHARSET=\"%s\" DOC-ID=\"%s\" SSI=\"%s\">\n",
1050         mb_nodeid,
1051         level,
1052         GetLanguage(),
1053         GetCharset(),
1054         docId,
1055         mb_ssi);
1056 m_free(mb_ssi,"multi-byte string");
1057 snbstart = ftell(outfile);
1058 } /* End starthelpnode(id) */
1059
1060
1061 #if defined(M_PROTO)
1062 void mb_starthelpnode(char   *ssi,
1063                       char   *id,
1064                       int     level)
1065 #else
1066 void mb_starthelpnode(ssi, id, level)
1067 char   *ssi;
1068 char   *id;
1069 int     level;
1070 #endif
1071 {
1072 M_WCHAR *wc_ssi, *wc_id;
1073
1074 wc_ssi = NULL;
1075 if (ssi)
1076     wc_ssi = MakeWideCharString(ssi);
1077 wc_id = NULL;
1078 if (id)
1079     wc_id  = MakeWideCharString(id);
1080 starthelpnode(wc_ssi, wc_id, level);
1081 if (wc_ssi)
1082     m_free(wc_ssi,"wide character string");
1083 if (wc_id)
1084     m_free(wc_id,"wide character string");
1085 }
1086
1087
1088 /* Start a labeled list */
1089 void StartLabList(spacing, longlabel)
1090 M_WCHAR *spacing;
1091 M_WCHAR *longlabel;
1092 {
1093        char *mb_spacing;
1094 static char  def_spacing[] = "LOOSE";
1095        char  ssi[32];
1096
1097 if (list >= MAXLISTLEV)
1098     m_error("Nesting of <LIST> and <LABLIST> too deep");
1099
1100 if (spacing)
1101     mb_spacing = MakeMByteString(spacing);
1102 else
1103     mb_spacing = def_spacing;
1104
1105 sprintf(ssi, "LABELED-%s", mb_spacing);
1106 PushForm("LIST", ssi, NULL);
1107
1108 if (mb_spacing != def_spacing)
1109     mb_free(&mb_spacing);
1110
1111 list++;
1112
1113 listitems[list].firstitem = TRUE;
1114 listitems[list].longlabel = vlonglabel(longlabel);
1115
1116 if (list <= MAXLISTLEV)
1117     {
1118     if (vspacing(spacing) == TIGHT)
1119         {
1120         lablisttight[list] = TRUE;
1121         }
1122     else
1123         {
1124         lablisttight[list] = FALSE;
1125         }
1126     }
1127 }
1128
1129
1130 /* Start a list */
1131 #if defined(M_PROTO)
1132 void StartList(M_WCHAR *type,
1133                M_WCHAR *order,
1134                M_WCHAR *spacing,
1135                M_WCHAR *cont)
1136 #else
1137 void StartList(type, order, spacing, cont)
1138 M_WCHAR *type, *order, *spacing, *cont;
1139 #endif
1140 {
1141 LIST *nextlist;
1142 CONTCHAIN *chain;
1143 CONTCHAIN *xchain;
1144 M_WCHAR *wc;
1145 char *mb_spacing;
1146 static char def_spacing[]  = "LOOSE";
1147 char *list_type;
1148 char  ssi[BIGBUF];
1149
1150 if (spacing)
1151     {
1152     mb_spacing = MakeMByteString(spacing);
1153     }
1154 else
1155     {
1156     mb_spacing = def_spacing;
1157     }
1158
1159 list++;
1160
1161 if (list > MAXLISTLEV)
1162     m_error("Nesting of <LIST> and <LABLIST> too deep");
1163
1164 if (! lastlist->started && cont)
1165     {
1166     m_error("No previous list to continue");
1167     cont = NULL;
1168     }
1169
1170 if (cont)
1171     {
1172     if (order && (vordertype(order) != lastlist->order))
1173         {
1174         m_error("Unable to continue a list and change the numbering scheme");
1175         cont = NULL;
1176         }
1177
1178     if (type && (vtype(type) != lastlist->type))
1179         {
1180         m_error("Unable to continue a list and change its type");
1181         cont = NULL;
1182         }
1183     }
1184
1185 if (! cont)
1186     { /* clear old list? */
1187     for (chain = lastlist->chain; chain ; chain = xchain)
1188         {
1189         xchain = chain->next;
1190         m_free(chain, "list chain");
1191         }
1192     lastlist->chain = NULL;
1193     lastlist->count = 0;
1194     }
1195
1196 /* If outermost list, initialize according to current defaults */
1197 if (! cont && lastlist == &outlist)
1198     {
1199     outlist.type       = vtype(NULL);
1200     outlist.order      = vordertype(NULL);
1201     outlist.count      = 0;
1202     outlist.space      = vspacing(NULL);
1203     outlist.punct      = DOTPUNCT;
1204     }
1205
1206 if (type) lastlist->type = vtype(type);
1207
1208 if (order)
1209     {
1210     lastlist->type = ORDER;
1211     lastlist->order = vordertype(order);
1212     }
1213
1214 switch (lastlist->type)
1215     {
1216     case MILSPEC:
1217     case PLAIN:
1218         list_type = "PLAIN";
1219         break;
1220     case CHECK:
1221         list_type = "CHECK";
1222         break;
1223     case ORDER:
1224         list_type = "ORDER";
1225         break;
1226     case BULLET:
1227     default:
1228         list_type = "BULLET";
1229     }
1230 sprintf(ssi, "%s-%s", list_type, mb_spacing);
1231
1232 PushForm("LIST", ssi, NULL);
1233
1234 if (mb_spacing != def_spacing)
1235     m_free(mb_spacing, "multi-byte string");
1236
1237
1238 lastlist->space = LOOSE;
1239 if (spacing && ! m_wcmbupstrcmp(spacing, QTIGHT)) lastlist->space = TIGHT;
1240
1241 if (type && order && m_wcmbupstrcmp(type, QORDER))
1242   m_err2("Incompatible specification for list: %s and %s", type, order);
1243
1244 if (lastlist->type == ORDER)
1245     {
1246     chain = (CONTCHAIN *) m_malloc(sizeof(CONTCHAIN), "list chain");
1247     chain->next = lastlist->chain;
1248     lastlist->chain = chain;
1249     chain->where = ftell(outfile);
1250     }
1251
1252 lastlist->started         = TRUE;
1253 listitems[list].firstitem = TRUE;
1254
1255 /* Prepare for sublist */
1256 nextlist = (LIST *) m_malloc(sizeof(LIST), "list structure");
1257 nextlist->lastlist = lastlist;
1258 nextlist->type = lastlist->type;
1259 nextlist->punct = lastlist->punct;
1260 if (lastlist->type == ORDER)
1261     {
1262     nextlist->order = lastlist->order + 1;
1263     if (nextlist->order > LROMAN)
1264         {
1265         nextlist->order = ARABIC;
1266         nextlist->punct = PARENPUNCT;
1267         }
1268     }
1269 else nextlist->order = lastlist->order;
1270 nextlist->count = 0;
1271 nextlist->space = lastlist->space;
1272 nextlist->started = FALSE;
1273 nextlist->where = FIRST;
1274 nextlist->chain = NULL;
1275 lastlist = nextlist;
1276 }
1277
1278
1279 void EndList()
1280 {
1281 LIST *curlist ;
1282 CONTCHAIN *chain, *xchain ;
1283 char *ncols;
1284
1285 curlist = lastlist->lastlist ;
1286
1287 if ((curlist->type == PLAIN) || (curlist->type == MILSPEC))
1288     PopForm();
1289 else
1290     PopForm2();
1291
1292 list-- ;
1293
1294 for (chain = lastlist->chain ; chain ; chain = xchain)
1295     {
1296     xchain = chain->next ;
1297     m_free(chain, "list chain") ;
1298     }
1299 m_free(lastlist, "list structure") ;
1300 lastlist = curlist ;
1301 for (chain = lastlist->chain ; chain ; chain = chain->next)
1302     {
1303     if (lastlist->count > 999)
1304         {
1305         m_error("Unable to support more than 999 items in an ordered list") ;
1306         lastlist->count = 999 ;
1307         }
1308     }
1309 if (lastlist->type == BULLET) bulcount-- ;
1310 }
1311
1312
1313 /* Open and initialize TeX file */
1314 void texinit(M_NOPAR)
1315 {
1316 LOGICAL init = TRUE;
1317 unsigned char type;
1318 M_WCHAR *content;
1319 unsigned char wheredef;
1320 M_WCHAR *name;
1321 M_WCHAR *qfile;
1322 LOGICAL icon;
1323 SEARCH *searchp;
1324 char *p;
1325 int ic;
1326 int i;
1327 M_WCHAR wsl;
1328 M_WCHAR *wc;
1329
1330 /* Check .XRF file */
1331 strcpy(helpext, ".xrh");
1332 xrf = fopen(helpbase, "r");
1333 if (! xrf) rebuild = TRUE;
1334 else
1335     {
1336     fscanf(xrf, "\\gobble\001");
1337     for (p = m_signon; *p ; p++)
1338         {
1339         ic = getc(xrf);
1340         if (ic != (int) *p)
1341             {
1342             m_errline(
1343         "Output files from different version of Tag, regenerating. . .\n");
1344             fclose(xrf);
1345             xrf = NULL;
1346             rebuild = TRUE;
1347             break;
1348             }
1349         }
1350     }
1351 if (xrf)
1352     while ((ic = getc(xrf)) != EOF)
1353         if (ic == '\n') break;
1354 if (xrf && ic !=EOF)
1355     while ((ic = getc(xrf)) != EOF)
1356         if (ic == '\n') break;
1357
1358 rebuild = TRUE;
1359
1360 /* Open output files */
1361 strcpy(helpext, ".sdl");
1362 m_openchk(&m_outfile, helpbase, "w");
1363 outfile = m_outfile;
1364
1365 savehelpfilename = (M_WCHAR *)m_malloc(strlen(helpbase)+1, "help file name");
1366 mbstowcs(savehelpfilename, helpbase, strlen(helpbase) + 1);
1367
1368 /* index file */
1369 strcpy(helpext, ".idx");
1370 m_openchk(&indexfp, helpbase, "wb");
1371
1372 /* system notation block file */
1373 strcpy(helpext, ".snb");
1374 m_openchk(&snbfp, helpbase, "wb");
1375
1376 while (name = m_cyclent(init, &type, &content, &wheredef))
1377     {
1378     init = FALSE;
1379     qfile = NULL;
1380     icon = FALSE;
1381
1382     if (type == M_SYSTEM)
1383         qfile = searchforfile(content);
1384
1385     if (qfile) m_free(qfile, "figure filename");
1386
1387     if (type == M_SYSTEM)
1388         {
1389         mbtowc(&wsl, "/", 1);
1390
1391         if (w_strchr(content, wsl))
1392             {
1393             m_err2("Avoid directory names in FILE entity %s: %s",
1394                    name,
1395                    content);
1396             m_errline("(Use the SEARCH option instead)\n");
1397             }
1398         }
1399     }
1400
1401 /* Include cross-reference file */
1402 strcpy(helpext, ".xrh");
1403 loadxref();
1404 postpreamble = ftell(outfile);
1405 }
1406
1407
1408 /* Lookup localized header string entity as defined (by default) in
1409    locallang.ent.  If the the header string was not found, or it was
1410    not of type "desiredType", return the default.
1411
1412    If the entity is of type file (M_SYSTEM) then if the content is not
1413    empty search the path for the file.  If the file is found, return
1414    its name else return an empty string.
1415
1416    If this routine returns anything other than the empty string (""),
1417    the string returned must be m_free'd.
1418 */
1419 char *
1420 #if defined(M_PROTO)
1421 GetDefaultHeaderString(
1422     char          *elementName,
1423     unsigned char  desiredType,
1424     char          *defaultString )
1425 #else
1426 GetDefaultHeaderString(elementName, desiredType, defaultString)
1427 char          *elementName;
1428 unsigned char  desiredType;
1429 char          *defaultString;
1430 #endif
1431 {
1432 unsigned char type,wheredef;
1433 M_WCHAR *content;
1434 M_WCHAR *path;
1435 M_WCHAR *wc_elementName;
1436 char    *mb_content;
1437 char    *retval;
1438
1439 wc_elementName = MakeWideCharString(elementName);
1440 if (m_lookent(wc_elementName, &type, &content, &wheredef))
1441     {
1442     if (type == desiredType)
1443         {
1444         if (type == M_SDATA)
1445             {
1446             m_free(wc_elementName,"wide character string");
1447             mb_content = MakeMByteString(content);
1448             if (!*mb_content)
1449                 {
1450                 m_free(mb_content,"multi-byte string");
1451                 return "";
1452                 }
1453             else
1454                 return mb_content;
1455             }
1456         if (*content)
1457             {
1458             path = searchforfile(content);
1459             if (!path)
1460                 {
1461                 m_err2("Can't find file %s (declared in entity %s)",
1462                        content,
1463                        wc_elementName);
1464                 m_free(wc_elementName,"wide character string");
1465                 return("");
1466                 }
1467             else
1468                 {
1469                 m_free(wc_elementName,"wide character string");
1470                 return MakeMByteString(path);
1471                 }
1472             }
1473         m_free(wc_elementName,"wide character string");
1474         return "";
1475         }
1476     }
1477
1478 m_free(wc_elementName,"wide character string");
1479 if (*defaultString)
1480     {
1481     retval = m_malloc(strlen(defaultString) + 1,
1482                       "GetDefaultHeaderString return");
1483     return strcpy(retval, defaultString);
1484     }
1485
1486 return "";
1487 }
1488
1489
1490 /* A function that takes a language/charset pair and:
1491  *     if they are standard, leave them unchanged but get local
1492  *                           versions and setlocale(3) using those
1493  *     if they are local, setlocale(3) with them and replace them with
1494  *                        standard versions.
1495 */
1496 static void
1497 #if defined(M_PROTO)
1498 SetStdLocale(char *pLang, char *pCharset)
1499 #else
1500 SetStdLocale(pLang, pCharset)
1501 char *pLang;
1502 char *pCharset;
1503 #endif
1504 {
1505 static const char *cString   = "C";
1506 static const char *isoString = "ISO-8859-1";
1507 _DtXlateDb  myDb = NULL;
1508 char        myPlatform[_DtPLATFORM_MAX_LEN+1];
1509 char        myLocale[256]; /* arbitrarily large */
1510 char       *locale;
1511 char       *lang;
1512 char       *charset;
1513 int         execVer;
1514 int         compVer;
1515 int         isStd;
1516
1517 strcpy(myLocale, pLang);
1518 if (*pCharset)
1519     {
1520     strcat(myLocale, ".");
1521     strcat(myLocale, pCharset);
1522     }
1523
1524 if ((_DtLcxOpenAllDbs(&myDb) != 0) ||
1525     (_DtXlateGetXlateEnv(myDb,myPlatform,&execVer,&compVer) != 0))
1526     {
1527     fprintf(stderr,
1528             "Warning: could not open locale translation database.\n");
1529     if (m_errfile != stderr)
1530         fprintf(m_errfile,
1531                 "Warning: could not open locale translation database.\n");
1532     strcpy(pLang, cString);
1533     strcpy(pCharset, isoString);
1534     if (myDb != 0)
1535         _DtLcxCloseDb(&myDb);
1536     return;
1537     }
1538
1539 isStd = !_DtLcxXlateOpToStd(myDb,
1540                             "CDE",
1541                             0,
1542                             DtLCX_OPER_STD,
1543                             myLocale,
1544                             NULL,
1545                             NULL,
1546                             NULL,
1547                             NULL);
1548
1549 if (isStd)
1550     { /* already standard - get local versions and set locale */
1551     if (_DtLcxXlateStdToOp(myDb,
1552                            myPlatform,
1553                            compVer,
1554                            DtLCX_OPER_SETLOCALE,
1555                            myLocale,
1556                            NULL,
1557                            NULL,
1558                            NULL,
1559                            &locale))
1560         {
1561         fprintf(stderr,
1562                 "Warning: could not translate CDE locale to local\n");
1563         if (m_errfile != stderr)
1564             fprintf(m_errfile,
1565                     "Warning: could not translate CDE locale to local\n");
1566         strcpy(pLang, cString);
1567         strcpy(pCharset, isoString);
1568         _DtLcxCloseDb(&myDb);
1569         return;
1570         }
1571     else
1572         {
1573         setlocale(LC_CTYPE, locale);
1574         mb_free(&locale);
1575         }
1576     }
1577 else
1578     { /* already local - set locale and get standard versions */
1579     if (_DtLcxXlateOpToStd(myDb,
1580                            myPlatform,
1581                            compVer,
1582                            DtLCX_OPER_SETLOCALE,
1583                            myLocale,
1584                            NULL,
1585                            &lang,
1586                            &charset,
1587                            NULL))
1588         {
1589         fprintf(stderr,
1590                 "Warning: could not translate local locale to CDE\n");
1591         if (m_errfile != stderr)
1592             fprintf(m_errfile,
1593                     "Warning: could not translate local locale to CDE\n");
1594         strcpy(pLang, cString);
1595         strcpy(pCharset, isoString);
1596         _DtLcxCloseDb(&myDb);
1597         return;
1598         }
1599     setlocale(LC_CTYPE, myLocale);
1600
1601     if (*lang)
1602         {
1603         strcpy(pLang, lang);
1604         mb_free(&lang);
1605         }
1606     else
1607         strcpy(pLang, cString);
1608
1609     if (*charset)
1610         {
1611         strcpy(pCharset, charset);
1612         mb_free(&charset);
1613         }
1614     else
1615         strcpy(pCharset, isoString);
1616     }
1617
1618 _DtLcxCloseDb(&myDb);
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 .ctg, .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 }