How about a predefined #FILE, #PATH and #FUNCTION for C?

Joseph S. D. Yao jsdy at hadron.UUCP
Tue Jan 28 23:36:29 AEST 1986


In article <312 at yale.ARPA> grace at yale.ARPA (Joseph Grace) writes:
>    error.h:
>	#define TEST printf ("FILE: error has occurred\n");
>...
>    output of test (on BSD 4.2 Pyramid):
>	FILE: error has occurred
>	/* not "test: error has occurred" as I would prefer */
>#FILE, #PATH and #FUNCTION would solve these problems.

First, let's drop the '#', otherwise we'll have to re-define our
concept of "identifier".  If you want uniqueness, let's go for
__FILE__ (which, along with __LINE__ does exist in many C
implementations, including 4.2BSD).

Second, for better compatibility, let's define TEST to be:
	printf("%s: ...\n", __FILE__);
Indeed, this won't work otherwise.

Now, for other things, you can sometimes use your SCCS and RCS
keywords.  Because you mentioned that this is a software project
under ongoing development, I assume you are using SCCS or RCS,
unless this is an undergrad programming project and your teachers
have not showed you SCCS or RCS (and shame on them if so!!!).
I routinely include something like:

#ifndef	lint
# ifdef	SCCS
    static char SCCS_id[] = "%W%";
#  else
    static char RCS_id[] =
	"@(#)$Header:$";
# endif	/*SCCS*/
#endif/*lint*/

ifndef lint so that lint won't complain.  SCCS is defined or not
in <local.h>.  "@(#)" prefix to $Header:$ because RCS doesn't do
it and I want what(1) to recognise the header.  Now, the second
word in each of these is the module name.  In SCCS, you can have
a separate string containing just "%M%" that is the module name.
In RCS, "$Source:$" will be the full path name (also in $Header:$
instead of module name in older RCS's).

BTW, <local.h> is what we're using to include bsd_4, bsd_4_2,
s5, s5r2, s5r2v2, SCCS, RCS, vax_785, m68020, and whatever other
configuration-dependent defines aren't already in the compiler
(like vax, m68k) or other files like <sys/param.h>.

I routinely want to use the command name (rather than the module
name) in my fprintf(stderr,...)'s.  This is especially true when
one command is linked with several names.  I do this:

#define DIRC	'/'
#ifdef	s5
#  define	rindex	strrchr
#  define	index	strchr
#endif/*s5*/
char *myname;
main(argc, argv, envp)
  int argc;
  char **argv;
  char **envp;
{
	extern char *rindex();
	if (argc > 0) {
		myname = rindex(*argv, DIRC);
		if (myname == (char *) NULL)
			myname = *argv;
		  else
			++myname;
	}
	...
}

'myname' is available to the whole program.

I have occasionally wanted to know at all times what function I
was in.  Here is one way:

#ifdef	EBUG
#  define	FUNBEG(fname)	\
			char *last_fnname;\
			extern char *fnname;\
			last_fnname = fnname;\
			fnname = "FUNCTION fname()";
#  define	FUNEND	fnname = last_fnname;
#  define	FUNCHG(fname,newstr)	\
			fnname = "IN FUNCTION fname(): newstr";
# else
#  define	FUNBEG(fname)
#  define	FUNEND
#  define	FUNCHG(fname,newstr)
#endif/*EBUG*/

Then inside a function:
func(a, b, c)
  int a, b, c;
{
	<decls>

	FUNBEG(func)	/* This must be right after decls! */
	...
	FUNCHG(func, this has just happened)
	...
	FUNEND		/* Before any explicit or implicit return */
}

Now, when you compile this -DEBUG you will always have a string
that reflects where you are (you  d i d  put this in main(), too,
didn't you?); while if you drop -DEBUG you get more space!  Note
that this must be re-written for ANSI C:
			fnname = "FUNCTION " fname "()";
			fnname = "IN FUNCTION " fname "(): " newstr;
	FUNBEG("func")	/* This must be right after decls! */
	FUNCHG("func", "this has just happened")

[In some ways, this is preferable.  The old way, you could get:
#define f(s)	printf("%s:" s)
	f(cp); -> printf("%cp", cp);]
-- 

	Joe Yao		hadron!jsdy at seismo.{CSS.GOV,ARPA,UUCP}



More information about the Comp.lang.c mailing list