(*---------------------------------------------------------------------------
    :Program.    With.mod
    :Author.     Fridtjof Siebert
    :Address.    Nobileweg 67, D-7-Stgt-40
    :Shortcut.   [fbs]
    :Version.    1.0
    :Date.       19-Jan-88
    :Copyright.  PD
    :Language.   Modula-II
    :Translator. M2Amiga v3.1d
    :Imports.    arp.library 34
    :Contents.   Programm to execute a CLI command on multiple files
    :Usage.      WITH <File-Pattern> <Command> [ALL] [DIRS] [FILES] [SHOW]
---------------------------------------------------------------------------*)

MODULE With;

(*------  IMPORTs:  ------*)

FROM SYSTEM  IMPORT ADR, ADDRESS, LONGSET;
FROM Arts    IMPORT Assert, wbStarted, dosCmdBuf, dosCmdLen, Terminate,
                    detectCtrlC;
FROM ARP     IMPORT StdAnchorPathPtr, FindFirst, FindNext, FreeAnchorChain,
                    ArpAlloc, AnchorPathPtr, Puts, GADS, AddDANode,
                    FreeDAList, DirEntryTypeSet, DirectoryEntryPtr, Printf,
                    errorBreak, ArpAllocMem, Examine, ExNext, Lock, UnLock,
                    TackOn, CheckBreak, Execute, ArpOpen;
FROM Dos     IMPORT ctrlC, ctrlF, noMoreEntries, FileInfoBlockPtr, FileLockPtr,
                    sharedLock, newFile, FileHandlePtr;
FROM Exec    IMPORT MemReqs, MemReqSet;

(*------  CONSTs:  ------*)

CONST
  Template = "PATTERN,COMMAND,TO/k,ALL/S,DIRS/S,FILES/S,SHOW/S";
  Help = '#With starts a cli command multiple times with different files##Usage: With <File-Pattern> "Command" [TO <File>] [ALL] [DIRS] [FILES] [SHOW]##Example: WITH * "RENAME $ AS $.txt" ALL FILES SHOW##© 1988 by Fridtjof Siebert / AMOK Stuttgart#';
  Break = "*** Break.";
  NoMem = "no memory.";

(*------  TYPEs:  ------*)

TYPE
  StringType = ARRAY[0..255] OF CHAR;

(*------  VARs:  ------*)

VAR
  ap: StdAnchorPathPtr;
  CharPtr: POINTER TO CHAR;
  Args: RECORD pat,comm,to,all,dirs,files,show: ADDRESS END;
  Argc: INTEGER;
  l: LONGINT;
  n,c,res: INTEGER;
  String: StringType;
  StringPtr: POINTER TO StringType;
  StrFound: BOOLEAN;
  FileList,de: DirectoryEntryPtr;
  break: LONGSET;
  out: FileHandlePtr;

(*------  Procedure for option ALL:  ------*)

PROCEDURE GetAllFiles(Path: StringType): BOOLEAN;

VAR
  fib: FileInfoBlockPtr;
  lock: FileLockPtr;
  res: BOOLEAN;

BEGIN
  fib := ArpAllocMem(SIZE(fib^),MemReqSet{chip,memClear});
  lock := Lock(ADR(Path),sharedLock);
  IF lock=NIL THEN
    StringPtr := ADR(Path); l:=Printf(ADR("Can't lock %s !"),ADR(StringPtr));
    RETURN FALSE;
  END;
  res := TRUE;
  IF Examine(lock,fib) THEN
    LOOP
      IF NOT ExNext(lock,fib) THEN EXIT END;
      WITH fib^ DO
        String := Path; TackOn(ADR(String),ADR(fileName));
        IF ((Args.files=NIL) AND (dirEntryType>0)) OR
           ((Args.dirs =NIL) AND (dirEntryType<0)) THEN
          IF AddDANode(ADR(String),ADR(FileList),0,DirEntryTypeSet{})=NIL THEN
            l:= Puts(ADR(NoMem)); res := FALSE; EXIT;
          END;
        END;
        IF dirEntryType>0 THEN
          IF NOT GetAllFiles(String) THEN res := FALSE; EXIT END;
        END;
        IF CheckBreak(LONGSET{ctrlC..ctrlF},NIL)#LONGSET{} THEN
          l:=Puts(ADR(Break)); res := FALSE; EXIT;
        END;
      END;
    END;
  END;
  UnLock(lock);
  RETURN res;
END GetAllFiles;

(*------  MAIN:  ------*)

BEGIN

(*------  Don't you start us from WB:  ------*)

  Assert(NOT wbStarted,ADR("Please start from CLI!"));

(*------  Let's modify our HELP-constant:  ------*)

  CharPtr := ADR(Help);
  WHILE CharPtr^#0C DO IF CharPtr^="#" THEN CharPtr^:=12C END; INC(CharPtr) END;

(*------  Handle Argument list:  ------*)

  Argc := GADS(dosCmdBuf,dosCmdLen,ADR(Help),ADR(Args),ADR(Template));
  IF Argc<2 THEN l := Puts(ADR(Help)); Terminate(0) END;
  IF Args.to#NIL THEN out := ArpOpen(Args.to,newFile) ELSE out := NIL END;

(*------  Get list of files:  ------*)

  detectCtrlC := FALSE;
  ap := ArpAlloc(SIZE(ap^));
  IF ap=NIL THEN l := Puts(ADR(NoMem)); Terminate(0) END;

  ap^.anchor.length := 256;
  ap^.anchor.breakBits := LONGSET{ctrlC..ctrlF};

  res := FindFirst(Args.pat,AnchorPathPtr(ap));
  WHILE res = 0 DO
    WITH ap^.anchor.info DO
      IF (Args.all#NIL) AND (dirEntryType>0) THEN
        StringPtr := ADR(ap^.buffer);
        IF NOT GetAllFiles(StringPtr^) THEN
          FreeDAList(FileList); Terminate(0);
        END;
      END;
      IF ((Args.files=NIL) AND (dirEntryType>0)) OR
         ((Args.dirs =NIL) AND (dirEntryType<0)) THEN
        IF AddDANode(ADR(ap^.buffer),ADR(FileList),0,DirEntryTypeSet{})=NIL THEN
          l:= Puts(ADR(NoMem));
          FreeDAList(FileList);
          Terminate(0);
        END;
      END;
    END;
    res := FindNext(AnchorPathPtr(ap));
  END;
  FreeAnchorChain(AnchorPathPtr(ap));

(*------  Do It:  ------*)

  CASE res OF
  errorBreak: l:=Puts(ADR(Break)); |
  noMoreEntries:
    de := FileList;
    break := LONGSET{};
    WHILE (de#NIL) AND (break=LONGSET{}) DO
      n := 0; CharPtr := Args.comm; StrFound := FALSE;
      WHILE (CharPtr^#0C) AND (n#-1) DO
        IF CharPtr^=";" THEN CharPtr^ := 12C END;
        IF CharPtr^="$" THEN
          StrFound := TRUE; c := 0;
          WHILE (de^.name[c]#0C) AND (n#-1) DO
            String[n]:=de^.name[c]; INC(c); INC(n); IF n>253 THEN n:=-1 END;
          END;
        ELSE
          String[n] := CharPtr^; INC(n); IF n>253 THEN n := -1 END;
        END;
        INC(CharPtr);
      END;
      IF NOT StrFound THEN
        String[n] := " "; INC(n); c := 0;
        WHILE (de^.name[c]#0C) AND (n#-1) DO
          String[n]:=de^.name[c]; INC(c); INC(n); IF n>253 THEN n :=-1 END;
        END;
      END;
      IF n=-1 THEN
        l:=Puts(ADR("string too long!"));
      ELSE
        String[n] := 0C;
        IF Args.show#NIL THEN l:=Puts(ADR(String)) END;
        IF Execute(ADR(String),NIL,out)=0 THEN
          l := Puts(ADR("Execute failed."));
        END;
      END;
      de := de^.next;
      break := CheckBreak(LONGSET{ctrlC..ctrlF},NIL);
    END;
    IF break=LONGSET{} THEN
      l := Puts(ADR("--- Done."));
    ELSE
      l := Puts(ADR(Break));
    END; |

  ELSE
    l:=Printf(ADR("Dos Error # %d"),ADR(res)); l:=Puts(ADR(""));
  END;

  FreeDAList(FileList);

END With.
