home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / OL.LZH / PROGS.LZH / FSET.ICN < prev    next >
Text File  |  1991-07-13  |  6KB  |  210 lines

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