From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.5-pre1 (2020-06-20) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-1.9 required=3.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.5-pre1 Date: 9 Jul 93 20:40:37 GMT From: cis.ohio-state.edu!math.ohio-state.edu!darwin.sura.net!source.asset.com!v and@ucbvax.Berkeley.EDU (Laurence VanDolsen) Subject: Re: Seek LOC Count Software in Pub Domain Message-ID: <1993Jul09.204037.28865@source.asset.com> List-Id: -------------------------CUT HERE----------------------------- -- This file contains the following logical files and Ada compilation units: -- -- This introductory text -- An overview (README) file for the utility COUNT -- package LINES_OF_CODE -- package FILE_SPECIFICATION -- package WILD_CARD -- procedure COUNT_ADA_STATEMENTS -- package body FILE_SPECIFICATION -- package body LINES_OF_CODE -- package body WILD_CARD -- -- Each logical file and compilation unit is demarked by a line of the -- following form to simplify separation of the compilation units ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- -- -- COUNT UTILITY -- -- This utility operates on any IBM PC clone under MS-DOS. -- -- It is used to count Ada source. -- -- -- It will count the NCNB lines, -- Ada statements, Comment Lines, and Total -- lines in one or more files in a DOS directory. -- The software was developed under Meridian v4.1.4 and will execute in any -- DOS environemt. -- The Usage is: COUNT FILE1 .. FILEN -- where FILEi is any string which can be interpreted -- as one or more DOS filenames -- e.g. COUNT *.ads *.adb c:\ada\*.ada -- will report on all .ads and .adb files in the -- current directory and all .ada files in c:\ada -- The Ada Statements are measured by counting the semicolon statement -- terminators, after excluding: -- -- comments -- separators in formal parameter lists (by excluding parenthesized items) -- string literals (set off by " or %) -- character literals (i.e. ';') -- comments -- This software is based, in part, on a similar set by Bill Whittaker which -- is available from the SIMTEL20 repository. -- When rehosting this utility to a non MS-DOS environment, alternatives -- to the following Meridian packages must be found/made: -- TEXT_HANDLER; - a variable length string package -- ARG; - reports DOS command line arguments -- -- WILD_CARD and FILE_SPECIFICATION by L. Van Dolsen are specific to -- DOS file naming conventions and "with" a variety of DOS-specific -- Meridian packages. -- -- DISK, DISK_TYPES, DIRECTORY, ERRORS, FILE_IO ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- package LINES_OF_CODE is --| This function calculates the Ada statements and comments of a valid --| Ada fragment specified by a FILE_NAME string parameter. --| It need not be a complete compilation unit but it must have closed --| all open parentheses and string delimiters. --| The Ada statement is defined by a semicolon terminator --| outside of comments, parentheses, or string or character literals --| This definition is insensitive to formatting or layout of the source --| William A. Whitaker WIS JPMO 3 March 1984 --| Modified rh 17 May 1986 --| Modified emery 18 MAR 87 --| Modified Van Dolsen - Paramax - Fri Feb 05, 1993 --| Adapted to Meridian Ada v4.1.4 --| and fixed emery hack (it counted one line in all cases) --| Modified Van Dolsen - Fri Feb 26, 1993 --| Added computation of NCNB lines. type LINES is record -- vandolsen hack NCNB : NATURAL; -- NCNB LINES -- end hack AS : NATURAL; -- Ada statements CMNTS : NATURAL; -- Comments LFS : NATURAL; -- lines (newlines) end record; function LOC(FILE_NAME : in STRING) return LINES; end LINES_OF_CODE; ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- package FILE_SPECIFICATION is -- This package interprets/sets disk and path -- LAURENCE VAN DOLSEN - Paramax - 12 FEB 1993 function CURRENT return STRING; -- d:\pathname function SET(TO : in STRING) return BOOLEAN; function PARSE(ARG : in STRING) return STRING; -- Constructs a useable filespec from a command line argument -- *.* becomes d:\currentpath\*.* -- If it can't interpret the argument, it returns the current path end FILE_SPECIFICATION; ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- package WILD_CARD is -- This package takes a file specification string, including wildcard -- characters, and returns the file name. -- LAURENCE VAN DOLSEN - Paramax - 12 FEB 1993 type STR_PTR is access STRING; procedure GET_FIRST(ARG : in STRING; PATH : out STR_PTR; FILE : out STR_PTR); procedure GET_NEXT(ARG : in STRING; PATH : out STR_PTR; FILE : out STR_PTR); end WILD_CARD; ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- with TEXT_IO; with ARG; -- a Meridian package for DOS aruguments with LINES_OF_CODE; -- a function developed by BILL WHITTAKER with WILD_CARD; use WILD_CARD; -- a filespec interpreter by LVD procedure COUNT_ADA_STATEMENTS is -- This procedure drives the function LOC to find Ada Statements, Comments, -- and total lines in Ada files. (See package LINES_OF_CODE) -- The Usage is: COUNT FILE1 .. FILEN -- where FILEi is any string which can be interpreted -- as one or more DOS filenames -- e.g. COUNT *.ads *.adb c:\ada\*.ada -- will report on all .ads and .adb files in the -- current directory and all .ada files in c:\ada -- See comments in package LINES_OF_CODE for background -- The original version was written by BILL WHITTAKER -- LAURENCE VAN DOLSEN Fri Feb 05, 1993 - Paramax -- The changes included modifications -- required to run under Meridian v4.1.4 -- and use the Meridian ARG package and -- WILD_CARD package to handle wildcard -- file descriptors. -- LAURENCE VAN DOLSEN Fri Feb 26, 1993 - Paramax -- modified to use NCNB version of LINES_OF_CODE package NATURAL_IO is new TEXT_IO.INTEGER_IO(NATURAL); NCNB_POSN : TEXT_IO.POSITIVE_COUNT := 35; STMTS_POSN : TEXT_IO.POSITIVE_COUNT := 45; CMTS_POSN : TEXT_IO.POSITIVE_COUNT := 55; LS_POSN : TEXT_IO.POSITIVE_COUNT := 65; LINE_LEN : POSITIVE := 79; DASHES : STRING(1 .. LINE_LEN) := (others => '_'); USAGE : constant STRING := "Usage: COUNT file1 .. filen "; PATH : STR_PTR; FILE : STR_PTR; TOTALS : LINES_OF_CODE.LINES := (0, 0, 0, 0); THIS_COUNT : LINES_OF_CODE.LINES; procedure PRINT_ENTRY(PATH : in STRING := ""; FILE : in STRING := ""; L : in LINES_OF_CODE.LINES) is NEXT_COL : POSITIVE; begin if PATH /= "" then for I in reverse 1 .. PATH'LAST loop if PATH(I) /= ' ' then TEXT_IO.PUT(PATH(1 .. I)); TEXT_IO.PUT('\'); exit; end if; end loop; end if; TEXT_IO.PUT(FILE); TEXT_IO.SET_COL(NCNB_POSN); NATURAL_IO.PUT(L.NCNB); TEXT_IO.SET_COL(STMTS_POSN); NATURAL_IO.PUT(L.AS); TEXT_IO.SET_COL(CMTS_POSN); NATURAL_IO.PUT(L.CMNTS); TEXT_IO.SET_COL(LS_POSN); NATURAL_IO.PUT(L.LFS); TEXT_IO.NEW_LINE; end PRINT_ENTRY; procedure PRINT_HEADER is use TEXT_IO; begin TEXT_IO.PUT("File Name"); TEXT_IO.SET_COL(NCNB_POSN + 2); TEXT_IO.PUT("NCNB"); TEXT_IO.SET_COL(STMTS_POSN); TEXT_IO.PUT("Ada STMTS"); TEXT_IO.SET_COL(CMTS_POSN + 2); TEXT_IO.PUT("Comments"); TEXT_IO.SET_COL(LS_POSN + 1); TEXT_IO.PUT("Line Feeds"); TEXT_IO.NEW_LINE; TEXT_IO.PUT_LINE(DASHES); end PRINT_HEADER; begin if ARG.COUNT <= 1 then TEXT_IO.PUT_LINE(USAGE); else PRINT_HEADER; for I in 2 .. ARG.COUNT loop if (I mod 52 = 0) then PRINT_HEADER; TEXT_IO.NEW_PAGE; end if; WILD_CARD.GET_FIRST(ARG.DATA(I), PATH, FILE); loop if FILE /= null then THIS_COUNT := LINES_OF_CODE.LOC(FILE.all); TOTALS.NCNB := TOTALS.NCNB + THIS_COUNT.NCNB; TOTALS.AS := TOTALS.AS + THIS_COUNT.AS; TOTALS.CMNTS := TOTALS.CMNTS + THIS_COUNT.CMNTS; TOTALS.LFS := TOTALS.LFS + THIS_COUNT.LFS; PRINT_ENTRY(PATH => PATH.all, FILE => FILE.all, L => THIS_COUNT); WILD_CARD.GET_NEXT(ARG.DATA(I), PATH, FILE); else exit; end if; end loop; end loop; TEXT_IO.PUT_LINE(DASHES); TEXT_IO.NEW_LINE; TEXT_IO.PUT(" ***** TOTALS ******"); PRINT_ENTRY(L => TOTALS); end if; end COUNT_ADA_STATEMENTS; ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- with DISK; with DISK_TYPES; with DIRECTORY; with ERRORS; with TEXT_HANDLER; with TEXT_IO; use DISK_TYPES; use ERRORS; use TEXT_HANDLER; package body FILE_SPECIFICATION is -- This package interprets/sets disk and path -- LAURENCE VAN DOLSEN - Paramax - 12 FEB 1993 package DNUM is new TEXT_IO.ENUMERATION_IO(DISK_TYPES.DRIVE_ID); type STR_PTR is access STRING; LAST_VALID_CHAR : NATURAL; PATH_NAME : DIRECTORY.PATHNAME; DRIVE : DISK_TYPES.DRIVE_ID := C; DS : STRING(1 .. 1); FULL_PATH : TEXT(100); function CURRENT return STRING is ERR : ERRORS.EXTENDED_ERRORS; begin DRIVE := DISK.GET_DEFAULT; DIRECTORY.CURRENT_NAME(FOR_DRIVE => DRIVE, NAME => PATH_NAME, LAST => LAST_VALID_CHAR, ERROR => ERR); DNUM.PUT(TO => DS, ITEM => DRIVE); SET(OBJECT => FULL_PATH, VALUE => (TO_TEXT(DS) & TO_TEXT(':') & TO_TEXT( PATH_NAME(1 .. LAST_VALID_CHAR)))); return VALUE(FULL_PATH); end CURRENT; function SET(TO : in STRING) return BOOLEAN is ERR : ERRORS.EXTENDED_ERRORS; CNT : DISK_TYPES.LOGICAL_DRIVE_COUNT; POSINT : POSITIVE; begin DNUM.GET(FROM => TO(1 .. 1), ITEM => DRIVE, LAST => POSINT); CNT := DISK.SET_DEFAULT(TO_DRIVE => DRIVE); if TO'LAST = 2 then -- change to a root directory ERR := DIRECTORY.CHANGE_TO(" "); else ERR := DIRECTORY.CHANGE_TO(TO(3 .. TO'LAST)); end if; return ERR = OK; end SET; function PARSE(ARG : in STRING) return STRING is DRIVEP, PATHP, BOTHP : STR_PTR := null; IX : POSITIVE := 1; RETP : STR_PTR := null; begin if (ARG(1) in 'A' .. 'Z' or ARG(1) in 'a' .. 'z') and ARG(2 .. 3) = ":\" then DRIVEP := new STRING'(ARG(1 .. 2)); IX := 3; else DRIVEP := new STRING'(CURRENT(1 .. 2)); end if; for I in reverse IX .. ARG'LAST loop if ARG(I) = '\' then if I > 1 then PATHP := new STRING'(ARG(IX .. I - 1)); else PATHP := new STRING'(" "); end if; SET(OBJECT => FULL_PATH, VALUE => (TO_TEXT(DRIVEP.all) & TO_TEXT(PATHP. all))); BOTHP := new STRING'((VALUE(FULL_PATH))); exit; end if; end loop; if PATHP = null then if IX = 3 then BOTHP := DRIVEP; else BOTHP := new STRING'(CURRENT); end if; end if; return BOTHP.all; end PARSE; end FILE_SPECIFICATION; ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- with TEXT_IO; use TEXT_IO; package body LINES_OF_CODE is --| William A. Whitaker WIS JPMO 3 March 1984 --| Modified rh 17 May 1986 --| Modified emery 18 MAR 87 --| Modified Van Dolsen - Paramax - Fri Feb 05, 1993 --| Adapted to Meridian Ada v4.1.4 --| and fixed emery hack (it counted one line in all cases) --| Modified Van Dolsen - Fri Feb 26, 1993 --| Added computation of NCNB lines. function LOC(FILE_NAME : in STRING) return LINES is INPUT : FILE_TYPE; C : CHARACTER := ' '; -- van dolsen hack PREVIOUS_C : CHARACTER := ' '; NCNB_COUNT : NATURAL := 0; -- end hack LINE_COUNT : NATURAL := 0; COMMENT_COUNT : NATURAL := 0; LEVEL : NATURAL := 0; -- emery hack NEW_LINES : NATURAL := 0; -- end hack begin -- van dolsen hack TEXT_IO.OPEN(INPUT, IN_FILE, FILE_NAME); -- FIRST PASS IS TO COUNT NCNB LINES - ADDED BY LVD while not TEXT_IO.END_OF_FILE(INPUT) loop TEXT_IO.GET(INPUT, C); if C /= ' ' then if C /= '-' then NCNB_COUNT := NCNB_COUNT + 1; TEXT_IO.SKIP_LINE(INPUT); elsif PREVIOUS_C = '-' then TEXT_IO.SKIP_LINE(INPUT); PREVIOUS_C := ' '; end if; PREVIOUS_C := C; end if; end loop; TEXT_IO.CLOSE(INPUT); -- end hack TEXT_IO.OPEN(INPUT, IN_FILE, FILE_NAME); -- SECOND PASS COUNTS EVERYTHING ELSE PER WHITTAKER'S FUNCTION loop TEXT_IO.GET(INPUT, C); -- Check for comment on the line if C = '-' then TEXT_IO.GET(INPUT, C); -- Which is signaled by the '-' following a '-' if C = '-' then COMMENT_COUNT := COMMENT_COUNT + 1; -- and then just skip the rest of the line and go to the next TEXT_IO.SKIP_LINE(INPUT); end if; end if; -- Check for one of the characters which introduce code constructs -- like string or character literal or formal parameter list -- within which a ';' does not terminate a statement if C = '(' or C = '"' or C = '%' or C = ''' then -- Check for opening parentheses -- Every ';' within is in a formal parameter list if C = '(' then -- Count the number of levels of parentheses LEVEL := LEVEL + 1; -- Read ahead until the whole construct is closed, LEVEL = 0 while LEVEL > 0 loop TEXT_IO.GET(INPUT, C); if C = '(' then -- Increase the level if another '(' is found LEVEL := LEVEL + 1; elsif C = ')' then -- Decrease the level if a ')' is found LEVEL := LEVEL - 1; end if; end loop; -- Now check for string brackets of either kind, " or % elsif C = '"' or C = '%' then -- Treat them in parallel, one must lead off if C = '"' then loop TEXT_IO.GET(INPUT, C); -- Loop until the close comes -- If there is a doubled character it just starts again exit when C = '"'; end loop; -- The '%' is handled exactly the same way as '"' elsif C = '%' then loop TEXT_IO.GET(INPUT, C); exit when C = '%'; end loop; end if; -- Character literals are just three characters long including ' elsif C = ''' then TEXT_IO.GET(INPUT, C); TEXT_IO.GET(INPUT, C); end if; -- Any ';' that can be found at this point after all exclusions -- must be a valid "line of code" terminator elsif C = ';' then LINE_COUNT := LINE_COUNT + 1; end if; -- vandolsen hack NEW_LINES := INTEGER(TEXT_IO.LINE(INPUT)); -- end hack end loop; exception -- Return through exception since the end of file may be encountered -- at several levels in the function and in any case it stops and returns -- Otherwise one would use END_OF_FILE but here it would have to appear -- in a number of places to no advantage -- and would cause multiple exits or returns -- This is much cleaner when END_ERROR => -- emery hack TEXT_IO.CLOSE(INPUT); return (NCNB_COUNT, LINE_COUNT, COMMENT_COUNT, NEW_LINES); -- end hack end LOC; end LINES_OF_CODE; ----------------CUT HERE TO SEPARATE COMPILATION UNITS----------------------- with TEXT_IO; use TEXT_IO; with FILE_IO; with FILE_SPECIFICATION; with ERRORS; use ERRORS; with DIRECTORY; with DISK; with DISK_TYPES; use DISK_TYPES; package body WILD_CARD is -- This package takes a file specification string, including wildcard -- characters, and returns the file name. -- LAURENCE VAN DOLSEN - Paramax - 12 FEB 1993 package DNUM is new TEXT_IO.ENUMERATION_IO(DISK_TYPES.DRIVE_ID); STARTED : BOOLEAN := FALSE; START_PATH, NEW_PATH : STR_PTR; SEARCH_DATA : FILE_IO.TRANSFER_DATA; INFORMATION : FILE_IO.FILE_DATA; ERR : ERRORS.EXTENDED_ERRORS; DRIVE : DISK_TYPES.DRIVE_ID; POSINT : POSITIVE; CNT : DISK_TYPES.LOGICAL_DRIVE_COUNT; function START return BOOLEAN is begin START_PATH := new STRING'(FILE_SPECIFICATION.CURRENT); NEW_PATH := START_PATH; STARTED := START_PATH /= null; return STARTED; end START; procedure CHECK(ERR : in ERRORS.EXTENDED_ERRORS; PATH, FILE : out STR_PTR) is begin if ERR = NO_MORE_FILES then DNUM.GET(FROM => START_PATH.all(1 .. 1), ITEM => DRIVE, LAST => POSINT); CNT := DISK.SET_DEFAULT(DRIVE); if DIRECTORY.CHANGE_TO(START_PATH.all) = OK then PATH := START_PATH; end if; else FILE := new STRING'(INFORMATION.NAME); PATH := NEW_PATH; end if; end CHECK; procedure GET_FIRST(ARG : in STRING; PATH : out STR_PTR; FILE : out STR_PTR) is begin PATH := null; FILE := null; ERR := NO_MORE_FILES; if STARTED or else START then NEW_PATH := new STRING'(FILE_SPECIFICATION.PARSE(ARG)); if FILE_SPECIFICATION.SET(TO => NEW_PATH.all) then FILE_IO.FIND_FIRST(NAME_TEMPLATE => ARG, TRANSFER_AREA => SEARCH_DATA, FILE_INFO => INFORMATION, ERROR => ERR); end if; CHECK(ERR, PATH, FILE); end if; end GET_FIRST; procedure GET_NEXT(ARG : in STRING; PATH : out STR_PTR; FILE : out STR_PTR) is begin PATH := null; FILE := null; FILE_IO.FIND_NEXT(TRANSFER_AREA => SEARCH_DATA, FILE_INFO => INFORMATION, ERROR => ERR); CHECK(ERR, PATH, FILE); end GET_NEXT; end WILD_CARD;