1 /* Code for handling XREF output from GNU C++.
2 Copyright (C) 1992, 1993 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann (tiemann@cygnus.com)
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
GNU_xref_begin(file)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
GNU_xref_end(ect)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
GNU_xref_file(name)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
GNU_xref_start_scope(id)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
GNU_xref_end_scope(id,inid,prm,keep,trns)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
GNU_xref_ref(fndecl,name)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
GNU_xref_decl(fndecl,decl)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)));
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
GNU_xref_call(fndecl,name)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
GNU_xref_function(fndecl,args)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
GNU_xref_assign(name)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
gen_assign(xf,name)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
GNU_xref_hier(cls,base,pub,virt,frnd)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
GNU_xref_member(cls,fld)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
find_file(name)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 *
filename(xf)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 *
fctname(fndecl)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 *
declname(dcl)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
simplify_type(typ)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 *
fixname(nam,buf)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
open_xref_file(file)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 }
826