home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / ipl / progs / fset.icn < prev    next >
Text File  |  2000-07-29  |  6KB  |  214 lines

  1. ############################################################################
  2. #
  3. #    File:     fset.icn
  4. #
  5. #    Subject:  Program to do set operations on file specifications
  6. #
  7. #    Author:   Thomas R. Hicks
  8. #
  9. #    Date:     June 10, 1988
  10. #
  11. ############################################################################
  12. #
  13. #   This file is in the public domain.
  14. #
  15. ############################################################################
  16. #
  17. #   The UNIX shell provides for the specification of filenames
  18. #  using ``wildcards''.  Each wildcard specification may be
  19. #  thought of as defining a set of names (that is, those that
  20. #  match the specification).  Fset allows the user to apply the
  21. #  set operations of intersection, union, and difference to
  22. #  these filename sets. The resultant list may then be used as
  23. #  an argument to other shell commands.
  24. #
  25. #  Fset's argument is an expression composed of legal UNIX file
  26. #  specifications, parenthesis, and the following set opera-
  27. #  tors:
  28. #
  29. #    &&   intersection
  30. #    ++   union
  31. #    --   difference
  32. #
  33. #  Because characters that have special meaning to the shell
  34. #  occur frequently in the arguments used for fset, it is
  35. #  advisable to quote the arguments consistently.
  36. #
  37. #  The use of fset is illustrated by the following examples:
  38. #
  39. #    fset 'g*--*.icn'
  40. #
  41. #  produces the list (set) of filenames for files beginning
  42. #  with g, excluding those ending with .icn.
  43. #
  44. #  Similarly,
  45. #
  46. #    fset '*'
  47. #
  48. #  produces all files in the current directory excluding the .
  49. #  and .. files.
  50. #
  51. #    fset '((*--*.icn)++c*)'
  52. #  and
  53. #
  54. #    fset '(*--*.icn)++c*'
  55. #
  56. #  produces the complement of all filenames ending with .icn in
  57. #  addition to all filenames beginning with c.
  58. #
  59. #    fset '(((c? && c*)))'
  60. #
  61. #  is a redundant, but legal, specification for all two-
  62. #  character filenames that begin with c, while
  63. #
  64. #    fset '.*'
  65. #
  66. #  produces the set of filenames for all hidden files, exclud-
  67. #  ing the . and ..  files.
  68. #
  69. #  Limitations:
  70. #
  71. #  Multiple command line arguments, formed by omitting the
  72. #  quotes around the file set expression, are permitted.  Their
  73. #  use is limited, however, since parentheses do not get past
  74. #  the shell's command-line expansion.
  75. #
  76. #  Almost any legal file specification will work when enclosed
  77. #  in quotes except that the simple grammar that is used cannot
  78. #  handle blanks adjacent to parentheses.
  79. #
  80. #  File names that begin or end in ``questionable'' characters
  81. #  such as *, ?, +, -, and &, probably will not work.
  82. #
  83. #  A file specification that, when interpreted by the shell,
  84. #  produces no matching filename will be placed (unchanged) in
  85. #  the result.
  86. #
  87. ############################################################################
  88. #
  89. #  See also:  gcomp.icn
  90. #
  91. ############################################################################
  92. #
  93. #  Requires:  UNIX
  94. #
  95. ############################################################################
  96.  
  97. procedure main(args)
  98.    local i, fyls, arglist
  99.    if *args = 0 then return
  100.    if *args > 1 then
  101.       every i := 2 to *args do
  102.          args[1] ||:= (" " || args[i])
  103.    (arglist := parse(args[1])) |
  104.       stop("Invalid file specification expression")
  105.    case type(arglist) of {
  106.       "string"    : fyls := mkfset(arglist)
  107.       "list"    : fyls := exec(arglist)
  108.       default    : stop("Main: bad type -can't happen")
  109.       }
  110.    fyls := sort(fyls)
  111.    every write(!fyls," ")
  112. end
  113.  
  114. procedure Exp()            # file spec expression parser
  115.    local a
  116.    suspend (a := [Factor(),=Op(),Factor()] & [a[2],a[1],a[3]]) |
  117.       Factor() |
  118.       (a := [="(",Exp(),=")"] & .a[2])
  119. end
  120.  
  121. procedure Factor()        # file spec expression parser
  122.    local a
  123.    suspend (a := [Term(),=Op(),Term()] & [a[2],a[1],a[3]]) |
  124.       Term() |
  125.       (a := [="(",Factor(),=")"] & .a[2])
  126. end
  127.  
  128. procedure Name()        # file spec name matcher
  129.    static valid
  130.    initial valid := ~'()'
  131.    suspend (any(~valid) || fail) | tab(find(Op()) | many(valid))
  132. end
  133.  
  134. procedure Non()            # file spec expression parser
  135.    local a
  136.    suspend a := [Name(),=Op(),Name()] & [a[2],a[1],a[3]]
  137. end
  138.  
  139. procedure Op()            # file spec operation matcher
  140.    suspend !["++","--","&&"]
  141. end
  142.  
  143. procedure Term()        # file spec expression parser
  144.    local a
  145.    suspend (a := [="(",Non(),=")"] & .a[2]) |
  146.            Name()
  147. end
  148.  
  149. procedure bldfset(arg)        # build file set, excluding . and ..
  150.    local line
  151.    static dotfiles
  152.    initial dotfiles := set([".",".."])
  153.    line := read(open("echo " || arg,"rp"))
  154.    return str2set(line,' ') -- dotfiles
  155. end
  156.  
  157. procedure exec(lst)        # process file spec list recursively
  158.    return setops(lst[1])(exec2(lst[2]),exec2(lst[3]))
  159. end
  160.  
  161. procedure exec2(arg)        # helping procedure for exec
  162.    case type(arg) of {
  163.       "string"    : return mkfset(arg)
  164.       "list"    : return exec(arg)
  165.       default    : stop("exec2: can't happen")
  166.       }
  167. end
  168.  
  169. procedure mkfset(fspec)        # make file list from specification
  170.    if fspec == "*" then
  171.       fspec := "* .*"
  172.    return bldfset(fspec)
  173. end
  174.  
  175. procedure parse(str)        # top level of parsing procedures
  176.    local res
  177.    str ? (res := Exp() & pos(0)) | fail
  178.    return res
  179. end
  180.  
  181. procedure sdiff(f1,f2)        # set difference
  182.    return f1 -- f2
  183. end
  184.  
  185. procedure setops(op)        # return correct set operaton
  186.    case op of {
  187.       "++"    : return sunion
  188.       "&&"    : return sinter
  189.       "--"    : return sdiff
  190.       }
  191. end
  192.  
  193. procedure sinter(f1,f2)        # set intersection
  194.    return f1 ** f2
  195. end
  196.  
  197. procedure str2set(str,delim)    # convert delimited string into a set
  198.    local fset, f
  199.    fset := set()
  200.    str ? {
  201.       while f := (tab(upto(delim))) do {
  202.          insert(fset,f)
  203.          move(1)
  204.          }
  205.       if "" ~== (f := tab(0)) then
  206.          insert(fset,f)
  207.       }
  208.    return fset
  209. end
  210.  
  211. procedure sunion(f1,f2)        # set union
  212.    return f1 ++ f2
  213. end
  214.