home *** CD-ROM | disk | FTP | other *** search
- Subject: v20i016: Tools for generating software metrics, Part09/14
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- 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
-
-
-