home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / OL.LZH / PROGS.LZH / DUPLPROC.ICN < prev    next >
Text File  |  1991-09-05  |  9KB  |  317 lines

  1. ############################################################################
  2. #
  3. #    Name:     duplproc.icn
  4. #
  5. #    Title:     Find duplicate procedure/record identifiers in a library
  6. #
  7. #    Author:     Richard L. Goerwitz
  8. #
  9. #    Version: 1.8
  10. #
  11. #    Date:     January 4, 1991
  12. #
  13. ############################################################################
  14. #
  15. #  Use this if you plan on posting utility procedures suitable for
  16. #  inclusion in someone's Icon library directories.
  17. #
  18. #  duplproc.icn compiles into a program which will search through
  19. #  every directory in your ILIBS environment variable (and/or in the
  20. #  directories supplied as arguments to the program).  If it finds any
  21. #  duplicate procedure or record identifiers, it will report this on
  22. #  the standard output.
  23. #
  24. #  It is important to try to use unique procedure names in programs
  25. #  you write, especially if you intend to link in some of the routines
  26. #  contained in the IPL.  Checking for duplicate procedure names has
  27. #  been somewhat tedious in the past, and many of us (me included)
  28. #  must be counted as guilty for not checking more thoroughly.  Now,
  29. #  however, checking should be a breeze.
  30. #
  31. #  BUGS:  Duplproc thinks that differently written names for the same
  32. #  directory are in fact different directories.  Use absolute path
  33. #  names, and you'll be fine.
  34. #
  35. ############################################################################
  36. #
  37. #  Requires:  UNIX (MS-DOS will work if all files are in MS-DOS format)
  38. #
  39. ############################################################################
  40.  
  41. record procedure_stats(name, file, lineno)
  42.  
  43. procedure main(a)
  44.  
  45.     local proc_table, fname, elem, lib_file, tmp
  46.  
  47.     #     usage:  duplproc [libdirs]
  48.     #
  49.     # Where libdirs is a series of space-separated directories in
  50.     # which relevant library files are to be found.  To the
  51.     # directories listed in libdirs are added any directories found in
  52.     # the ILIBS environment variable.
  53.  
  54.     proc_table := table()
  55.     too_many_table := table()
  56.  
  57.     # Put all command-line option paths, and ILIBS paths, into one sorted
  58.     # list.  Then get the names of all .icn filenames in those paths.
  59.     every fname := !get_icn_filenames(getlibpaths(a)) do {
  60.     # For each .icn filename, open that file, and find all procedure
  61.     # calls in it.
  62.     if not (lib_file := open(fname, "r")) then
  63.         write(&errout,"Can't open ",fname," for reading.")
  64.     else {
  65.         # Find all procedure calls in lib_file.
  66.         every elem := !get_procedures(lib_file,fname) do {
  67.         /proc_table[elem.name] := set()
  68.         insert(proc_table[elem.name],elem)
  69.         }
  70.         close(lib_file)
  71.     }
  72.     }
  73.  
  74.     every elem := key(proc_table) do {
  75.     if *proc_table[elem] > 1 then {
  76.         write("\"", elem, "\" is defined in ",*proc_table[elem]," places:")
  77.         every tmp := !proc_table[elem] do {
  78.         write("     ",tmp.file, ", line ",tmp.lineno)
  79.         }
  80.     }
  81.     }
  82.  
  83. end
  84.  
  85.  
  86.  
  87. procedure getlibpaths(ipl_paths)
  88.  
  89.     # Unite command-line args and ILIBS environment variable into one
  90.     # path list.
  91.  
  92.     local i, path
  93.  
  94.     # Make sure all paths have a consistent format (one trailing slash).a
  95.     if *\ipl_paths > 0 then {
  96.     every i := 1 to *ipl_paths do {
  97.         ipl_paths[i] := fixup_path(ipl_paths[i])
  98.     }
  99.     ipl_paths := set(ipl_paths)
  100.     }
  101.     else ipl_paths := set()
  102.  
  103.     # If the ILIBS environment variable is set, read it into
  104.     # ipl_paths.  Spaces - NOT COLONS - are used as separators.
  105.     getenv("ILIBS") ? {
  106.     while path := tab(find(" ")) do {
  107.         insert(ipl_paths, fixup_path(path))
  108.         tab(many(' '))
  109.     }
  110.     insert(ipl_paths, fixup_path(tab(0)))
  111.     }
  112.  
  113.     return sort(ipl_paths)
  114.  
  115. end
  116.  
  117.  
  118.  
  119. procedure fixup_path(s)
  120.     # Make sure paths have a consistent format.
  121.     return "/" ~== (trim(s,'/') || "/")
  122. end
  123.  
  124.  
  125.  
  126. procedure get_procedures(intext,fname)
  127.  
  128.     # Extracts the names of all procedures declared in file f.
  129.     # Returns them in a list, each of whose elements have the
  130.     # form record procedure_stats(procedurename, filename, lineno).
  131.  
  132.     local psl, f_pos
  133.     static name_chars
  134.     initial {
  135.     name_chars := &ucase ++ &lcase ++ &digits ++ '_'
  136.     }
  137.  
  138.     # Initialize procedure-name list, line count.
  139.     psl := list()
  140.     line_no := 0
  141.  
  142.     # Find procedure declarations in intext.
  143.     while line := read(intext) & line_no +:= 1 do {
  144.     take_out_comments(line) ? {
  145.         if tab(match("procedure")) then {
  146.         tab(many(' \t')) &
  147.             put(psl, procedure_stats(
  148.                 "main" ~== tab(many(name_chars)), fname, line_no))
  149.         }
  150.     }
  151.     }
  152.  
  153.     return psl   # returns empty list if no procedures found
  154.  
  155. end
  156.  
  157.  
  158.  
  159. procedure take_out_comments(s)
  160.  
  161.     # Commented-out portions of Icon code - strip 'em.  Fails on lines
  162.     # which, either stripped or otherwise, come out as an empty string.
  163.     #
  164.     # BUG:  Does not handle lines which use the _ string-continuation
  165.     # notation.  Typically take_out_comments barfs on the next line.
  166.  
  167.     local i, j, c, c2
  168.  
  169.     s ? {
  170.     tab(many(' \t'))
  171.     pos(0) & fail
  172.         find("#") | (return trim(tab(0),' \t'))
  173.     match("#") & fail
  174.     (s2 <- tab(find("#"))) ? {
  175.         c2 := &null
  176.         while tab(upto('\\"\'')) do {
  177.         case c := move(1) of {
  178.             "\\"   : {
  179.             if match("^")
  180.             then move(2)
  181.             else move(1)
  182.             }
  183.             default: {
  184.             if \c2
  185.             then (c == c2, c2 := &null)
  186.             else c2 := c
  187.             }
  188.         }
  189.         }
  190.         /c2
  191.     }
  192.     return "" ~== trim((\s2 | tab(0)) \ 1, ' \t')
  193.     }
  194.  
  195. end
  196.  
  197.  
  198.  
  199. procedure get_icn_filenames(lib_paths)
  200.  
  201.     # Return the names of all .icn files in all of the paths in the
  202.     # list lib_paths.  The dir routine used depends on which OS we
  203.     # are running under.
  204.  
  205.     local procedure_stat_list
  206.     static get_dir
  207.     initial get_dir := set_getdir_by_os()
  208.  
  209.     procedure_stat_list := list()
  210.     # Run through every possible path in which files might be found,
  211.     # and get a list of procedures contained in those files.
  212.     every procedure_stat_list |||:= get_dir(!lib_paths)
  213.  
  214.     return procedure_stat_list
  215.  
  216. end
  217.  
  218.  
  219.  
  220. procedure set_getdir_by_os()
  221.  
  222.     if find("UNIX", &features)
  223.     then return unix_get_dir
  224.     else if find("MS-DOS", &features)
  225.     then return msdos_get_dir
  226.     else stop("Your operating system is not (yet) supported.")
  227.  
  228. end
  229.  
  230.  
  231.  
  232. procedure msdos_get_dir(dir)
  233.  
  234.     # Returns a sorted list of all filenames (full paths included) in
  235.     # directory "dir."  The list is sorted.  Fails on invalid or empty
  236.     # directory.  Aborts if temp file cannot be opened.
  237.     #
  238.     # Temp files can be directed to one or another directory either by
  239.     # manually setting the variable temp_dir below, or by setting the
  240.     # value of the environment variable TEMPDIR to an appropriate
  241.     # directory name.
  242.  
  243.     local in_dir, filename_list, line
  244.     static temp_dir
  245.     initial {
  246.         temp_dir := 
  247.             (trim(map(getenv("TEMPDIR"), "/", "\\"), '\\') || "\\") |
  248.                 ".\\"
  249.     }
  250.  
  251.     # Get name of tempfile to be used.
  252.     temp_name := get_dos_tempname(temp_dir) |
  253.     stop("No more available tempfile names!")
  254.  
  255.     # Make sure we have an unambiguous directory name, with backslashes
  256.     # instead of Unix-like forward slashes.
  257.     dir := trim(map(dir, "/", "\\"), '\\') || "\\"
  258.  
  259.     # Put dir listing into a temp file.
  260.     system("dir "||dir||" > "||temp_name)
  261.  
  262.     # Put tempfile entries into a list, removing blank- and
  263.     # space-initial lines.  Exclude directories (i.e. return file
  264.     # names only).
  265.     in_dir := open(temp_name,"r") |
  266.     stop("Can't open temp file in directory ",temp_dir,".")
  267.     filename_list := list()
  268.     every filename := ("" ~== !in_dir) do {
  269.         match(" ",filename) | find(" <DIR>", filename) & next
  270.     filename ?:= trim(trim(tab(10)) || "." || tab(13), '. ')
  271.     if filename ? (tab(find(".ICN")+4), pos(0))
  272.     then put(filename_list, map(dir || filename))
  273.     }
  274.  
  275.     # Clean up.
  276.     close(in_dir) & remove(temp_name)
  277.  
  278.     # Check to be sure we actually managed to read some files.
  279.     if *filename_list = 0 then fail
  280.     else return sort(filename_list)
  281.  
  282. end
  283.  
  284.  
  285.  
  286. procedure get_dos_tempname(dir)
  287.  
  288.     # Don't clobber existing files.  Get a unique temp file name for
  289.     # use as a temporary storage site.
  290.  
  291.     every temp_name := dir || "icondir." || right(string(1 to 999),3,"0") do {
  292.     temp_file := open(temp_name,"r") | break
  293.         close(temp_file)
  294.     }
  295.     return \temp_name
  296.  
  297. end
  298.  
  299.  
  300.  
  301. procedure unix_get_dir(dir)
  302.  
  303.     dir := trim(dir, '/') || "/"
  304.     filename_list := list()
  305.     in_dir := open("/bin/ls -F "||dir, "pr")
  306.     every filename := ("" ~== !in_dir) do {
  307.     match("/",filename,*filename) & next
  308.     if filename ? (not match("s."), tab(find(".icn")+4), pos(0))
  309.     then put(filename_list, trim(dir || filename, '*'))
  310.     }
  311.     close(in_dir)
  312.  
  313.     if *filename_list = 0 then fail
  314.     else return filename_list
  315.  
  316. end
  317.