OSDN Git Service

* repo.c (getpwd): Don't prototype.
[pf3gnuchains/gcc-fork.git] / gcc / cp / xref.c
1 /* Code for handling XREF output from GNU C++.
2    Copyright (C) 1992, 93-97, 1998 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 #include "toplev.h"
29
30 /* The character(s) used to join a directory specification (obtained with
31    getwd or equivalent) with a non-absolute file name.  */
32
33 #ifndef FILE_NAME_JOINER
34 #define FILE_NAME_JOINER "/"
35 #endif
36
37 /* Nonzero if NAME as a file name is absolute.  */
38 #ifndef FILE_NAME_ABSOLUTE_P
39 #define FILE_NAME_ABSOLUTE_P(NAME) (NAME[0] == '/')
40 #endif
41
42 /* For cross referencing.  */
43
44 int flag_gnu_xref;
45
46 /************************************************************************/
47 /*                                                                      */
48 /*      Common definitions                                              */
49 /*                                                                      */
50 /************************************************************************/
51
52 #ifndef TRUE
53 #define TRUE 1
54 #endif
55 #ifndef FALSE
56 #define FALSE 0
57 #endif
58
59 #define PALLOC(typ) ((typ *) xcalloc(1,sizeof(typ)))
60
61
62 /* Return a malloc'd copy of STR.  */
63 #define SALLOC(str) \
64  ((char *) ((str) == NULL ? NULL        \
65             : (char *) strcpy ((char *) xmalloc (strlen ((str)) + 1), (str))))
66 #define SFREE(str) (str != NULL && (free(str),0))
67
68 #define STREQL(s1,s2) (strcmp((s1),(s2)) == 0)
69 #define STRNEQ(s1,s2) (strcmp((s1),(s2)) != 0)
70 #define STRLSS(s1,s2) (strcmp((s1),(s2)) < 0)
71 #define STRLEQ(s1,s2) (strcmp((s1),(s2)) <= 0)
72 #define STRGTR(s1,s2) (strcmp((s1),(s2)) > 0)
73 #define STRGEQ(s1,s2) (strcmp((s1),(s2)) >= 0)
74
75 /************************************************************************/
76 /*                                                                      */
77 /*      Type definitions                                                */
78 /*                                                                      */
79 /************************************************************************/
80
81
82 typedef struct _XREF_FILE *     XREF_FILE;
83 typedef struct _XREF_SCOPE *    XREF_SCOPE;
84
85 typedef struct _XREF_FILE
86 {
87   const char *name;
88   const char *outname;
89   XREF_FILE next;
90 } XREF_FILE_INFO;
91
92 typedef struct _XREF_SCOPE
93 {
94   int gid;
95   int lid;
96   XREF_FILE file;
97   int start;
98   XREF_SCOPE outer;
99 } XREF_SCOPE_INFO;
100
101 /************************************************************************/
102 /*                                                                      */
103 /*      Local storage                                                   */
104 /*                                                                      */
105 /************************************************************************/
106
107 static  char            doing_xref = 0;
108 static  FILE *          xref_file = NULL;
109 static  char            xref_name[1024];
110 static  XREF_FILE       all_files = NULL;
111 static  char *          wd_name = NULL;
112 static  XREF_SCOPE      cur_scope = NULL;
113 static  int     scope_ctr = 0;
114 static  XREF_FILE       last_file = NULL;
115 static  tree            last_fndecl = NULL;
116
117 /************************************************************************/
118 /*                                                                      */
119 /*      Forward definitions                                             */
120 /*                                                                      */
121 /************************************************************************/
122 static  void            gen_assign PROTO((XREF_FILE, tree));
123 static  XREF_FILE       find_file PROTO((const char *));
124 static  const char *    filename PROTO((XREF_FILE));
125 static  const char *    fctname PROTO((tree));
126 static  const char *    declname PROTO((tree));
127 static  void            simplify_type PROTO((char *));
128 static  const char *    fixname PROTO((const char *, char *));
129 static  void            open_xref_file PROTO((const char *));
130 static  const char *    classname PROTO((tree));
131
132 /* Start cross referencing.  FILE is the name of the file we xref.  */
133
134 void
135 GNU_xref_begin (file)
136    const 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    const 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 *) xmalloc (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   const 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 ",
289            filename (xf), xs->start, lineno,xs->lid);
290   fprintf (xref_file, HOST_WIDE_INT_PRINT_DEC, inid);
291   fprintf (xref_file, " %s\n", stype);
292
293   if (lxs == NULL) cur_scope = xs->outer;
294   else lxs->outer = xs->outer;
295
296   free (xs);
297 }
298
299 /* Output a reference to NAME in FNDECL.  */
300
301 void
302 GNU_xref_ref (fndecl,name)
303    tree fndecl;
304    const char *name;
305 {
306   XREF_FILE xf;
307
308   if (!doing_xref) return;
309   xf = find_file (input_filename);
310   if (xf == NULL) return;
311
312   fprintf (xref_file, "REF %s %d %s %s\n",
313            filename (xf), lineno, fctname (fndecl), name);
314 }
315
316 /* Output a reference to DECL in FNDECL.  */
317
318 void
319 GNU_xref_decl (fndecl,decl)
320    tree fndecl;
321    tree decl;
322 {
323   XREF_FILE xf,xf1;
324   const char *cls = 0;
325   const char *name;
326   char buf[10240];
327   int uselin;
328
329   if (!doing_xref) return;
330   xf = find_file (input_filename);
331   if (xf == NULL) return;
332
333   uselin = FALSE;
334
335   if (TREE_CODE (decl) == TYPE_DECL) cls = "TYPEDEF";
336   else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
337   else if (TREE_CODE (decl) == VAR_DECL)
338     {
339       if (fndecl == NULL && TREE_STATIC(decl)
340           && TREE_READONLY(decl) && DECL_INITIAL(decl) != 0
341           && !TREE_PUBLIC(decl) && !DECL_EXTERNAL(decl)
342           && DECL_MODE(decl) != BLKmode) cls = "CONST";
343       else if (DECL_EXTERNAL(decl)) cls = "EXTERN";
344       else if (TREE_PUBLIC(decl)) cls = "EXTDEF";
345       else if (TREE_STATIC(decl)) cls = "STATIC";
346       else if (DECL_REGISTER(decl)) cls = "REGISTER";
347       else cls = "AUTO";
348     }
349   else if (TREE_CODE (decl) == PARM_DECL) cls = "PARAM";
350   else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
351   else if (TREE_CODE (decl) == CONST_DECL) cls = "CONST";
352   else if (TREE_CODE (decl) == FUNCTION_DECL)
353     {
354       if (DECL_EXTERNAL (decl)) cls = "EXTERN";
355       else if (TREE_PUBLIC (decl)) cls = "EFUNCTION";
356       else cls = "SFUNCTION";
357     }
358   else if (TREE_CODE (decl) == LABEL_DECL) cls = "LABEL";
359   else if (TREE_CODE (decl) == UNION_TYPE)
360     {
361       cls = "UNIONID";
362       decl = TYPE_NAME (decl);
363       uselin = TRUE;
364     }
365   else if (TREE_CODE (decl) == RECORD_TYPE)
366     {
367       if (CLASSTYPE_DECLARED_CLASS (decl)) cls = "CLASSID";
368       else cls = "STRUCTID";
369       decl = TYPE_NAME (decl);
370       uselin = TRUE;
371     }
372   else if (TREE_CODE (decl) == ENUMERAL_TYPE)
373     {
374       cls = "ENUMID";
375       decl = TYPE_NAME (decl);
376       uselin = TRUE;
377     }
378   else if (TREE_CODE (decl) == TEMPLATE_DECL)
379     {
380       if (TREE_CODE (DECL_RESULT (decl)) == TYPE_DECL)
381         cls = "CLASSTEMP";
382       else if (TREE_CODE (DECL_RESULT (decl)) == FUNCTION_DECL)
383         cls = "FUNCTEMP";
384       else if (TREE_CODE (DECL_RESULT (decl)) == VAR_DECL)
385         cls = "VARTEMP";
386       else
387         my_friendly_abort (358);
388       uselin = TRUE;
389     }
390   else cls = "UNKNOWN";
391
392   if (decl == NULL || DECL_NAME (decl) == NULL) return;
393
394   if (uselin && decl->decl.linenum > 0 && decl->decl.filename != NULL)
395     {
396       xf1 = find_file (decl->decl.filename);
397       if (xf1 != NULL)
398         {
399           lineno = decl->decl.linenum;
400           xf = xf1;
401         }
402     }
403
404   if (DECL_ASSEMBLER_NAME (decl))
405     name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
406   else
407     name = IDENTIFIER_POINTER (DECL_NAME (decl));
408
409   strcpy (buf, type_as_string (TREE_TYPE (decl), 0));
410   simplify_type (buf);
411
412   fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
413            filename(xf), lineno, name,
414            (cur_scope != NULL ? cur_scope->lid : 0),
415            cls, fctname(fndecl), buf);
416
417   if (STREQL (cls, "STRUCTID") || STREQL (cls, "UNIONID"))
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    const char *name;
433 {
434   XREF_FILE xf;
435   char buf[1024];
436   const 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   const 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 static const char *
542 classname (cls)
543      tree cls;
544 {
545   if (cls && TREE_CODE_CLASS (TREE_CODE (cls)) == 't')
546     cls = TYPE_NAME (cls);
547   if (cls && TREE_CODE_CLASS (TREE_CODE (cls)) == 'd')
548     cls = DECL_NAME (cls);
549   if (cls && TREE_CODE (cls) == IDENTIFIER_NODE)
550     return IDENTIFIER_POINTER (cls);
551   return "?";
552 }
553
554 /* Output cross-reference info about a class hierarchy.
555    CLS is the class type of interest.  BASE is a baseclass
556    for CLS.  PUB and VIRT give the access info about
557    the class derivation.  FRND is nonzero iff BASE is a friend
558    of CLS.
559
560    ??? Needs to handle nested classes.  */
561
562 void
563 GNU_xref_hier(cls, base, pub, virt, frnd)
564    tree cls;
565    tree base;
566    int pub;
567    int virt;
568    int frnd;
569 {
570   XREF_FILE xf;
571
572   if (!doing_xref) return;
573   xf = find_file(input_filename);
574   if (xf == NULL) return;
575
576   fprintf(xref_file, "HIE %s %d %s %s %d %d %d\n",
577           filename(xf), lineno, classname (cls), classname (base), 
578           pub, virt, frnd);
579 }
580
581 /* Output cross-reference info about class members.  CLS
582    is the containing type; FLD is the class member.  */
583
584 void
585 GNU_xref_member(cls, fld)
586    tree cls;
587    tree fld;
588 {
589   XREF_FILE xf;
590   const char *prot;
591   int confg, pure;
592   const char *d;
593 #ifdef XREF_SHORT_MEMBER_NAMES
594   int i;
595 #endif
596   char buf[1024], bufa[1024];
597
598   if (!doing_xref) return;
599   xf = find_file(fld->decl.filename);
600   if (xf == NULL) return;
601
602   if (TREE_PRIVATE (fld)) prot = "PRIVATE";
603   else if (TREE_PROTECTED(fld)) prot = "PROTECTED";
604   else prot = "PUBLIC";
605
606   confg = 0;
607   if (TREE_CODE (fld) == FUNCTION_DECL && DECL_CONST_MEMFUNC_P(fld))
608     confg = 1;
609   else if (TREE_CODE (fld) == CONST_DECL)
610     confg = 1;
611
612   pure = 0;
613   if (TREE_CODE (fld) == FUNCTION_DECL && DECL_ABSTRACT_VIRTUAL_P(fld))
614     pure = 1;
615
616   d = IDENTIFIER_POINTER(cls);
617   sprintf(buf, "%d%s", (int) strlen(d), d);
618 #ifdef XREF_SHORT_MEMBER_NAMES
619   i = strlen(buf);
620 #endif
621   strcpy(bufa, declname(fld));
622
623 #ifdef XREF_SHORT_MEMBER_NAMES
624   for (p = &bufa[1]; *p != 0; ++p)
625     {
626       if (p[0] == '_' && p[1] == '_' && p[2] >= '0' && p[2] <= '9') {
627         if (strncmp(&p[2], buf, i) == 0) *p = 0;
628         break;
629       }
630       else if (p[0] == '_' && p[1] == '_' && p[2] == 'C' && p[3] >= '0' && p[3] <= '9') {
631         if (strncmp(&p[3], buf, i) == 0) *p = 0;
632         break;
633       }
634     }
635 #endif
636
637   fprintf(xref_file, "MEM %s %d %s %s %s %d %d %d %d %d %d %d\n",
638           filename(xf), fld->decl.linenum, d,  bufa,  prot,
639           (TREE_CODE (fld) == FUNCTION_DECL ? 0 : 1),
640           (DECL_INLINE (fld) ? 1 : 0),
641           (DECL_LANG_SPECIFIC(fld) && DECL_FRIEND_P(fld) ? 1 : 0),
642           (DECL_VINDEX(fld) ? 1 : 0),
643           (TREE_STATIC(fld) ? 1 : 0),
644           pure, confg);
645 }
646
647 /* Find file entry given name.  */
648
649 static XREF_FILE
650 find_file(name)
651    const char *name;
652 {
653   XREF_FILE xf;
654
655   for (xf = all_files; xf != NULL; xf = xf->next) {
656     if (STREQL(name, xf->name)) break;
657   }
658
659   return xf;
660 }
661
662 /* Return filename for output purposes.  */
663
664 static const char *
665 filename(xf)
666    XREF_FILE xf;
667 {
668   if (xf == NULL) {
669     last_file = NULL;
670     return "*";
671   }
672
673   if (last_file == xf) return "*";
674
675   last_file = xf;
676
677   return xf->outname;
678 }
679
680 /* Return function name for output purposes.  */
681
682 static const char *
683 fctname(fndecl)
684    tree fndecl;
685 {
686   static char fctbuf[1024];
687   const char *s;
688
689   if (fndecl == NULL && last_fndecl == NULL) return "*";
690
691   if (fndecl == NULL)
692     {
693       last_fndecl = NULL;
694       return "*TOP*";
695     }
696
697   if (fndecl == last_fndecl) return "*";
698
699   last_fndecl = fndecl;
700
701   s = declname(fndecl);
702   s = fixname(s, fctbuf);
703
704   return s;
705 }
706
707 /* Return decl name for output purposes.  */
708
709 static const char *
710 declname(dcl)
711    tree dcl;
712 {
713   if (DECL_NAME (dcl) == NULL) return "?";
714
715   if (DECL_ASSEMBLER_NAME (dcl))
716     return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (dcl));
717   else
718     return IDENTIFIER_POINTER (DECL_NAME (dcl));
719 }
720
721 /* Simplify a type string by removing unneeded parenthesis.  */
722
723 static void
724 simplify_type(typ)
725    char *typ;
726 {
727   char *s;
728   int lvl, i;
729
730   i = strlen(typ);
731   while (i > 0 && ISSPACE((unsigned char) typ[i-1])) typ[--i] = 0;
732
733   if (i > 7 && STREQL(&typ[i-5], "const"))
734     {
735       typ[i-5] = 0;
736       i -= 5;
737     }
738
739   if (typ[i-1] != ')') return;
740
741   s = &typ[i-2];
742   lvl = 1;
743   while (*s != 0) {
744     if (*s == ')') ++lvl;
745     else if (*s == '(')
746       {
747         --lvl;
748         if (lvl == 0)
749           {
750             s[1] = ')';
751             s[2] = 0;
752             break;
753           }
754       }
755     --s;
756   }
757
758   if (*s != 0 && s[-1] == ')')
759     {
760       --s;
761       --s;
762       if (*s == '(') s[2] = 0;
763       else if (*s == ':') {
764         while (*s != '(') --s;
765         s[1] = ')';
766         s[2] = 0;
767       }
768     }
769 }
770
771 /* Fixup a function name (take care of embedded spaces).  */
772
773 static const char *
774 fixname(nam, buf)
775    const char *nam;
776    char *buf;
777 {
778   const char *s;
779   char *t;
780   int fg;
781
782   s = nam;
783   t = buf;
784   fg = 0;
785
786   while (*s != 0)
787     {
788       if (*s == ' ')
789         {
790           *t++ = '\36';
791           ++fg;
792         }
793       else *t++ = *s;
794       ++s;
795     }
796   *t = 0;
797
798   if (fg == 0) return nam;
799
800   return buf;
801 }
802
803 /* Open file for xreffing.  */
804
805 static void
806 open_xref_file(file)
807    const char *file;
808 {
809   const char *s;
810   char *t;
811
812 #ifdef XREF_FILE_NAME
813   XREF_FILE_NAME (xref_name, file);
814 #else
815   s = rindex (file, '/');
816   if (s == NULL)
817     sprintf (xref_name, ".%s.gxref", file);
818   else
819     {
820       ++s;
821       strcpy (xref_name, file);
822       t = rindex (xref_name, '/');
823       ++t;
824       *t++ = '.';
825       strcpy (t, s);
826       strcat (t, ".gxref");
827     }
828 #endif /* no XREF_FILE_NAME */
829
830   xref_file = fopen(xref_name, "w");
831
832   if (xref_file == NULL)
833     {
834       error("Can't create cross-reference file `%s'", xref_name);
835       doing_xref = 0;
836     }
837 }