[comp.sources.unix] v20i080: Modify files to help remove multiple #include's

rsalz@uunet.uu.net (Rich Salz) (10/28/89)

Submitted-by: "Fred J. E. Long" <flong@sdsu.edu>
Posting-number: Volume 20, Issue 80
Archive-name: multi-include

[  I believe this is a solution in search of a problem, but the ongoing
   discussion in comp.lang.c and comp.lang.c++ indicates that lots of
   people are interested in something like this.  /r$ ]

Here is a very simple program I wrote after seeing the recent
controversy in comp.lang.c++ over "multiple inclusion".  It just puts
	#if FILENAME != 0
	#define FILENAME 0
at the top of each file (if the -i option is specified) and puts
	#endif /* FILENAME */
at the bottom.  The -o option does likewise, but it puts the macros around
all the #includes:
	#include "foobar.h"
goes to:
	#ifndef FOOBAR_H
	#define FOOBAR_H 1
	#include "foobar.h"
	#endif /* FOOBAR_H */
	
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	include.1
#	include.c
#	makefile
#	run_test
#	test.c
#	test.h
sed 's/^X//' << 'SHAR_EOF' > README
XHere is a very simple program I wrote after seeing the recent
Xcontroversy in comp.lang.c++ over "multiple inclusion".  It just puts
X
X#if FILENAME != 0
X#define FILENAME 0
X
Xat the top of each file (if the -i option is specified) and puts
X
X#endif /* FILENAME */
X
Xat the bottom.  The -o option does likewise, but it puts the macros around
Xall the #includes:
X
X#include "foobar.h"
X
Xgoes to:
X
X#ifndef FOOBAR_H
X#define FOOBAR_H 1
X#include "foobar.h"
X#endif /* FOOBAR_H */
X
XIt would be a good idea to backup your files before using this program.
XHave fun.
X
X----
XFred J. E. Long
Xflong@sdsu.edu, flong@midgard.ucsc.edu
X
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > include.1
X.TH INCLUDE 1 "26 October 1989"
X.UC 4
X.SH NAME
Xinclude \- eases multiple inclusion problems
X.SH SYNOPSIS
X\fBinclude \-\fR{\fBio\fR}[\fBb\fR] \fIfilename ...\fR
X.SH DESCRIPTION
X.PP
X.I Include
Xmodifies the specified files to help eliminate multiple inclusion problems.
X.PP
XOptions:
X.TP 8
X.B \-b
XThe named files are backed up.  Each backup file will have the
X.B .bak
Xextension.
X.TP 8
X.B \-i
XEach file will have
X.sp
X#if FILENAME != 0
X.br
X#define FILENAME 0
X.sp
Xas the first two lines of the file, and
X.sp
X#endif /* FILENAME */
X.sp
Xwill be the last line in the file,
Xwhere FILENAME is the filename modified to be a legal macro.
X.TP 8
X.B \-o
XFor any file inclusion
X.sp
X#include "filename"
X.sp
Xyou will get
X.sp
X#ifndef FILENAME
X.br
X#define FILENAME 1
X.br
X#include "filename"
X.br
X#endif /* FILENAME */
X.sp
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > include.c
X/*
X *	Fred J. E. Long
X *
X *	flong@sdsu.edu
X */
X
X#include <stdio.h>
X
X#include <ctype.h>
X
Xextern	char	*optarg;
Xextern	int	optind, opterr;
X
Xint	inside = 0, outside = 0, backup = 0;
X
Xvoid	format(name)
Xchar	*name;
X{
X	printf("\n%s -{io}[b] files\n\n", name);
X	printf("\ti\t#ifndef at the top, #endif at the bottom of each file\n");
X	printf("\to\tPut #ifndef/#endif around all #include's\n");
X	printf("\tb\tBackup all files\n");
X	exit(0);
X}
X
Xvoid	backup_file(name)
Xchar	*name;
X{
X	char	tmp[200];
X
X	sprintf(tmp, "cp %s %s.bak", name, name);
X	if (system(tmp)) {
X		printf("\nCould not make backup of %s\n", name);
X		exit(1);
X	}
X}
X
Xvoid	update_file(tmp, name)
Xchar	*tmp, *name;
X{
X	char	command[200];
X
X	sprintf(command, "mv %s %s", tmp, name);
X	if (system(command)) {
X		printf("\nCould not update %s\n", name);
X		exit(1);
X	}
X}
X
Xchar	*is_include(name)
Xchar	*name;
X{
Xstatic	char	tmp[200];
X	int	i;
X
X	i = sscanf(name, "#%*[ \t]include%*[ \t]%*1[\"<]%[^\">]%*1[\">]", tmp);
X	if (i == 1) return(tmp);
X	else return(0);
X}
X
Xchar	*convert(name)
Xchar	*name;
X{
Xstatic	char	tmp[200], *t;
X
X	for (t = tmp; *name; name++, t++) {
X		if (isalpha(*name)) {
X			if (islower(*name)) *t = toupper(*name);
X			else *t = *name;
X		}
X		else *t = '_';
X	}
X	*t = 0;
X	return(tmp);
X}
X
Xvoid	do_for(name)
Xchar	*name;
X{
X	char	*tmp_name, line[500], *tmp, *mktemp();
X	FILE	*fi, *fo;
X
X	if (backup) backup_file(name);
X
X	if (!(fi = fopen(name, "r"))) {
X		printf("\nCould not open %s\n", name);
X		exit(1);
X	}
X	tmp_name = mktemp("/tmp/includeXXXXXX");
X	if (!(fo = fopen(tmp_name, "w"))) {
X		printf("\nCould not open %s\n", tmp_name);
X		exit(1);
X	}
X	if (inside) {
X		fprintf(fo, "#if %s != 0\n", convert(name));
X		fprintf(fo, "#define %s 0\n\n", convert(name));
X	}
X	while (fgets(line, 500, fi)) {
X		if (!outside || !(tmp = is_include(line))) {
X			fputs(line, fo);
X			continue;
X		}
X		fprintf(fo, "#ifndef %s\n", convert(tmp));
X		fprintf(fo, "#define %s 1\n", convert(tmp));
X		fputs(line, fo);
X		fprintf(fo, "#endif /* %s */\n\n", tmp);
X	}
X	if (inside) {
X		fprintf(fo, "\n#endif /* %s */\n", name);
X	}
X	fclose(fi);
X	fclose(fo);
X	update_file(tmp_name, name);
X}
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	int	c;
X
X	while ((c = getopt(argc, argv, "iob")) != EOF) {
X		switch (c) {
X		case 'i':	inside = 1; break;
X		case 'o':	outside = 1; break;
X		case 'b':	backup = 1; break;
X		default:	format(argv[0]);
X		}
X	}
X	if (inside + outside == 0) {
X		printf("\nNothing to do; choose -i, -o, or both\n");
X		format(argv[0]);
X	}
X	for (; optind < argc; optind++) do_for(argv[optind]);
X
X	return(0);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > makefile
Xinclude:	include.c
X		cc -o include include.c
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > run_test
Xinclude -ib test.h
Xinclude -ob test.c
Xcc -c test.c
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > test.c
X#include "test.h"
Xint	i = FOOBAR;
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > test.h
X#define	FOOBAR 2
SHAR_EOF
exit

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.