calls.c (expand_call): Only destroy temporaries at the end of function calls, if...
[platform/upstream/gcc.git] / gcc / cp / xref.c
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
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 if (IS_SIGNATURE (decl)) cls = "SIGNATUREID";
390       else cls = "STRUCTID";
391       decl = TYPE_NAME (decl);
392       uselin = TRUE;
393     }
394   else if (TREE_CODE (decl) == ENUMERAL_TYPE)
395     {
396       cls = "ENUMID";
397       decl = TYPE_NAME (decl);
398       uselin = TRUE;
399     }
400   else cls = "UNKNOWN";
401
402   if (decl == NULL || DECL_NAME (decl) == NULL) return;
403
404   if (uselin && decl->decl.linenum > 0 && decl->decl.filename != NULL)
405     {
406       xf1 = find_file (decl->decl.filename);
407       if (xf1 != NULL)
408         {
409           lineno = decl->decl.linenum;
410           xf = xf1;
411         }
412     }
413
414   if (DECL_ASSEMBLER_NAME (decl))
415     name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
416   else
417     name = IDENTIFIER_POINTER (DECL_NAME (decl));
418
419   strcpy (buf, type_as_string (TREE_TYPE (decl), 0));
420   simplify_type (buf);
421
422   fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
423            filename(xf), lineno, name,
424            (cur_scope != NULL ? cur_scope->lid : 0),
425            cls, fctname(fndecl), buf);
426
427   if (STREQL (cls, "STRUCTID") || STREQL (cls, "UNIONID")
428       || STREQL (cls, "SIGNATUREID"))
429     {
430       cls = "CLASSID";
431       fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
432                filename(xf), lineno,name,
433                (cur_scope != NULL ? cur_scope->lid : 0),
434                cls, fctname(fndecl), buf);
435     }
436 }
437
438 /* Output a reference to a call to NAME in FNDECL.  */
439
440 void
441 GNU_xref_call (fndecl, name)
442    tree fndecl;
443    char *name;
444 {
445   XREF_FILE xf;
446   char buf[1024];
447   char *s;
448
449   if (!doing_xref) return;
450   xf = find_file (input_filename);
451   if (xf == NULL) return;
452   name = fixname (name, buf);
453
454   for (s = name; *s != 0; ++s)
455     if (*s == '_' && s[1] == '_') break;
456   if (*s != 0) GNU_xref_ref (fndecl, name);
457
458   fprintf (xref_file, "CAL %s %d %s %s\n",
459            filename (xf), lineno, name, fctname (fndecl));
460 }
461
462 /* Output cross-reference info about FNDECL.  If non-NULL,
463    ARGS are the arguments for the function (i.e., before the FUNCTION_DECL
464    has been fully built).  */
465
466 void
467 GNU_xref_function (fndecl, args)
468    tree fndecl;
469    tree args;
470 {
471   XREF_FILE xf;
472   int ct;
473   char buf[1024];
474
475   if (!doing_xref) return;
476   xf = find_file (input_filename);
477   if (xf == NULL) return;
478
479   ct = 0;
480   buf[0] = 0;
481   if (args == NULL) args = DECL_ARGUMENTS (fndecl);
482
483   GNU_xref_decl (NULL, fndecl);
484
485   for ( ; args != NULL; args = TREE_CHAIN (args))
486     {
487       GNU_xref_decl (fndecl,args);
488       if (ct != 0) strcat (buf,",");
489       strcat (buf, declname (args));
490       ++ct;
491     }
492
493   fprintf (xref_file, "PRC %s %d %s %d %d %s\n",
494            filename(xf), lineno, declname(fndecl),
495            (cur_scope != NULL ? cur_scope->lid : 0),
496            ct, buf);
497 }
498
499 /* Output cross-reference info about an assignment to NAME.  */
500
501 void
502 GNU_xref_assign(name)
503    tree name;
504 {
505   XREF_FILE xf;
506
507   if (!doing_xref) return;
508   xf = find_file(input_filename);
509   if (xf == NULL) return;
510
511   gen_assign(xf, name);
512 }
513
514 static void
515 gen_assign(xf, name)
516    XREF_FILE xf;
517    tree name;
518 {
519   char *s;
520
521   s = NULL;
522
523   switch (TREE_CODE (name))
524     {
525     case IDENTIFIER_NODE :
526       s = IDENTIFIER_POINTER(name);
527       break;
528     case VAR_DECL :
529       s = declname(name);
530       break;
531     case COMPONENT_REF :
532       gen_assign(xf, TREE_OPERAND(name, 0));
533       gen_assign(xf, TREE_OPERAND(name, 1));
534       break;
535     case INDIRECT_REF :
536     case OFFSET_REF :
537     case ARRAY_REF :
538     case BUFFER_REF :
539       gen_assign(xf, TREE_OPERAND(name, 0));
540       break;
541     case COMPOUND_EXPR :
542       gen_assign(xf, TREE_OPERAND(name, 1));
543       break;
544       default :
545       break;
546     }
547
548   if (s != NULL)
549     fprintf(xref_file, "ASG %s %d %s\n", filename(xf), lineno, s);
550 }
551
552 /* Output cross-reference info about a class hierarchy.
553    CLS is the class type of interest.  BASE is a baseclass
554    for CLS.  PUB and VIRT give the access info about
555    the class derivation.  FRND is nonzero iff BASE is a friend
556    of CLS.
557
558    ??? Needs to handle nested classes.  */
559 void
560 GNU_xref_hier(cls, base, pub, virt, frnd)
561    char *cls;
562    char *base;
563    int pub;
564    int virt;
565    int frnd;
566 {
567   XREF_FILE xf;
568
569   if (!doing_xref) return;
570   xf = find_file(input_filename);
571   if (xf == NULL) return;
572
573   fprintf(xref_file, "HIE %s %d %s %s %d %d %d\n",
574           filename(xf), lineno, cls, base, pub, virt, frnd);
575 }
576
577 /* Output cross-reference info about class members.  CLS
578    is the containing type; FLD is the class member.  */
579
580 void
581 GNU_xref_member(cls, fld)
582    tree cls;
583    tree fld;
584 {
585   XREF_FILE xf;
586   char *prot;
587   int confg, pure;
588   char *d;
589   int i;
590   char buf[1024], bufa[1024];
591
592   if (!doing_xref) return;
593   xf = find_file(fld->decl.filename);
594   if (xf == NULL) return;
595
596   if (TREE_PRIVATE (fld)) prot = "PRIVATE";
597   else if (TREE_PROTECTED(fld)) prot = "PROTECTED";
598   else prot = "PUBLIC";
599
600   confg = 0;
601   if (TREE_CODE (fld) == FUNCTION_DECL && DECL_CONST_MEMFUNC_P(fld))
602     confg = 1;
603   else if (TREE_CODE (fld) == CONST_DECL)
604     confg = 1;
605
606   pure = 0;
607   if (TREE_CODE (fld) == FUNCTION_DECL && DECL_ABSTRACT_VIRTUAL_P(fld))
608     pure = 1;
609
610   d = IDENTIFIER_POINTER(cls);
611   sprintf(buf, "%d%s", strlen(d), d);
612   i = strlen(buf);
613   strcpy(bufa, declname(fld));
614
615 #ifdef XREF_SHORT_MEMBER_NAMES
616   for (p = &bufa[1]; *p != 0; ++p)
617     {
618       if (p[0] == '_' && p[1] == '_' && p[2] >= '0' && p[2] <= '9') {
619         if (strncmp(&p[2], buf, i) == 0) *p = 0;
620         break;
621       }
622       else if (p[0] == '_' && p[1] == '_' && p[2] == 'C' && p[3] >= '0' && p[3] <= '9') {
623         if (strncmp(&p[3], buf, i) == 0) *p = 0;
624         break;
625       }
626     }
627 #endif
628
629   fprintf(xref_file, "MEM %s %d %s %s %s %d %d %d %d %d %d %d\n",
630           filename(xf), fld->decl.linenum, d,  bufa,  prot,
631           (TREE_CODE (fld) == FUNCTION_DECL ? 0 : 1),
632           (DECL_INLINE (fld) ? 1 : 0),
633           (DECL_FRIEND_P(fld) ? 1 : 0),
634           (DECL_VINDEX(fld) ? 1 : 0),
635           (TREE_STATIC(fld) ? 1 : 0),
636           pure, confg);
637 }
638
639 /* Find file entry given name.  */
640
641 static XREF_FILE
642 find_file(name)
643    char *name;
644 {
645   XREF_FILE xf;
646
647   for (xf = all_files; xf != NULL; xf = xf->next) {
648     if (STREQL(name, xf->name)) break;
649   }
650
651   return xf;
652 }
653
654 /* Return filename for output purposes.  */
655
656 static char *
657 filename(xf)
658    XREF_FILE xf;
659 {
660   if (xf == NULL) {
661     last_file = NULL;
662     return "*";
663   }
664
665   if (last_file == xf) return "*";
666
667   last_file = xf;
668
669   return xf->outname;
670 }
671
672 /* Return function name for output purposes.  */
673
674 static char *
675 fctname(fndecl)
676    tree fndecl;
677 {
678   static char fctbuf[1024];
679   char *s;
680
681   if (fndecl == NULL && last_fndecl == NULL) return "*";
682
683   if (fndecl == NULL)
684     {
685       last_fndecl = NULL;
686       return "*TOP*";
687     }
688
689   if (fndecl == last_fndecl) return "*";
690
691   last_fndecl = fndecl;
692
693   s = declname(fndecl);
694   s = fixname(s, fctbuf);
695
696   return s;
697 }
698
699 /* Return decl name for output purposes.  */
700
701 static char *
702 declname(dcl)
703    tree dcl;
704 {
705   if (DECL_NAME (dcl) == NULL) return "?";
706
707   if (DECL_ASSEMBLER_NAME (dcl))
708     return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (dcl));
709   else
710     return IDENTIFIER_POINTER (DECL_NAME (dcl));
711 }
712
713 /* Simplify a type string by removing unneeded parenthesis.  */
714
715 static void
716 simplify_type(typ)
717    char *typ;
718 {
719   char *s;
720   int lvl, i;
721
722   i = strlen(typ);
723   while (i > 0 && isspace(typ[i-1])) typ[--i] = 0;
724
725   if (i > 7 && STREQL(&typ[i-5], "const"))
726     {
727       typ[i-5] = 0;
728       i -= 5;
729     }
730
731   if (typ[i-1] != ')') return;
732
733   s = &typ[i-2];
734   lvl = 1;
735   while (*s != 0) {
736     if (*s == ')') ++lvl;
737     else if (*s == '(')
738       {
739         --lvl;
740         if (lvl == 0)
741           {
742             s[1] = ')';
743             s[2] = 0;
744             break;
745           }
746       }
747     --s;
748   }
749
750   if (*s != 0 && s[-1] == ')')
751     {
752       --s;
753       --s;
754       if (*s == '(') s[2] = 0;
755       else if (*s == ':') {
756         while (*s != '(') --s;
757         s[1] = ')';
758         s[2] = 0;
759       }
760     }
761 }
762
763 /* Fixup a function name (take care of embedded spaces).  */
764
765 static char *
766 fixname(nam, buf)
767    char *nam;
768    char *buf;
769 {
770   char *s, *t;
771   int fg;
772
773   s = nam;
774   t = buf;
775   fg = 0;
776
777   while (*s != 0)
778     {
779       if (*s == ' ')
780         {
781           *t++ = '\36';
782           ++fg;
783         }
784       else *t++ = *s;
785       ++s;
786     }
787   *t = 0;
788
789   if (fg == 0) return nam;
790
791   return buf;
792 }
793
794 /* Open file for xrefing.  */
795
796 static void
797 open_xref_file(file)
798    char *file;
799 {
800   char *s, *t;
801
802 #ifdef XREF_FILE_NAME
803   XREF_FILE_NAME (xref_name, file);
804 #else
805   s = rindex (file, '/');
806   if (s == NULL)
807     sprintf (xref_name, ".%s.gxref", file);
808   else
809     {
810       ++s;
811       strcpy (xref_name, file);
812       t = rindex (xref_name, '/');
813       ++t;
814       *t++ = '.';
815       strcpy (t, s);
816       strcat (t, ".gxref");
817     }
818 #endif /* no XREF_FILE_NAME */
819
820   xref_file = fopen(xref_name, "w");
821
822   if (xref_file == NULL)
823     {
824       error("Can't create cross-reference file `%s'", xref_name);
825       doing_xref = 0;
826     }
827 }