|
|
1.1 root 1: /* Code for handling XREF output from GNU C++.
2: Copyright (C) 1992, 1993 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
4:
5: This file is part of GNU CC.
6:
7: GNU CC is free software; you can redistribute it and/or modify
8: it under the terms of the GNU General Public License as published by
9: the Free Software Foundation; either version 2, or (at your option)
10: any later version.
11:
12: GNU CC is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with GNU CC; see the file COPYING. If not, write to
19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20:
21:
22: #include "config.h"
23: #include "tree.h"
24: #include <stdio.h>
25: #include "cp-tree.h"
26: #include "input.h"
27:
28: #include <ctype.h>
29:
30: extern char *getpwd ();
31:
32: extern char *index ();
33: extern char *rindex ();
34:
35: /* The character(s) used to join a directory specification (obtained with
36: getwd or equivalent) with a non-absolute file name. */
37:
38: #ifndef FILE_NAME_JOINER
39: #define FILE_NAME_JOINER "/"
40: #endif
41:
42: /* Nonzero if NAME as a file name is absolute. */
43: #ifndef FILE_NAME_ABSOLUTE_P
44: #define FILE_NAME_ABSOLUTE_P(NAME) (NAME[0] == '/')
45: #endif
46:
47: /* For cross referencing. */
48:
49: int flag_gnu_xref;
50:
51: /************************************************************************/
52: /* */
53: /* Common definitions */
54: /* */
55: /************************************************************************/
56:
57: #ifndef TRUE
58: #define TRUE 1
59: #endif
60: #ifndef FALSE
61: #define FALSE 0
62: #endif
63: #ifndef NULL
64: #define NULL 0
65: #endif
66:
67: #define PALLOC(typ) ((typ *) calloc(1,sizeof(typ)))
68:
69:
70: /* Return a malloc'd copy of STR. */
71: #define SALLOC(str) \
72: ((char *) ((str) == NULL ? NULL \
73: : (char *) strcpy ((char *) malloc (strlen ((str)) + 1), (str))))
74: #define SFREE(str) (str != NULL && (free(str),0))
75:
76: #define STREQL(s1,s2) (strcmp((s1),(s2)) == 0)
77: #define STRNEQ(s1,s2) (strcmp((s1),(s2)) != 0)
78: #define STRLSS(s1,s2) (strcmp((s1),(s2)) < 0)
79: #define STRLEQ(s1,s2) (strcmp((s1),(s2)) <= 0)
80: #define STRGTR(s1,s2) (strcmp((s1),(s2)) > 0)
81: #define STRGEQ(s1,s2) (strcmp((s1),(s2)) >= 0)
82:
83: /************************************************************************/
84: /* */
85: /* Type definitions */
86: /* */
87: /************************************************************************/
88:
89:
90: typedef struct _XREF_FILE * XREF_FILE;
91: typedef struct _XREF_SCOPE * XREF_SCOPE;
92:
93: typedef struct _XREF_FILE
94: {
95: char *name;
96: char *outname;
97: XREF_FILE next;
98: } XREF_FILE_INFO;
99:
100: typedef struct _XREF_SCOPE
101: {
102: int gid;
103: int lid;
104: XREF_FILE file;
105: int start;
106: XREF_SCOPE outer;
107: } XREF_SCOPE_INFO;
108:
109: /************************************************************************/
110: /* */
111: /* Local storage */
112: /* */
113: /************************************************************************/
114:
115: static char doing_xref = 0;
116: static FILE * xref_file = NULL;
117: static char xref_name[1024];
118: static XREF_FILE all_files = NULL;
119: static char * wd_name = NULL;
120: static XREF_SCOPE cur_scope = NULL;
121: static int scope_ctr = 0;
122: static XREF_FILE last_file = NULL;
123: static tree last_fndecl = NULL;
124:
125: /************************************************************************/
126: /* */
127: /* Forward definitions */
128: /* */
129: /************************************************************************/
130:
131: extern void GNU_xref_begin();
132: extern void GNU_xref_end();
133: extern void GNU_xref_file();
134: extern void GNU_xref_start_scope();
135: extern void GNU_xref_end_scope();
136: extern void GNU_xref_ref();
137: extern void GNU_xref_decl();
138: extern void GNU_xref_call();
139: extern void GNU_xref_function();
140: extern void GNU_xref_assign();
141: extern void GNU_xref_hier();
142: extern void GNU_xref_member();
143:
144: static void gen_assign();
145: static XREF_FILE find_file();
146: static char * filename();
147: static char * fctname();
148: static char * declname();
149: static void simplify_type();
150: static char * fixname();
151: static void open_xref_file();
152:
153: extern char * type_as_string();
154:
155: /* Start cross referencing. FILE is the name of the file we xref. */
156:
157: void
158: GNU_xref_begin (file)
159: char *file;
160: {
161: doing_xref = 1;
162:
163: if (file != NULL && STRNEQ (file,"-"))
164: {
165: open_xref_file(file);
166: GNU_xref_file(file);
167: }
168: }
169:
170: /* Finish cross-referencing. ERRCNT is the number of errors
171: we encountered. */
172:
173: void
174: GNU_xref_end (ect)
175: int ect;
176: {
177: XREF_FILE xf;
178:
179: if (!doing_xref) return;
180:
181: xf = find_file (input_filename);
182: if (xf == NULL) return;
183:
184: while (cur_scope != NULL)
185: GNU_xref_end_scope(cur_scope->gid,0,0,0,0);
186:
187: doing_xref = 0;
188:
189: if (xref_file == NULL) return;
190:
191: fclose (xref_file);
192:
193: xref_file = NULL;
194: all_files = NULL;
195:
196: if (ect > 0) unlink (xref_name);
197: }
198:
199: /* Write out xref for file named NAME. */
200:
201: void
202: GNU_xref_file (name)
203: char *name;
204: {
205: XREF_FILE xf;
206:
207: if (!doing_xref || name == NULL) return;
208:
209: if (xref_file == NULL)
210: {
211: open_xref_file (name);
212: if (!doing_xref) return;
213: }
214:
215: if (all_files == NULL)
216: fprintf(xref_file,"SCP * 0 0 0 0 RESET\n");
217:
218: xf = find_file (name);
219: if (xf != NULL) return;
220:
221: xf = PALLOC (XREF_FILE_INFO);
222: xf->name = SALLOC (name);
223: xf->next = all_files;
224: all_files = xf;
225:
226: if (wd_name == NULL)
227: wd_name = getpwd ();
228:
229: if (FILE_NAME_ABSOLUTE_P (name) || ! wd_name)
230: xf->outname = xf->name;
231: else
232: {
233: char *nmbuf
234: = (char *) malloc (strlen (wd_name) + strlen (FILE_NAME_JOINER)
235: + strlen (name) + 1);
236: sprintf (nmbuf, "%s%s%s", wd_name, FILE_NAME_JOINER, name);
237: name = nmbuf;
238: xf->outname = nmbuf;
239: }
240:
241: fprintf (xref_file, "FIL %s %s 0\n", name, wd_name);
242:
243: filename (xf);
244: fctname (NULL);
245: }
246:
247: /* Start a scope identified at level ID. */
248:
249: void
250: GNU_xref_start_scope (id)
251: HOST_WIDE_INT id;
252: {
253: XREF_SCOPE xs;
254: XREF_FILE xf;
255:
256: if (!doing_xref) return;
257: xf = find_file (input_filename);
258:
259: xs = PALLOC (XREF_SCOPE_INFO);
260: xs->file = xf;
261: xs->start = lineno;
262: if (xs->start <= 0) xs->start = 1;
263: xs->gid = id;
264: xs->lid = ++scope_ctr;
265: xs->outer = cur_scope;
266: cur_scope = xs;
267: }
268:
269: /* Finish a scope at level ID.
270: INID is ???
271: PRM is ???
272: KEEP is nonzero iff this scope is retained (nonzero if it's
273: a compiler-generated invisible scope).
274: TRNS is ??? */
275:
276: void
277: GNU_xref_end_scope (id,inid,prm,keep,trns)
278: HOST_WIDE_INT id;
279: HOST_WIDE_INT inid;
280: int prm,keep,trns;
281: {
282: XREF_FILE xf;
283: XREF_SCOPE xs,lxs,oxs;
284: char *stype;
285:
286: if (!doing_xref) return;
287: xf = find_file (input_filename);
288: if (xf == NULL) return;
289:
290: lxs = NULL;
291: for (xs = cur_scope; xs != NULL; xs = xs->outer)
292: {
293: if (xs->gid == id) break;
294: lxs = xs;
295: }
296: if (xs == NULL) return;
297:
298: if (inid != 0) {
299: for (oxs = cur_scope; oxs != NULL; oxs = oxs->outer) {
300: if (oxs->gid == inid) break;
301: }
302: if (oxs == NULL) return;
303: inid = oxs->lid;
304: }
305:
306: if (prm == 2) stype = "SUE";
307: else if (prm != 0) stype = "ARGS";
308: else if (keep == 2 || inid != 0) stype = "INTERN";
309: else stype = "EXTERN";
310:
311: fprintf (xref_file,"SCP %s %d %d %d %d %s\n",
312: filename (xf), xs->start, lineno,xs->lid, inid, stype);
313:
314: if (lxs == NULL) cur_scope = xs->outer;
315: else lxs->outer = xs->outer;
316:
317: free (xs);
318: }
319:
320: /* Output a reference to NAME in FNDECL. */
321:
322: void
323: GNU_xref_ref (fndecl,name)
324: tree fndecl;
325: char *name;
326: {
327: XREF_FILE xf;
328:
329: if (!doing_xref) return;
330: xf = find_file (input_filename);
331: if (xf == NULL) return;
332:
333: fprintf (xref_file, "REF %s %d %s %s\n",
334: filename (xf), lineno, fctname (fndecl), name);
335: }
336:
337: /* Output a reference to DECL in FNDECL. */
338:
339: void
340: GNU_xref_decl (fndecl,decl)
341: tree fndecl;
342: tree decl;
343: {
344: XREF_FILE xf,xf1;
345: char *cls;
346: char *name;
347: char buf[10240];
348: int uselin;
349:
350: if (!doing_xref) return;
351: xf = find_file (input_filename);
352: if (xf == NULL) return;
353:
354: uselin = FALSE;
355:
356: if (TREE_CODE (decl) == TYPE_DECL) cls = "TYPEDEF";
357: else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
358: else if (TREE_CODE (decl) == VAR_DECL)
359: {
360: if (fndecl == NULL && TREE_STATIC(decl)
361: && TREE_READONLY(decl) && DECL_INITIAL(decl) != 0
362: && !TREE_PUBLIC(decl) && !DECL_EXTERNAL(decl)
363: && DECL_MODE(decl) != BLKmode) cls = "CONST";
364: else if (DECL_EXTERNAL(decl)) cls = "EXTERN";
365: else if (TREE_PUBLIC(decl)) cls = "EXTDEF";
366: else if (TREE_STATIC(decl)) cls = "STATIC";
367: else if (DECL_REGISTER(decl)) cls = "REGISTER";
368: else cls = "AUTO";
369: }
370: else if (TREE_CODE (decl) == PARM_DECL) cls = "PARAM";
371: else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
372: else if (TREE_CODE (decl) == CONST_DECL) cls = "CONST";
373: else if (TREE_CODE (decl) == FUNCTION_DECL)
374: {
375: if (DECL_EXTERNAL (decl)) cls = "EXTERN";
376: else if (TREE_PUBLIC (decl)) cls = "EFUNCTION";
377: else cls = "SFUNCTION";
378: }
379: else if (TREE_CODE (decl) == LABEL_DECL) cls = "LABEL";
380: else if (TREE_CODE (decl) == UNION_TYPE)
381: {
382: cls = "UNIONID";
383: decl = TYPE_NAME (decl);
384: uselin = TRUE;
385: }
386: else if (TREE_CODE (decl) == RECORD_TYPE)
387: {
388: if (CLASSTYPE_DECLARED_CLASS (decl)) cls = "CLASSID";
389: else cls = "STRUCTID";
390: decl = TYPE_NAME (decl);
391: uselin = TRUE;
392: }
393: else if (TREE_CODE (decl) == ENUMERAL_TYPE)
394: {
395: cls = "ENUMID";
396: decl = TYPE_NAME (decl);
397: uselin = TRUE;
398: }
399: else cls = "UNKNOWN";
400:
401: if (decl == NULL || DECL_NAME (decl) == NULL) return;
402:
403: if (uselin && decl->decl.linenum > 0 && decl->decl.filename != NULL)
404: {
405: xf1 = find_file (decl->decl.filename);
406: if (xf1 != NULL)
407: {
408: lineno = decl->decl.linenum;
409: xf = xf1;
410: }
411: }
412:
413: if (DECL_ASSEMBLER_NAME (decl))
414: name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
415: else
416: name = IDENTIFIER_POINTER (DECL_NAME (decl));
417:
418: strcpy (buf, type_as_string (TREE_TYPE (decl), 0));
419: simplify_type (buf);
420:
421: fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
422: filename(xf), lineno, name,
423: (cur_scope != NULL ? cur_scope->lid : 0),
424: cls, fctname(fndecl), buf);
425:
426: if (STREQL (cls, "STRUCTID") || STREQL (cls, "UNIONID"))
427: {
428: cls = "CLASSID";
429: fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
430: filename(xf), lineno,name,
431: (cur_scope != NULL ? cur_scope->lid : 0),
432: cls, fctname(fndecl), buf);
433: }
434: }
435:
436: /* Output a reference to a call to NAME in FNDECL. */
437:
438: void
439: GNU_xref_call (fndecl, name)
440: tree fndecl;
441: char *name;
442: {
443: XREF_FILE xf;
444: char buf[1024];
445: char *s;
446:
447: if (!doing_xref) return;
448: xf = find_file (input_filename);
449: if (xf == NULL) return;
450: name = fixname (name, buf);
451:
452: for (s = name; *s != 0; ++s)
453: if (*s == '_' && s[1] == '_') break;
454: if (*s != 0) GNU_xref_ref (fndecl, name);
455:
456: fprintf (xref_file, "CAL %s %d %s %s\n",
457: filename (xf), lineno, name, fctname (fndecl));
458: }
459:
460: /* Output cross-reference info about FNDECL. If non-NULL,
461: ARGS are the arguments for the function (i.e., before the FUNCTION_DECL
462: has been fully built). */
463:
464: void
465: GNU_xref_function (fndecl, args)
466: tree fndecl;
467: tree args;
468: {
469: XREF_FILE xf;
470: int ct;
471: char buf[1024];
472:
473: if (!doing_xref) return;
474: xf = find_file (input_filename);
475: if (xf == NULL) return;
476:
477: ct = 0;
478: buf[0] = 0;
479: if (args == NULL) args = DECL_ARGUMENTS (fndecl);
480:
481: GNU_xref_decl (NULL, fndecl);
482:
483: for ( ; args != NULL; args = TREE_CHAIN (args))
484: {
485: GNU_xref_decl (fndecl,args);
486: if (ct != 0) strcat (buf,",");
487: strcat (buf, declname (args));
488: ++ct;
489: }
490:
491: fprintf (xref_file, "PRC %s %d %s %d %d %s\n",
492: filename(xf), lineno, declname(fndecl),
493: (cur_scope != NULL ? cur_scope->lid : 0),
494: ct, buf);
495: }
496:
497: /* Output cross-reference info about an assignment to NAME. */
498:
499: void
500: GNU_xref_assign(name)
501: tree name;
502: {
503: XREF_FILE xf;
504:
505: if (!doing_xref) return;
506: xf = find_file(input_filename);
507: if (xf == NULL) return;
508:
509: gen_assign(xf, name);
510: }
511:
512: static void
513: gen_assign(xf, name)
514: XREF_FILE xf;
515: tree name;
516: {
517: char *s;
518:
519: s = NULL;
520:
521: switch (TREE_CODE (name))
522: {
523: case IDENTIFIER_NODE :
524: s = IDENTIFIER_POINTER(name);
525: break;
526: case VAR_DECL :
527: s = declname(name);
528: break;
529: case COMPONENT_REF :
530: gen_assign(xf, TREE_OPERAND(name, 0));
531: gen_assign(xf, TREE_OPERAND(name, 1));
532: break;
533: case INDIRECT_REF :
534: case OFFSET_REF :
535: case ARRAY_REF :
536: case BUFFER_REF :
537: gen_assign(xf, TREE_OPERAND(name, 0));
538: break;
539: case COMPOUND_EXPR :
540: gen_assign(xf, TREE_OPERAND(name, 1));
541: break;
542: default :
543: break;
544: }
545:
546: if (s != NULL)
547: fprintf(xref_file, "ASG %s %d %s\n", filename(xf), lineno, s);
548: }
549:
550: /* Output cross-reference info about a class hierarchy.
551: CLS is the class type of interest. BASE is a baseclass
552: for CLS. PUB and VIRT give the visibility info about
553: the class derivation. FRND is nonzero iff BASE is a friend
554: of CLS.
555:
556: ??? Needs to handle nested classes. */
557: void
558: GNU_xref_hier(cls, base, pub, virt, frnd)
559: char *cls;
560: char *base;
561: int pub;
562: int virt;
563: int frnd;
564: {
565: XREF_FILE xf;
566:
567: if (!doing_xref) return;
568: xf = find_file(input_filename);
569: if (xf == NULL) return;
570:
571: fprintf(xref_file, "HIE %s %d %s %s %d %d %d\n",
572: filename(xf), lineno, cls, base, pub, virt, frnd);
573: }
574:
575: /* Output cross-reference info about class members. CLS
576: is the containing type; FLD is the class member. */
577:
578: void
579: GNU_xref_member(cls, fld)
580: tree cls;
581: tree fld;
582: {
583: XREF_FILE xf;
584: char *prot;
585: int confg, pure;
586: char *d;
587: int i;
588: char buf[1024], bufa[1024];
589:
590: if (!doing_xref) return;
591: xf = find_file(fld->decl.filename);
592: if (xf == NULL) return;
593:
594: if (TREE_PRIVATE (fld)) prot = "PRIVATE";
595: else if (TREE_PROTECTED(fld)) prot = "PROTECTED";
596: else prot = "PUBLIC";
597:
598: confg = 0;
599: if (TREE_CODE (fld) == FUNCTION_DECL && DECL_CONST_MEMFUNC_P(fld))
600: confg = 1;
601: else if (TREE_CODE (fld) == CONST_DECL)
602: confg = 1;
603:
604: pure = 0;
605: if (TREE_CODE (fld) == FUNCTION_DECL && DECL_ABSTRACT_VIRTUAL_P(fld))
606: pure = 1;
607:
608: d = IDENTIFIER_POINTER(cls);
609: sprintf(buf, "%d%s", strlen(d), d);
610: i = strlen(buf);
611: strcpy(bufa, declname(fld));
612:
613: #ifdef XREF_SHORT_MEMBER_NAMES
614: for (p = &bufa[1]; *p != 0; ++p)
615: {
616: if (p[0] == '_' && p[1] == '_' && p[2] >= '0' && p[2] <= '9') {
617: if (strncmp(&p[2], buf, i) == 0) *p = 0;
618: break;
619: }
620: else if (p[0] == '_' && p[1] == '_' && p[2] == 'C' && p[3] >= '0' && p[3] <= '9') {
621: if (strncmp(&p[3], buf, i) == 0) *p = 0;
622: break;
623: }
624: }
625: #endif
626:
627: fprintf(xref_file, "MEM %s %d %s %s %s %d %d %d %d %d %d %d\n",
628: filename(xf), fld->decl.linenum, d, bufa, prot,
629: (TREE_CODE (fld) == FUNCTION_DECL ? 0 : 1),
630: (DECL_INLINE (fld) ? 1 : 0),
631: (DECL_FRIEND_P(fld) ? 1 : 0),
632: (DECL_VINDEX(fld) ? 1 : 0),
633: (TREE_STATIC(fld) ? 1 : 0),
634: pure, confg);
635: }
636:
637: /* Find file entry given name. */
638:
639: static XREF_FILE
640: find_file(name)
641: char *name;
642: {
643: XREF_FILE xf;
644:
645: for (xf = all_files; xf != NULL; xf = xf->next) {
646: if (STREQL(name, xf->name)) break;
647: }
648:
649: return xf;
650: }
651:
652: /* Return filename for output purposes. */
653:
654: static char *
655: filename(xf)
656: XREF_FILE xf;
657: {
658: if (xf == NULL) {
659: last_file = NULL;
660: return "*";
661: }
662:
663: if (last_file == xf) return "*";
664:
665: last_file = xf;
666:
667: return xf->outname;
668: }
669:
670: /* Return function name for output purposes. */
671:
672: static char *
673: fctname(fndecl)
674: tree fndecl;
675: {
676: static char fctbuf[1024];
677: char *s;
678:
679: if (fndecl == NULL && last_fndecl == NULL) return "*";
680:
681: if (fndecl == NULL)
682: {
683: last_fndecl = NULL;
684: return "*TOP*";
685: }
686:
687: if (fndecl == last_fndecl) return "*";
688:
689: last_fndecl = fndecl;
690:
691: s = declname(fndecl);
692: s = fixname(s, fctbuf);
693:
694: return s;
695: }
696:
697: /* Return decl name for output purposes. */
698:
699: static char *
700: declname(dcl)
701: tree dcl;
702: {
703: if (DECL_NAME (dcl) == NULL) return "?";
704:
705: if (DECL_ASSEMBLER_NAME (dcl))
706: return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (dcl));
707: else
708: return IDENTIFIER_POINTER (DECL_NAME (dcl));
709: }
710:
711: /* Simplify a type string by removing unneeded parenthesis. */
712:
713: static void
714: simplify_type(typ)
715: char *typ;
716: {
717: char *s;
718: int lvl, i;
719:
720: i = strlen(typ);
721: while (i > 0 && isspace(typ[i-1])) typ[--i] = 0;
722:
723: if (i > 7 && STREQL(&typ[i-5], "const"))
724: {
725: typ[i-5] = 0;
726: i -= 5;
727: }
728:
729: if (typ[i-1] != ')') return;
730:
731: s = &typ[i-2];
732: lvl = 1;
733: while (*s != 0) {
734: if (*s == ')') ++lvl;
735: else if (*s == '(')
736: {
737: --lvl;
738: if (lvl == 0)
739: {
740: s[1] = ')';
741: s[2] = 0;
742: break;
743: }
744: }
745: --s;
746: }
747:
748: if (*s != 0 && s[-1] == ')')
749: {
750: --s;
751: --s;
752: if (*s == '(') s[2] = 0;
753: else if (*s == ':') {
754: while (*s != '(') --s;
755: s[1] = ')';
756: s[2] = 0;
757: }
758: }
759: }
760:
761: /* Fixup a function name (take care of embedded spaces). */
762:
763: static char *
764: fixname(nam, buf)
765: char *nam;
766: char *buf;
767: {
768: char *s, *t;
769: int fg;
770:
771: s = nam;
772: t = buf;
773: fg = 0;
774:
775: while (*s != 0)
776: {
777: if (*s == ' ')
778: {
779: *t++ = '\36';
780: ++fg;
781: }
782: else *t++ = *s;
783: ++s;
784: }
785: *t = 0;
786:
787: if (fg == 0) return nam;
788:
789: return buf;
790: }
791:
792: /* Open file for xrefing. */
793:
794: static void
795: open_xref_file(file)
796: char *file;
797: {
798: char *s, *t;
799:
800: #ifdef XREF_FILE_NAME
801: XREF_FILE_NAME (xref_name, file);
802: #else
803: s = rindex (file, '/');
804: if (s == NULL)
805: sprintf (xref_name, ".%s.gxref", file);
806: else
807: {
808: ++s;
809: strcpy (xref_name, file);
810: t = rindex (xref_name, '/');
811: ++t;
812: *t++ = '.';
813: strcpy (t, s);
814: strcat (t, ".gxref");
815: }
816: #endif /* no XREF_FILE_NAME */
817:
818: xref_file = fopen(xref_name, "w");
819:
820: if (xref_file == NULL)
821: {
822: error("Can't create cross-reference file `%s'", xref_name);
823: doing_xref = 0;
824: }
825: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.