xref: /386bsd/usr/src/usr.bin/g++/cc1plus/cp-xref.c (revision a2142627)
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