Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dthelp / parser / pass1 / helptag / xref.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 /* $XConsortium: xref.c /main/3 1995/11/08 10:13:50 rswiston $ */
24 /*
25 Copyright 1988, 1989 Hewlett-Packard Co.
26 */
27
28 /* HP Tag to TeX cross-reference processing */
29
30 #include "userinc.h"
31 #include "globdec.h"
32
33 /* Chk for duplicate xref id's, called in TEST, S1, S2, S3, S4, and rsect. */
34 M_WCHAR *checkid(id)
35 M_WCHAR *id;
36 {
37 struct xref *xref;
38 char *buffer;
39 char *mb_id;
40
41 if (!id) return(NULL);
42
43 m_getline(&xrffile, &xrfline);
44 if (xrffile == NULL)
45     {
46     /* set to primary input */
47     xrffile = inputname;
48     }
49
50 xref = (struct xref*) m_lookfortrie(id, &xtree);
51 if (!xref) return(id);  /* not in trie, so not previously defined */
52
53 if (!(xref->wheredef))  /* defined only in previous pass */
54     return(id);
55
56 /* else, we have a duplicate definition of id */
57 m_err1("Redefinition of ID '%s'", id);
58 mb_id = MakeMByteString(id);
59 buffer = (char *) m_malloc(1 + strlen(firstused) + strlen(mb_id) + 6,
60                            "error buffer");
61 sprintf(buffer, firstused, mb_id, xref->line);
62 m_errline(buffer);
63 m_free(buffer, "error buffer");
64 m_free(mb_id,"multi-byte string");
65
66 if (xref->file)
67     {
68     char *mb_file;
69
70     mb_file = MakeMByteString(xref->file);
71     buffer = (char *) m_malloc(1 - 2 + strlen(offile) + strlen(mb_file),
72                                "error buffer");
73     sprintf(buffer, offile, mb_file);
74     m_errline(buffer);
75     m_free(buffer, "error buffer");
76     m_free(mb_file,"multi-byte string");
77     }
78 m_errline(".\n");
79 return(NULL);
80 }
81
82 /* Write a single cross-reference macro definition */
83 static void defxref(xfile, id, xref)
84 FILE *xfile;
85 M_WCHAR *id;
86 struct xref *xref;
87 {
88 char *csname;
89 char *p;
90 char *buffer;
91
92 csname = MakeMByteString(id);
93 if (xref->defined)
94     {
95     char *mb_text;
96
97     mb_text = MakeMByteString(xref->textptr);
98     fprintf(xfile,
99             "\\definexref %s\\\\endxref\001%s\002\001%s",
100             csname,
101             mb_text,
102             xref->chapstring);
103     fprintf(xfile,
104             "\002\001%c\002\001%s\002\001%c\002%%\n",
105             xref->csensitive ? 'Y' : 'N',
106             xref->inchapter ? "\\LOCchap" : "\\LOCapp",
107             xref->xrefable ? 'Y' : 'N');
108     m_free(mb_text,"multi-byte string");
109     }
110 else
111     {
112     fprintf(xfile, "\\undefinedxref %s\\\\endxref\001", csname);
113     for (p = csname; *p ; p++)
114         outchar(*p, xfile);
115     fputs("\002%\n", xfile);
116     m_eprefix();  /* correctly delimit error in error file */
117     buffer = (char *) m_malloc(1 - 2 + strlen(undef) + w_strlen(id),
118                                "error buffer");
119     sprintf(buffer, undef, csname);
120     m_errline(buffer);
121     m_free(buffer, "error buffer");
122     if (xref->file)
123         {
124         char *mb_file;
125
126         mb_file = MakeMByteString(xref->file);
127         buffer = (char *) m_malloc(1 - 2 + strlen(infile) +
128                                    strlen(mb_file),
129                                    "error buffer");
130         sprintf(buffer, infile, mb_file);
131         m_errline(buffer);
132         m_free(buffer, "error buffer");
133         m_free(mb_file,"multi-byte string");
134         }
135     buffer = (char *) m_malloc(1 - 2 + strlen(online) + 10,
136                                "error buffer");
137     sprintf(buffer, online, xref->line);
138     m_errline(buffer);
139     m_free(buffer, "error buffer");
140     }
141 m_free(csname, "csname");
142 }
143
144 /* Write cross-reference file for next time document is processed
145    and TeX macro file for post-processing this pass */
146 void dumpxref(M_NOPAR)
147 {
148 int n;
149 M_WCHAR id[M_NAMELEN + 1];
150 M_TRIE *node[M_NAMELEN + 1];
151 M_TRIE *current;
152 FILE *tex;
153
154 strcpy(helpext, ".xrh");
155 tex = fopen(helpbase, "w");
156 fprintf(tex, "\\gobble\001%s\002%%\n", m_signon);
157 fputs("% Generated Cross-Reference Macros (for a particular document)\n", tex);
158 if (! xtree.data) return;
159
160 n = 0;
161 current = xtree.data;
162 while (TRUE)
163     {
164     id[n] = current->symbol;
165     node[n] = current->next;
166     if (! id[n])
167         {
168         /* Process one table entry */
169         defxref(tex, id, (struct xref *) current->data);
170
171         /* Look for the next one */
172         current = current->next;
173         while (! current)
174             {
175             n--;
176             if (n < 0)
177                 {
178                 fclose(tex);
179                 return;
180                 }
181             current = node[n];
182             }
183         }
184     else
185         {
186         current = current->data;
187         n++;
188         }
189     }
190 }
191
192 /* Copies string to end of current cross-reference string */
193 void idstring(string)
194 M_WCHAR *string;
195 {
196 int length;
197
198 length = w_strlen(string);
199 if (xstrlen + length + 1 > (sizeof(xrefstring) / sizeof(M_WCHAR)))
200     {
201     if (! iderr)
202         {
203         m_error(
204     "Internal error. Too many characters in cross-reference expansion.");
205         iderr = TRUE;
206         }
207     return;
208     }
209
210 w_strcpy(&xrefstring[xstrlen],string);
211 xstrlen += length;
212 }
213
214 /* Initializes cross-reference table reading in file output from previous
215    pass through document */
216 void loadxref(M_NOPAR)
217 {
218 M_WCHAR id[M_NAMELEN + 1];
219 char c, d;
220 int nextc;
221 int n;
222 LOGICAL csensitive;
223 LOGICAL inchapter;
224 LOGICAL xrefable;
225 char chapnum[15];
226 char string[15];
227 int braces;
228 M_WCHAR *p, *pStart;
229 static M_WCHAR wbs = 0, wca, wcb, wnl, weof;
230
231 if (! xrf) return;
232
233 if (!wbs)
234     {
235     char mb_eof;
236
237     mbtowc(&wbs, "\\", 1);
238     mbtowc(&wca, "\001", 1); /* ^A */
239     mbtowc(&wcb, "\002", 1); /* ^B */
240     mbtowc(&wnl, "\n", 1);
241     mb_eof = EOF;
242     mbtowc(&weof, &mb_eof, 1);
243     }
244
245 while (TRUE)
246     {
247     if (fscanf(xrf, "%14s ", string) != 1)
248         {
249         fclose(xrf);
250         return;
251         }
252     if (! strcmp(string, "\\undefinedxref"))
253         {
254         for (nextc = mb_getwc(xrf);
255              (nextc != wnl) && (nextc != weof);
256              nextc = mb_getwc(xrf)
257             );
258         continue;
259         }
260     for (n = 0; n <= M_NAMELEN ; n++)
261         {
262         nextc = mb_getwc(xrf); /* use mb_getwc to read multi-byte chars */
263         if (nextc == weof)
264             {
265             m_error("Incomplete cross-reference file.");
266             fclose(xrf);
267             return;
268             }
269         if (nextc == wbs) break;
270         id[n] = nextc;
271         }
272     if (n > M_NAMELEN)
273         {
274         m_error("Error in cross-reference file.");
275         fclose(xrf);
276         return;
277         }
278     pStart = p = MakeWideCharString("\\endxref\001");
279     for (; *p ; p++)
280         {
281         nextc = mb_getwc(xrf);
282         if (nextc != *p)
283             {
284             m_free(pStart,"wide character string");
285             m_error("Error in cross-reference file.");
286             fclose(xrf);
287             return;
288             }
289         }
290     m_free(pStart,"wide character string");
291     id[n] = M_EOS;
292     for (xstrlen = 0, braces = 1;
293          xstrlen < (sizeof(xrefstring) / sizeof(M_WCHAR));
294          xstrlen++)
295         {
296         xrefstring[xstrlen] = mb_getwc(xrf);
297         if (xrefstring[xstrlen] == wca) braces++;
298         else if (xrefstring[xstrlen] == wcb) if (! --braces) break;
299     }
300     if (xstrlen >= (sizeof(xrefstring) / sizeof(M_WCHAR)))
301         {
302         m_error("Error in cross-reference file");
303         fclose(xrf);
304         return;
305         }
306
307     xrefstring[xstrlen] = M_EOS;
308     if ((fscanf(xrf,
309                 "\001%14[^\002]\002\001%c\002\001%8[^\002]\002\001%c\002%%\n",
310                 chapnum, &c, string, &d) != 4)                ||
311             (c != 'Y' && c != 'N') ||  (d != 'Y' && d != 'N') || 
312             (strcmp(string, "\\LOCapp") && strcmp(string, "\\LOCchap"))
313        )
314         {
315         m_error("Error in cross-reference file");
316         fclose(xrf);
317         return;
318         }
319     csensitive = (LOGICAL) (c == 'Y');
320     inchapter = (LOGICAL) (strcmp(string, "\\LOCchap") == FALSE);
321     xrefable = (LOGICAL) (d == 'Y');
322     setid(id,
323           FALSE,
324           csensitive,
325           inchapter,
326           chapnum,
327           NULL,
328           0,
329           xrefable);
330     }
331 /* fclose(xrf);  ** not reachable; left in for future reference */
332 }
333
334
335 /* Save a cross-reference ID and associated expansion */
336 #if defined(M_PROTO)
337 void setid(M_WCHAR *id, LOGICAL where, LOGICAL csensitive, LOGICAL inchapter,
338            char *chapter, M_WCHAR *xrffile, int xrfline, LOGICAL xrefable)
339 #else
340 void setid(id, where, csensitive, inchapter, chapter, xrffile, xrfline, xrefable)
341 M_WCHAR *id;
342 LOGICAL where;
343 LOGICAL csensitive;
344 LOGICAL inchapter;
345 char *chapter;
346 M_WCHAR *xrffile;
347 int xrfline;
348 LOGICAL xrefable;
349 #endif
350 {
351 struct xref *old;
352 struct xref *xref;
353 char *buffer;
354
355 if (!*id)
356     {
357     m_err2("Erroneous cross reference of `%s' for id `%s'",
358     xrefstring,
359     id);
360     return;
361     }
362 xref = (struct xref *) m_malloc(sizeof(struct xref), "xref");
363 if (old = (struct xref *) m_ntrtrie(id, &xtree, (M_TRIE *) xref))
364     {
365     m_free(xref, "xref");
366     xref = old;
367     if (xref->wheredef)
368         {
369         char *mb_id;
370
371         mb_id = MakeMByteString(id);
372         m_err1("Redefinition of ID '%s'", id);
373         buffer = (char *)
374             m_malloc(1 + strlen(firstused) + w_strlen(id) + 6,
375                      "error buffer");
376         sprintf(buffer, firstused, mb_id, xref -> line);
377         m_errline(buffer);
378         m_free(buffer, "error buffer");
379         m_free(mb_id,"multi-byte string");
380         if (xref->file)
381             {
382             char *mb_file;
383
384             mb_file = MakeMByteString(xref->file);
385             buffer = (char *)
386                 m_malloc(1 - 2 + strlen(offile) + strlen(mb_file),
387                          "error message");
388             sprintf(buffer, offile, mb_file);
389             m_errline(buffer);
390             m_free(buffer, "error buffer");
391             m_free(mb_file,"multi-byte string");
392             }
393         m_errline(".\n");
394         return;
395         }
396     if (xref->defined)
397         {
398         if (w_strcmp(xrefstring, xref->textptr) != 0) /* ref has changed */
399             have_forward_xrefs = TRUE;         /* so force a second pass */
400         m_free(xref->chapstring, "xref chapter string");
401         m_free(xref->textptr, "xref text pointer");
402         }
403     }
404 else xref->retrieved = FALSE;
405
406 xref->defined = TRUE;
407 xref->wheredef = where;
408 xref->csensitive = csensitive;
409 xref->inchapter = inchapter;
410 xref->chapstring =
411     (char *) m_malloc(strlen(chapter) + 1, "xref chapter string");
412 xref->textptr = (M_WCHAR *) m_malloc(xstrlen + 1, "xref text pointer");
413 strcpy(xref->chapstring, chapter);
414 w_strcpy(xref->textptr, xrefstring);
415 xref->file = xrffile;
416 xref->line = xrfline;
417 xref->xrefable = xrefable;
418 xstrlen = 0;
419 savid = NULL;
420 }
421
422 /* Generate a cross-reference */
423 void xrefexpand(id)
424 M_WCHAR *id;
425 {
426 struct xref *xref;
427 struct xref *old;
428 #define format "\\<xref %s>"
429 char *texcode;
430 char *csname;
431
432 /* ID is 0 in case of a parameter error which MARKUP will report */
433 if (! id) return;
434
435 /* Write call to generated macro in output file */
436 csname = MakeMByteString(id);
437 texcode = (char *) m_malloc(sizeof(format) + strlen(csname), "texcode");
438 sprintf(texcode, format, csname);
439
440 if (echo)
441     {
442     mb_echohead(m_stago);
443     mb_echohead("XREF ");
444     echohead(id);
445     mb_echohead(m_tagc);
446     }
447
448 if (savhd)
449     mb_shstring(texcode,
450                 &svheadlen,
451                 (sizeof(savehead) / sizeof(M_WCHAR)),
452                 savehead,
453                 "Too many characters in head or caption",
454                 &hderr);
455
456 if (savtc)
457     mb_shstring(texcode,
458                 &svtclen,
459                 (sizeof(savetabcap) / sizeof(M_WCHAR)),
460                 savetabcap,
461                 "Too many characters in table caption",
462                 &hderr);
463
464 if (savid)
465     mb_shstring(texcode,
466                 &xstrlen,
467                 (sizeof(xrefstring) / sizeof(M_WCHAR)),
468                 xrefstring,
469                 "Too many characters in corresponding cross-reference",
470                 &iderr);
471
472 /* Enter id in xref table if it's not already there */
473 xref = (struct xref *) m_malloc(sizeof(struct xref), "xref");
474 if (old = (struct xref *) m_ntrtrie(id, &xtree, (M_TRIE *) xref))
475     {
476     /* non-NULL, we had an old one */
477     m_free(xref, "xref");
478     xref = old;
479     if (! xref->xrefable)
480         {
481         m_error("You can't cross reference to that type of tag");
482         /* but put out the string anyway... */
483
484         /* decrement error counter to treat this as a warning */
485         m_errcnt--;
486         }
487     if (xref->textptr)
488         {
489         /* we have an expansion */
490         char *mb_textptr;
491
492         if (!*xref->textptr)
493             {
494             m_err1("Empty cross reference for id `%s'", id);
495             return;
496             }
497
498         mb_textptr = MakeMByteString(xref->textptr);
499         fprintf(outfile,
500                 "<LINK RID=\"%s\">%s</LINK>",
501                 csname,
502                 mb_textptr);
503         m_free(mb_textptr,"multi-byte string");
504         }
505     else
506         { /* expansion */
507         /* dump out a tag string as a placeholder */
508         fputs(texcode, outfile);
509         /* not really forward, but a null string */
510         have_forward_xrefs = TRUE;
511         /*     xref->defined = FALSE;
512         xref->retrieved = FALSE;
513         xref->textptr = NULL;
514         xref->wheredef = FALSE;*/
515         }
516     }
517 else
518     { /* no old xref */
519     if (rebuild)
520         {
521         m_errline(
522             "Unresolved xrefs. Running HelpTag a second time may help.\n");
523         rebuild = FALSE;  /* one error message will do */
524         }
525     have_forward_xrefs = TRUE;
526     xref->defined = FALSE;
527     xref->retrieved = FALSE;
528     xref->textptr = NULL;
529     xref->wheredef = FALSE;
530
531     /* This is a forward ref.  We assume it is xrefable */
532     /* It will be set correctly if and when the ref is defined */
533     xref->xrefable = TRUE;
534
535     fputs(texcode, outfile);
536     }
537
538 /* Record retrieval status if this is the first reference */
539 if (! xref->retrieved && ! xref->defined)
540     {
541     m_getline(&xref->file, &xref->line);
542     if (xref->file == NULL)
543         {
544         /* set to primary input */
545         xref->file = inputname;
546         }
547     xref->retrieved = TRUE;
548     }
549 m_free(texcode, "texcode buffer");
550 m_free(csname, "csname");
551 }
552