[net.sources] shred - C program shredder

nitin@ur-laser.UUCP (04/03/87)

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by ur-lle!nitin on Fri Apr  3 11:09:16 EST 1987
# Contents:  README shred.1 Makefile shred.l
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
Program to break a C program into their individual functions:
This program "tries" to do this. It is not 100% effective.  
Nevertheless, it can prove to be a very useful tool.

The following files should be available:

README			This file 
Makefile		Makefile for shred
shred.l			lex source code for shred
shred.1			manual page (-man macros)
shred.man		(nroffed) manual page

DIRECTIONS FOR CREATING/MAKING SOURCE:

1. Edit the Makefile to reflect the correct path for the binary and 
   the manual page *
2. Type "make"
3. Check to make sure the executable "shred" was made
4. Type "make install" to install the program
5. Type "make clean" to clean the directory




* you can also set the environment variable "MAKE_ROOT" to reflect the 
 the root path for the binary file and the manual pages. This avoids
 editing the Makefiles everytime the sources are moved around on the system.
 If all files follow this system, one need only change the environment
 variable when files are moved around. 

e.g.
	% setenv MAKE_ROOT /usr/local
 
@//E*O*F README//
chmod u=rw,g=rw,o=r README
 
echo x - shred.1
sed 's/^@//' > "shred.1" <<'@//E*O*F shred.1//'
@.TH shred 1L "April Fool's Day, 1987"
@.SH NAME
shred -  Program to break a C program into subroutines.
@.SH SYNOPSIS
@.B shred
@.B [\-u] [\-h
@.I <header file>
@.B ]
@.I <file.c> ...
@.SH DESCRIPTION
@.I shred
is a (and i quote)
@.nf
@.ps 8

		\fIkrufty hack to rip large \fB(C)\fI source modules into
		subroutine modules.  This program is only semi-intelligent
		and should be treated as such.
							M.J.R.\fR
@.ps 10
@.fi
@.PP
Some more intelligence, and options have been added here at LLE. In
particular, shred recognizes functions with types out front, or on the previous
line(s). Also, it prefixes each subroutine with an 'include' line for the
@.I header file
and with the comments which appeared before this subroutine, but after the
previous subroutine, if any.
It now can tell the difference between a function declaration and a function
definition. Declarations are left in the
@.I header file.
And, finally, you can now get the file names
to be prefixed by an underscore as an option, rather than always, as was
previously the case.
@.SH OPTIONS 
@.B \-u
- prefix file names with underscore. (this was the old default)
@.br
@.B \-h
@.I <header file>
- use this as the name of the file containing header (non-subroutine)
lines. (default is _header.h)
@.SH EXAMPLES 
% \fBshred messy.c\fR
@.br
hopefully the result is a bunch of subroutines in separate files.
@.SH BUGS
As mentioned, shed is not too smart.
There is little hope of shred working on files with C syntax errors.
Also, shred doesn't know about #ifdef's, so any weirdness in #ifdef's, or
even syntax errors inside #ifdef's will confuse it.
However, if it gets confused, the
worst that seems to happen is all of your file(s) end up in the
@.I header file.
At the moment, strange things happen if the subroutine files already
exist. The new file is appended to the existing one, however, no comments
will be prepended. In any event, this usually results in garbage, but at
least nothing gets lost. There is a check to make sure you're not writing
over the file you're reading from, which could be ugly.
@.SH AUTHOR
Copyright, 1987, Marcus J Ranum
@.br
All rights reserved. This code can be distributed, modified,
or altered at will, but it or versions of it may not be sold
for profit.
@.sp 2
Local extensions by S Swales, Lab. for Laser Energetics (LLE)
@//E*O*F shred.1//
chmod u=rwx,g=rwx,o=r shred.1
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
# Makefile for shred
#
# To use this change MAKE_ROOT to reflect the correct path.
# You can also do this at the shell level by setting the enviroment:
# 	% setenv MAKE_ROOT the_path_to_follow
# The latter is advisable since if ever the directory is moved, only
# the environment need change for all Makefiles
#

DEST		= ${MAKE_ROOT}/bin
MAN		= ${MAKE_ROOT}/man/man1
LD		= ${CC}
CFLAGS		= -fsingle -O
LDFLAGS		= -fsingle
DEBUG		= -O
STRIP		= -s
INCLUDES	= 
LIBS		=
PROGRAM		= shred
EXECUTABLES	= ${PROGRAM}
OBJS		= ${PROGRAM}.o
SRCS		= $(PROGRAM).l

all:	${PROGRAM}

${PROGRAM}:	${OBJS} ${LIBS}
		${LD} ${LDFLAGS} ${OBJS} ${LIBS} -o ${PROGRAM}

clean:;		@rm -f core junk foo *.out *.o *.lint
		@rm -f ${EXECUTABLES}

install: ${EXECUTABLES} ${SCRIPTS} manual
	 cp ${EXECUTABLES} ${SCRIPTS} ${DEST}

man:	manual

manual:
	-cp ${PROGRAM}.[12345678]* ${MAN}

print:	.print

@.print:	${SRCS} ${MENU} ${SCRIPTS} 
	itroff -t -ms -man ${PROGRAM}.[1234]? | catimp -h
	vgrind -t $? | catimp -h
	touch .print

lint:	${SRCS} 
	lint ${INCLUDES} $?
@//E*O*F Makefile//
chmod u=rw,g=rw,o=r Makefile
 
echo x - shred.l
sed 's/^@//' > "shred.l" <<'@//E*O*F shred.l//'
shred.l:

%{
/*
%e 2000
%p 5000
%n 1000
%k 500
%a 4000
%o 2000
*/
	/* Copyright, 1987, Marcus J Ranum */
	/* All rights reserved. This code can be distributed, modified, */
	/* or altered at will, but it or versions of it may not be sold */
	/* for profit */
	
	/* krufty hack to rip large source modules into subroutine modules */
	/* this program is only semi-intelligent and should be treated as such */

	/* April 1, 1987 Steve Swales (Lab. for Laser Energetics) */
	/* added features/options and a manual page (see this for details) */
	/* added a Makefile */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>


int trigger =0;
int bracelev =0;
int incomment =0;
int infunction =0;
int ininclude =0;
int junkint =0;
char *junkp =0;
struct stat stbuf;
char jfname[512];
char jfname2[512];
char *curfile;
char *strcat();
char headerfile[512] = "_header.h";
int use_underscore = 0;
char tempcom[] = "shed_tempXXXXXX";
FILE *tempfp = 0;

%}

%%
^[a-zA-Z1-9*_ \t\n]+"("[ \t\n]*")"[ \t\n]*";" { /* declaration only*/
				printout(yytext);
			}
^[a-zA-Z1-9*_ \t\n]+"("[a-zA-Z1-9_, ]*")" { /* found a function definition ! */
				if (!bracelev && !incomment && !ininclude) {
					infunction = 1;
					(void) sprintf(jfname2, "%s", yytext);
					for (junkint = 0; junkint < strlen(jfname2); junkint++) {
						if (jfname2[junkint] == '(') {
							jfname2[junkint] = '\0';
							while (jfname2[--junkint] <= ' ')
								jfname2[junkint] = '\0';
							break;
						}
					}
					junkp = jfname2 + strlen(jfname2) - 1;
					while (junkp >= jfname2) {
						if (*junkp <= ' ' || *junkp == '*') {
							break;
						}
						--junkp;
					}
					junkp++;
					(void) sprintf(jfname, "%s%s",
					  (use_underscore) ? "_" : "", junkp);
					(void) strcat(jfname, ".c");
					if (!strncmp(jfname, curfile)) {
						fprintf(stderr, "Cant write over the file you're reading from!!\n");
						if (tempfp) {
							fclose(tempfp);
							unlink(tempcom);
							tempfp = 0;
							}
						printout(yytext);
					}
					else {
						if (tempfp) {
							fclose(tempfp);
							link(tempcom, jfname);
							unlink(tempcom);
							tempfp = 0;
						}
						fprintf(stderr, "writing %s\n", jfname);
						(void) fclose(yyout);
						if ((yyout = fopen(jfname, "a")) == NULL) {
							perror("shred");
							unlink(tempcom);
							exit(9);
						}
						fprintf(yyout, "\n#include \"%s\"\n\n", headerfile);
						fprintf(yyout, "%s", yytext);
					}
				}

				else {
					printout(yytext);
				}
			}
"{"			{
				if(!incomment)
					++bracelev;
				fprintf(yyout,"%s",yytext);
			}
"}"			{
				if(!incomment)
					--bracelev;
				fprintf(yyout,"%s",yytext);
				if(bracelev <0) {
					fprintf(stderr,"too many \"}\" !  unmatched \"{\"\n");
					exit(1);
				}
				/* if we're not in braces, anything goes to header file */
				if(!bracelev) {
					fprintf(yyout,"\n");
					(void)fclose(yyout);
					infunction = 0;
					if((yyout = fopen(headerfile,"a")) ==NULL) {
						perror("shred");
						exit(9);
					}
				}
		}
\*\/		{
				printout(yytext);
				if(incomment)
					incomment--;
			}
\/\*		{
				incomment++;
				if(bracelev == 0) {
					if(!tempfp)
						tempfp = fopen(tempcom,"w");
				}
				printout(yytext);
			}
^[]*"#"		{
				ininclude++;
				/* flush includes */
				fprintf(yyout,"%s",yytext);
			}
\n			{
				ininclude =0;
				printout(yytext);
			}
@.			{printout(yytext); } /* default action */
%%

/* beginning of MAIN */
main(argc,argv)
int argc;
char *argv[];
{
	int index =0;
	char    *s;                     /* used by command line parser */

/* 
 *      Parse command line for options  
 */
        while ( --argc > 0 && ( *++argv) [0] == '-' )
                for( s = argv[0]+1; *s != '\0'; s++)
                        switch(*s) {
						case 'u':
							use_underscore = 1;
							break;
						case 'h':
							strcpy(headerfile,*++argv);
							--argc;
							break;
						default:
							fprintf(stderr,"'-%c' is not a legal option\n",*s);
							usage();
							break;
						}

		if(argc == 0)
			usage();
		mktemp(tempcom);

	if(!stat(headerfile,&stbuf)) {
printf("%d braces\n",bracelev);
		fprintf(stderr,"will not overwrite existing %s\n",headerfile);
		exit(1);
	} else {
		if((yyout = fopen(headerfile,"w")) ==NULL) {
			perror("shred");
			exit(9);
		}
	}

	for(index = 0; index <argc; index++) {
		if((yyin = fopen(argv[index],"r")) ==NULL) {
			perror("shred");
			unlink(tempcom);
			exit(1);
		} else { 
			curfile = argv[index];
			yylex();
		}
	}
	unlink(tempcom);
}

usage()
{
	fprintf(stderr,"Usage: shred [-u] [-h <header file>] <file.c>...\n");
	fprintf(stderr,"	-u - prefix subroutine file names with underscore\n");
	fprintf(stderr,"	-h <header file> - use this name for include file.\n");
	exit(1);
}

yywrap()
{
	/*yywrap returns a 1. It can be used to detect end of
		file, and whether to provide more input to
		yyinput.  I get rid of it like this.
		If you have some desire to frob the input,
		here is one place to do it. -mjr */
	return(1);
}


printout(yytext)
char *yytext;
{
				fprintf(yyout,"%s",yytext);
				if(bracelev == 0 && !infunction && incomment) {
					if(tempfp)
                        fprintf(tempfp,"%s",yytext);
				}
}
@//E*O*F shred.l//
chmod u=rw,g=rw,o=r shred.l
 
exit 0
-- 
{seismo,allegra}!rochester!ur-laser!nitin