OSDN Git Service

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