v20i016: Tools for generating software metrics, Part09/14
Rich Salz
rsalz at uunet.uu.net
Wed Sep 20 04:46:49 AEST 1989
Submitted-by: Brian Renaud <!huron.ann-arbor.mi.us!bdr>
Posting-number: Volume 20, Issue 16
Archive-name: metrics/part09
---- Cut Here and unpack ----
#!/bin/sh
# this is part 9 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/kdsi/kdsi.c continued
#
CurArch=9
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file src/kdsi/kdsi.c"
sed 's/^X//' << 'SHAR_EOF' >> src/kdsi/kdsi.c
X tot_cdline = tot_cmline = tot_bkline = tot_comment = 0;
X while ( (fp = nextfp(argc, argv, &filename)) != FNULL )
X {
X cod_linect = com_linect = blnk_linect = comment_ct = 0;
X filecount++;
X
X while ( (input = GetChar(fp)) != STOP_INPUT )
X {
X switch ( input )
X {
X case NEWLINE:
X if ( statevar == Code )
X cod_linect++;
X else if ( statevar == Comment )
X com_linect++;
X /* state is quiescent */
X else if ( laststate == Comment )
X {
X /* if is supposed to catch cases where a comment
X * follows a line of code
X */
X if ( following_com )
X cod_linect++;
X else
X com_linect++;
X }
X else
X blnk_linect++;
X if ( statevar != Comment )
X {
X laststate = Quiescent;
X statevar = Quiescent;
X }
X following_com = False;
X break;
X case START_COMMENT:
X laststate = statevar;
X statevar = Comment;
X break;
X case END_COMMENT:
X comment_ct++;
X /* if true, is a comment on same line as code */
X if ( laststate == Code )
X following_com = True;
X
X laststate = Comment;
X statevar = Quiescent;
X break;
X case MISC_CHARACTER:
X if ( statevar == Quiescent )
X {
X laststate = statevar;
X statevar = Code;
X }
X break;
X default:
X fprintf(stderr, "kdsi: illegal token (%d) returned from GetChar\n", input);
X exit(1);
X break;
X
X }
X }
X if ( !only_stdin )
X printf("%8ld %8ld %8ld %7ld %s\n",
X cod_linect, blnk_linect, com_linect, comment_ct,
X filename);
X else
X printf("%8ld %8ld %8ld %7ld\n",
X cod_linect, blnk_linect, com_linect, comment_ct);
X tot_cdline += cod_linect;
X tot_cmline += com_linect;
X tot_bkline += blnk_linect;
X tot_comment += comment_ct;
X }
X if ( !only_stdin && filecount > 1 )
X printf("%8ld %8ld %8ld %7ld total\n",
X tot_cdline, tot_bkline, tot_cmline, tot_comment);
X exit(0);
X}
X
XToken
XGetChar( file )
X FILE *file;
X{
X /* return token for char type, taking into account comment delims */
X /* ignores spaces and tabs */
X
X register int c;
X register Token retval;
X static int buf;
X static Bool inbuf = False;
X
X do
X {
X if ( inbuf )
X {
X c = buf;
X inbuf = False;
X }
X else
X c = getc(file);
X
X switch ( c )
X {
X case EOF:
X retval = STOP_INPUT;
X break;
X case '\n':
X retval = NEWLINE;
X break;
X case '/':
X buf = getc( file );
X if ( buf == '*' )
X retval = START_COMMENT;
X else
X {
X inbuf = True;
X retval = MISC_CHARACTER;
X }
X break;
X case '*':
X buf = getc( file );
X if ( buf == '/' )
X retval = END_COMMENT;
X else
X {
X inbuf = True;
X retval = MISC_CHARACTER;
X }
X break;
X case ' ':
X case '\t':
X retval = WHITE_SPACE;
X break;
X default:
X retval = MISC_CHARACTER;
X }
X }
X while ( retval == WHITE_SPACE );
X
X return (retval);
X}
X
XFILE *
Xnextfp( argc, argv, p_filename)
X int argc;
X char *argv[];
X char **p_filename;
X{
X /* looks through parameters trying to return next FILE * to next
X * specified file
X * passes back a pointer to the filename as a side effect
X */
X
X static Bool first = True;
X static int index = 1;
X static FILE *result = FNULL;
X
X *p_filename = CNULL;
X
X if ( result != FNULL )
X {
X fclose( result );
X result = FNULL;
X }
X while ( index < argc && *argv[index] == '-' )
X index++;
X
X if ( index < argc )
X {
X if ( (result = fopen( argv[index], "r")) == NULL )
X {
X fprintf(stderr, "%s: unable to open %s for read\n",
X argv[0], argv[index]);
X exit(1);
X }
X else
X *p_filename = argv[index];
X index++;
X }
X if ( first )
X {
X /* if no files specified, read from stdin */
X /* filename remains null */
X if ( result == FNULL )
X {
X result = stdin;
X only_stdin = True;
X }
X first = False;
X }
X return ( result );
X}
SHAR_EOF
echo "File src/kdsi/kdsi.c is complete"
chmod 0644 src/kdsi/kdsi.c || echo "restore of src/kdsi/kdsi.c fails"
echo "x - extracting src/kdsi/test.result (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/kdsi/test.result
X 153 25 20 11 test1.c
X 233 22 4 4 test2.y
X 311 44 8 22 test3.c
X 697 91 32 37 total
SHAR_EOF
chmod 0644 src/kdsi/test.result || echo "restore of src/kdsi/test.result fails"
echo "x - extracting src/mccabe/Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/mccabe/Makefile
X# makefile for mccabe utilities
X
XBIN=../bin
XTEST=../testfiles
X
X
Xall: mccabe
X
Xmccabe: mccabe.sh
X cp mccabe.sh mccabe
X chmod u+x mccabe
X
Xinstall: all
X mv mccabe $(BIN)/mccabe
X chmod 755 $(BIN)/mccabe
X
Xclean:
X -rm -f mccabe _test
X
Xtest:
X @echo results of this command should be the same as test.result
X @cp $(TEST)/test1.c $(TEST)/test2.y $(TEST)/test3.c .
X mccabe test1.c test2.y test3.c > _test
X diff _test test.result
X @/bin/rm -f test1.c test2.y test3.c
SHAR_EOF
chmod 0644 src/mccabe/Makefile || echo "restore of src/mccabe/Makefile fails"
echo "x - extracting src/mccabe/mccabe.sh (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/mccabe/mccabe.sh
X:
X# determine function complexity based on Mccabe model of program complexity
X# anything greater than 10 is usually considered bad, or at least questionable
X#
X# originally written by Rick Cobb, modified by Brian Renaud to add out
X# of function complexity detection and to fix some minor bugs
X
X# NOTE the beginning and ending braces "{}" in a function must be at the
X# same indent level, or this tools will NOT work!!
X
X# heuristics for function declaration detection:
X# Handles three conventions:
X#
X# |int foo()
X# | char *
X# | {
X
X# |int foo()
X# |char *
X# |[ ]*{
X
X# or the preferred
X# int
X# foo()
X# []*{
X
X
Xif [ $# = 0 ]
Xthen
X echo "usage: mccabe [-n] file [file]" > /dev/tty
X exit 1
Xfi
X
X# the -n flag (No Header) is useful if you are using this to produce data for
X# other tools
X
XHEADER=1
Xif [ $1 = "-n" ]
Xthen
X HEADER=0
X shift
Xfi
X
Xif [ $HEADER = "1" ]
Xthen
X echo "File Name Complexity No. of returns"
X echo "-------------- --------------- ---------- --------------"
Xfi
X
Xfor file in $*
Xdo
X stripcom ${file} |\
X awk 'BEGIN {
X File = "'"${file}"'";
X Header = '${HEADER}';
X gotfunction = "FALSE";
X infunction = "FALSE";
X nofunc = "***"
X complexity[nofunc] = 1;
X returns[nofunc] = 0;
X casecount[nofunc] = 0;
X }
X
X# Should recognize the actual function:
X/^[_a-zA-Z][_a-zA-Z]*.*\(.*\)[ ]*$/ && $1 !~ /extern/ && infunction == "FALSE"{
X
X gotfunction="TRUE";
X
X # strip off parens (so we can make PARMS statement)
X endpos = index($0,"(");
X funcname = substr($0,1,endpos-1);
X
X # strip off beginning declaratory stuff (if any)
X parts = split(funcname,funky," ");
X funcname = funky[parts];
X complexity[funcname] = 1; # default complexity is 1
X casecount[funcname] = 0;
X switchcount[funcname] = 0;
X
X next;
X }
X
X#do not count preprocessor lines
X/^#/ { next; }
X
X# find end of formal parameters
X
Xgotfunction == "TRUE" && /[ ]*{/ {
X gotfunction = "FALSE";
X infunction = "TRUE";
X
X depth = index($0,"{");
X next;
X }
X
Xinfunction == "TRUE" && /(^|[ \t;])(if|else|while|for)($|[ \t(])/ {
X complexity[funcname]++;
X }
X
Xinfunction == "TRUE" && /(^|[ \t;])(switch)($|[ \t(])/ {
X switchcount[funcname]++;
X }
X
Xinfunction == "TRUE" && /(^|[ \t;])(case|default[ \t]*:)($|[ \t])/ {
X casecount[funcname]++;
X }
X
Xinfunction == "TRUE" && /(^|[ \t;])return([ \t(]|$)/ {
X returns[funcname]++;
X }
X
Xinfunction == "TRUE" && /(^|[ \t;])exit($|[ \t(])/ {
X returns[funcname]++;
X }
X
Xinfunction == "TRUE" && /}/ {
X if (index($0,"}") == depth)
X {
X infunction = "FALSE";
X gotfunction = "FALSE";
X }
X next;
X }
X
Xinfunction == "FALSE" && /(^|[ \t;])(if|else|while|for)($|[ \t(])/ {
X complexity[nofunc]++;
X }
X
Xinfunction == "FALSE" && /(^|[ \t;])(case|default[ \t]*:)($|[ \t])/ {
X casecount[nofunc]++;
X }
X
Xinfunction == "FALSE" && /(^|[ \t;])return([ \t(]|$)/ {
X returns[nofunc]++;
X }
X
Xinfunction == "FALSE" && /(^|[ \t;])exit($|[ \t(])/ {
X returns[nofunc]++;
X }
X
XEND {
X count = 0;
X for (func in complexity)
X {
X if ( func == nofunc &&\
X complexity[ func ] == 1 &&\
X casecount[ func ] == 0 &&\
X returns[ func ] == 0)
X continue;
X count++;
X complex=complexity[func];
X cases=casecount[func];
X
X if ( Header )
X printf("%-14s\t%-15s\t%10d\t%10d\n",\
X File, func, complex + cases, returns[func]);
X else
X printf("%s\t%s\t%d\t%d\n",\
X File, func, complex + cases, returns[func]);
X }
X if ( count == 0 )
X {
X # this means that no functions were found in the file
X if ( Header )
X printf("%-14s\t%-15s\t%10d\t%10d\n",\
SHAR_EOF
echo "End of part 9"
echo "File src/mccabe/mccabe.sh is continued in part 10"
echo "10" > s2_seq_.tmp
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list