pSyntax10.Scn.Fntex`_VersionElemsAllocBeg#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMac$Syntax14b.Scn.FntPOWERMAC VERSIONSyntax14b.Scn.Fnt`_VersionElemsAllocEnd"`_#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMac:'Syntax10.Scn.FntC8FoldElemsNew#Syntax10.Scn.Fnt(* ---------------------------------------------------------- Backup does an incremental backup between two directories, i.e. only the files that have changed since the last backup are copied. Backup.WriteFiles ( {src dst} ~ | "^") src and dst are given as Macintosh path names starting with the volume name and ending with ":". If a path name contains blanks it must be written under quotes. All entries in dst which are not also in src are deleted so that after the backup the contents of dst will be equal to the contents of src. Example: Backup.WriteFiles Othello:Text:Lectures:EiP: hm:Backup:EiP: ~ ----------------------------------------------------------*)Syntax10i.Scn.Fnt 8IStampElemsAlloc9 Oct 96B$h*% + Gg8#Syntax10.Scn.Fntww VAR i: INTEGER; BEGIN i := 0; WHILE in[i] # 0X DO out[i+1] := in[i]; INC(i) END; out[0] := CHR(i) END MakeStr255; 8>8#Syntax10.Scn.Fnt VAR res: INTEGER; BEGIN NEW(par); par.ioCompletion := 0; par.ioNamePtr := SYSTEM.ADR(spec.name); par.ioVRefNum := spec.vRefNum; par.ioDirID := spec.parID; par.ioFDirIndex := 0; res := Sys.PBGetCatInfo(par); ASSERT(res = 0) END GetFileInfo; 8<8#Syntax10.Scn.Fnt VAR res: INTEGER; BEGIN NEW(par); par.ioCompletion := 0; par.ioNamePtr := SYSTEM.ADR(spec.name); par.ioVRefNum := spec.vRefNum; par.ioDrDirID := spec.parID; par.ioFDirIndex := 0; res := Sys.PBGetCatInfo(par); ASSERT(res = 0) END GetDirInfo; 8 18#Syntax10.Scn.Fnt VAR ch, start: CHAR; i: INTEGER; BEGIN REPEAT In.Char(ch) UNTIL (ch > " ") OR ~In.Done; i := 1; IF (ch = '"') OR (ch = "'") THEN start := ch; In.Char(ch); WHILE In.Done & (ch # start) DO s[i] := ch; INC(i); In.Char(ch) END; In.Char(ch); ELSE WHILE In.Done & (ch > " ") DO s[i] := ch; INC(i); In.Char(ch) END END; s[i] := 0X; s[0] := CHR(i-1); FOR i := 1 TO ORD(s[0]) DO IF (s[i] >= CHR(129)) & (s[i] <= CHR(133)) THEN s[i] := umlaut[ORD(s[i])-129] END END END ReadString; 8+ 8#Syntax10.Scn.Fnt VAR i, j: INTEGER; BEGIN FOR i := 1 TO ORD(s[0]) DO FOR j := 0 TO LEN(umlaut)-1 DO IF s[i] = umlaut[j] THEN s[i] := CHR(129 + j) END END END; s[0] := " "; s[i] := 0X; Out.String(s) END PrintString; 87A8#Syntax10.Scn.Fnt VAR i: INTEGER; BEGIN IF a[0] # b[0] THEN RETURN FALSE END; i := ORD(a[0]); WHILE (i > 0) & (a[i] = b[i]) DO DEC(i) END; RETURN i = 0 END EqualString; 88#Syntax10.Scn.Fnt BEGIN Out.String(" --- "); CASE n OF -33: Out.String("directory full") | -34: Out.String("disk full") | -35: Out.String("volume not found") | -37: Out.String("bad file or volume name") | -43: Out.String("file not found") | -44, -46: Out.String("volume locked") | -45: Out.String("file locked") | -47: Out.String("file busy or directory not empty") | -49: Out.String("file already open for writing") ELSE Out.F("error #", n) END; Out.Ln END Err; 8@8c8388;8Syntax10.Scn.FntR_8FoldElemsNew#Syntax10.Scn.FntPrintString(f.spec.name); IF g # NIL THEN res := Sys.FSpDelete(g.spec); ASSERT(res = 0, 99) ELSE NEW(g); FOR i := 0 TO ORD(f.spec.name[0]) DO s[i] := f.spec.name[i] END; res := Sys.FSMakeFSSpec(dt.spec.vRefNum, dt.dirID, s, g.spec); ASSERT(res = fnfErr, 98) END; res := Sys.FSpCreate(g.spec, f.creator, f.type, Sys.smSystemScript); IF res # 0 THEN Err(res); RETURN END; Syntax10i.Scn.Fnt8J8#Syntax10.Scn.Fntres := Sys.FSpOpenDF(f.spec, 0, fRef); IF res # 0 THEN Err(res); RETURN END; res := Sys.FSpOpenDF(g.spec, 0, gRef); IF res # 0 THEN Err(res); RETURN END; res := Sys.FSRead(fRef, f.len, SYSTEM.ADR(buf^)); ASSERT(res = 0, 94); res := Sys.FSWrite(gRef, f.len, SYSTEM.ADR(buf^)); IF res # 0 THEN Err(res) END; res := Sys.FSClose(fRef); ASSERT(res = 0, 92); res := Sys.FSClose(gRef); ASSERT(res = 0, 91);8 8#Syntax10.Scn.FntIF f.rlen > 0 THEN res := Sys.FSpOpenRF(f.spec, 0, fRef); IF res # 0 THEN Err(res); RETURN END; res := Sys.FSpOpenRF(g.spec, 0, gRef); IF res # 0 THEN Err(res); RETURN END; res := Sys.FSRead(fRef, f.rlen, SYSTEM.ADR(buf^)); ASSERT(res = 0, 88); res := Sys.FSWrite(gRef, f.rlen, SYSTEM.ADR(buf^)); IF res # 0 THEN Err(res) END; res := Sys.FSClose(fRef); ASSERT(res = 0, 86); res := Sys.FSClose(gRef); ASSERT(res = 0, 85); Out.String(" + resources") END;88 VAR res, i: INTEGER; s: Sys.Str255; fRef, gRef: INTEGER; info: FileInfo; BEGIN create empty g on dt copy data fork copy resource fork Out.String(" saved$"); INC(savedFiles) END SaveFile; 8 48#Syntax10.Scn.Fnt VAR d: Directory; info: DirInfo; res: INTEGER; BEGIN NEW(d); d.next := NIL; d.files := NIL; d.dirs := NIL; d.spec := spec; GetDirInfo(spec, info); d.dirID := info.ioDrDirID; d.date := info.ioDrMdDat; RETURN d END NewDir; 8<x8#Syntax10.Scn.Fntff VAR spec: Sys.FSSpec; s: Sys.Str255; res, i: INTEGER; dummy: LONGINT; BEGIN FOR i := 0 TO ORD(df.spec.name[0]) DO s[i] := df.spec.name[i] END; res := Sys.FSMakeFSSpec(parent.spec.vRefNum, parent.dirID, s, spec); ASSERT(res = fnfErr, 29); res := Sys.FSpDirCreate(spec, Sys.smSystemScript, dummy); ASSERT(res = 0, 30); dt := NewDir(spec) END CreateDir; 82U8#Syntax10.Scn.Fnt VAR g: File; BEGIN g := d.dirs; WHILE (g # NIL) & ~EqualString(f.spec.name, g.spec.name) DO g := g.next END; RETURN g END ThisDir; 87X8#Syntax10.Scn.Fnt VAR f: File; i: INTEGER; BEGIN FOR i := 1 TO indent DO Out.String(" ") END; Out.String("--- "); PrintString(d.spec.name); Out.Ln; f := d.files; WHILE f # NIL DO FOR i := 1 TO indent DO Out.String(" ") END; Out.String(" "); PrintString(f.spec.name); Out.Ln; f := f.next END; f := d.dirs; WHILE f # NIL DO PrintDir(f(Directory), indent + 1); f := f.next END END PrintDir; 83P8CSyntax10.Scn.FntSyntax10i.Scn.Fnt%n VAR f: File; d1: Directory; par: FileInfo; res, n, i: INTEGER; spec: Sys.FSSpec; s: Sys.Str255; BEGIN n := 1; Out.Char(prompt); NEW(par); par.ioCompletion := 0; par.ioVRefNum := d.spec.vRefNum; LOOP s[0] := 0X; par.ioNamePtr := SYSTEM.ADR(s); par.ioDirID := d.dirID; par.ioFDirIndex := n; INC(n); res := Sys.PBGetCatInfo(par); IF res = 0 THEN IF par.ioFlFndrInfo.fdFlags >= 0 THEN (*no alias: alias files have bit 15 set*) res := Sys.FSMakeFSSpec(d.spec.vRefNum, d.dirID, s, spec); ASSERT(res = 0); IF ODD(par.ioFlAttrib DIV 16) THEN (*directory*) d1 := NewDir(spec); d1.next := d.dirs; d.dirs := d1 ELSE (*file*) f := NewFile(spec, par); f.next := d.files; d.files := f END END ELSIF res = fnfErr THEN EXIT ELSE HALT(20) END END; f := d.dirs; WHILE f # NIL DO FillDir(f(Directory), prompt); f := f.next END END FillDir; 8(8#Syntax10.Scn.Fnt VAR f, g: File; first: BOOLEAN; BEGIN f := df.files; first := TRUE; WHILE f # NIL DO g := ThisFile(dt, f); IF (g = NIL) OR (f.date > g.date) THEN IF first THEN Out.String("-- "); PrintString(df.spec.name); Out.Ln; first := FALSE END; SaveFile(f, g, dt) END; g.touched := TRUE; f := f.next END; f := df.dirs; WHILE f # NIL DO g := ThisDir(dt, f); IF g = NIL THEN CreateDir(f(Directory), dt, g) END; SaveDir(f(Directory), g(Directory)); g.touched := TRUE; f := f.next END END SaveDir; 8& 8QSyntax10.Scn.FntCSyntax10i.Scn.Fnt  VAR f: File; first: BOOLEAN; res: INTEGER; inf: DirInfo; BEGIN (*delete redundant files in d*) f := d.files; first := TRUE; WHILE f # NIL DO IF ~f.touched THEN IF first THEN Out.String("-- "); PrintString(d.spec.name); Out.Ln; first := FALSE END; res := Sys.FSpDelete(f.spec); PrintString(f.spec.name); Out.String(" deleted$") END; f := f.next END; f := d.dirs; WHILE f # NIL DO CleanupDir(f(Directory)); res := Sys.FSpDelete(f.spec); IF res = 0 THEN (*was empty*) IF first THEN Out.String("-- "); PrintString(d.spec.name); Out.Ln; first := FALSE END; PrintString(f.spec.name); Out.String(" deleted$") END; f := f.next END END CleanupDir; 8 Syntax10b.Scn.Fnt 8#Syntax10.Scn.Fnt   VAR path: Sys.Str255; df, dt: Directory; res: INTEGER; spec: Sys.FSSpec; BEGIN In.Open; Out.Open; savedFiles := 0; LOOP ReadString(path); IF (path[0] = 0X) OR (path[1] = "~") THEN EXIT END; res := Sys.FSMakeFSSpec(0, 0, path, spec); IF res # 0 THEN Out.F("-- Invalid source directory. res = #$", res); EXIT END; df := NewDir(spec); ReadString(path); res := Sys.FSMakeFSSpec(0, 0, path, spec); IF res # 0 THEN Out.F("-- Invalid destination directory. res = #$", res); EXIT END; dt := NewDir(spec); maxLen := 0; Out.String("Reading directories"); FillDir(df, "-"); FillDir(dt, "+"); Out.Ln; NEW(buf, maxLen); (*PrintDir(df, 0); PrintDir(dt, 0);*) SaveDir(df, dt); CleanupDir(dt) END; Out.F("$# files saved$", savedFiles); Out.Close; buf := NIL END WriteFiles; 8 Documentation MODULE Backup; (* HM  *) IMPORT Sys, In, Out, SYSTEM; CONST fnfErr = -43; TYPE File = POINTER TO FileDesc; FileDesc = RECORD next: File; spec: Sys.FSSpec; date, len, rlen, creator, type: LONGINT; touched: BOOLEAN END; Directory = POINTER TO DirectoryDesc; DirectoryDesc = RECORD (FileDesc) dirID: LONGINT; files: File; (*the files in this directory*) dirs: File (*the subdirectories in this directory*) END; DirInfo = POINTER TO DirInfoDesc; DirInfoDesc = RECORD (Sys.CInfoPBRec) ioDrUsrWds: Sys.DInfo; ioDrDirID: LONGINT; ioDrNmFls: INTEGER; f3: ARRAY 9 OF INTEGER; ioDrCrDat: LONGINT; ioDrMdDat: LONGINT; ioDrBkDat: LONGINT; ioDrFndrInfo: Sys.DXInfo; ioDrParID: LONGINT END; FileInfo = Sys.CInfoPBFilePtr; VAR maxLen: LONGINT; (*max. file length (determines buffer sizes)*) buf: POINTER TO ARRAY OF CHAR; (*files are copied via this buffer*) savedFiles: LONGINT; (*number of saved files*) umlaut: ARRAY 5 OF CHAR; (*conversion of Oberon umlauts to Mac umlauts*) (*--- toolbox*) PROCEDURE MakeStr255 (VAR in: ARRAY OF CHAR; VAR out: Sys.Str255);  PROCEDURE GetFileInfo (spec: Sys.FSSpec; VAR par: FileInfo);  PROCEDURE GetDirInfo (spec: Sys.FSSpec; VAR par: DirInfo);  (*--- auxiliaries*) PROCEDURE ReadString (VAR s: ARRAY OF CHAR);  PROCEDURE PrintString (s: ARRAY OF CHAR);  PROCEDURE EqualString (a, b: ARRAY OF CHAR): BOOLEAN;  PROCEDURE Err (n: INTEGER);  (*--- files*) PROCEDURE NewFile (spec: Sys.FSSpec; info: FileInfo): File;  VAR f: File; BEGIN NEW(f); f.next := NIL; f.spec := spec; f.touched := FALSE; f.date := info.ioFlMdDat; f.len := info.ioFlLgLen; f.rlen := info.ioFlRLgLen; f.creator := info.ioFlFndrInfo.fdCreator; f.type := info.ioFlFndrInfo.fdType; IF f.len > maxLen THEN maxLen := f.len END; IF f.rlen > maxLen THEN maxLen := f.rlen END; RETURN f END NewFile;  PROCEDURE ThisFile (d: Directory; f: File): File;  VAR g: File; BEGIN g := d.files; WHILE (g # NIL) & ~EqualString(f.spec.name, g.spec.name) DO g := g.next END; RETURN g END ThisFile;  PROCEDURE SaveFile (f: File; VAR g: File; dt: Directory);  (*--- directories*) PROCEDURE NewDir (spec: Sys.FSSpec): Directory;  PROCEDURE CreateDir (df, parent: Directory; VAR dt: File);  PROCEDURE ThisDir (d: Directory; f: File): File;  (*PROCEDURE PrintDir (d: Directory; indent: INTEGER); *) PROCEDURE FillDir (d: Directory; prompt: CHAR);  PROCEDURE SaveDir (df, dt: Directory);  PROCEDURE CleanupDir (d: Directory);  PROCEDURE WriteFiles*;  BEGIN umlaut[0] := CHR(133); (*Oe*) umlaut[1] := CHR(134); (*Ue*) umlaut[2] := CHR(138); (*ae*) umlaut[3] := CHR(154); (*oe*) umlaut[4] := CHR(159); (*ue*) END Backup. 8FoldElemsNew#Syntax10.Scn.FntZZ(* ---------------------------------------------------------- Backup does an incremental backup between two directories, i.e. only the files that have changed since the last backup are copied. Backup.WriteFiles ( {src dst} ~ | "^") src and dst are given as path names. If a path name contains blanks it must be written under quotes. All entries in dst which are not also in src are deleted so that after the backup the contents of dst will be equal to the contents of src. Example: Backup.WriteFiles c:\Users\cs\Oberon.NT c:\Temp\Oberon ~ ----------------------------------------------------------*)Syntax10i.Scn.Fnt 8-IStampElemsAlloc9 Oct 96FG8mSyntax10.Scn.FntCSyntax10i.Scn.Fnt40|M FileAttrReadOnly = 0; FileAttrHidden = 1; FileAttrSystem = 2; (* file attributes *) FileAttrDirectory = 4; FileAttrArchive = 5; FileAttrNormal = 7; FileAttrTemp = 8; FileAttrCompressed = 11; FileAttrOffline = 12; CreateNew = 1; CreateAlways = 2; OpenExisting = 3; OpenAlways = 4; (* file creation options *) GenReadWrite = 0C0000000H; GenRead = 80000000H; (* file access modes *) ShareRead = 1; NULL = 0; InvalidHandle = -1; (* invalid Win32 file handle *) fromSystem = 1000H; (* FORMAT_MESSAGE_FROM_SYSTEM *) neutral = 0; (* LANG_NEUTRAL *) default = 1; (* SUBLANG_DEFAULT *)8Courier10.Scn.Fnt8#Syntax10.Scn.Fnt low, high: LONGINT END ; 88#Syntax10.Scn.FntRR year, month, weekday, day: INTEGER; hour, min, sec, millisec: INTEGER END ; 88#Syntax10.Scn.FntQQ creation, lastAccess, lastWrite: FileTime; len: LONGINT; attr: SET END ; 8I8#Syntax10.Scn.Fnt FileDesc = RECORD next: File; dir: ARRAY 260 OF CHAR; name: ARRAY 46 OF CHAR; handle: LONGINT; info: FileInfo; touched: BOOLEAN END ; 8(8QSyntax10.Scn.Fnt6Syntax10i.Scn.Fnt$ DirectoryDesc* = RECORD (FileDesc) files: File; (*the files in this directory*) dirs: File (*the subdirectories in this directory*) END ; 88XSyntax10i.Scn.FntSyntax10.Scn.Fnto.(* WIN32_FIND_DATA *) attrib: SET; (* file attributes *) creation, lastAcc, lastWrite: FileTime; sizeH, sizeL: LONGINT; res0, res1: LONGINT; name: ARRAY 260 (* = MAX_PATH *) OF CHAR; altName: ARRAY 14 OF CHAR END ; 88CSyntax10.Scn.FntSyntax10i.Scn.Fnt savedFiles: LONGINT; (*number of saved files*) CreateFile: PROCEDURE (name: LONGINT; accessMode: LONGINT; shareMode: LONGINT; securityAttr: LONGINT; createOpts: LONGINT; attrAndFlags: SET; template: LONGINT): LONGINT; CloseHandle: PROCEDURE (h: LONGINT): BOOLEAN; DeleteFile: PROCEDURE (name: LONGINT): BOOLEAN; ReadFile: PROCEDURE (f: LONGINT; data: LONGINT; count: LONGINT; VAR read: LONGINT; ovrlp: LONGINT): BOOLEAN; WriteFile: PROCEDURE (f: LONGINT; data, count: LONGINT; VAR written: LONGINT; ovrlp: LONGINT): BOOLEAN; GetFileSize: PROCEDURE (fd: LONGINT; fileSizeHigh: LONGINT): LONGINT; GetFileTime: PROCEDURE (fd: LONGINT; creation, lastAccess, lastWrite: LONGINT): BOOLEAN; SetFileTime: PROCEDURE (fd: LONGINT; creation, lastAccess, lastWrite: LONGINT): BOOLEAN; FindFirstFile: PROCEDURE (filename: LONGINT; data: LONGINT): LONGINT; FindNextFile: PROCEDURE (hFindFile: LONGINT; data: LONGINT): BOOLEAN; FindClose: PROCEDURE (hFindFile: LONGINT); GetFileAttributes: PROCEDURE (name: LONGINT): SET; CreateDir: PROCEDURE (name: LONGINT; secAttr: LONGINT): BOOLEAN; FileTimeToSystemTime: PROCEDURE (ft: LONGINT; st: LONGINT): BOOLEAN; FormatMessage: PROCEDURE (flags, source, msgId, langId, buffer, size, args: LONGINT): LONGINT; GetLastError: PROCEDURE (): LONGINT;8 MarkElemsAllocXW^8#Syntax10.Scn.Fnt BEGIN COPY(path, fullName); Strings.Append(Directories.delimiter, fullName); Strings.Append(name, fullName) END FullPathName; 8K8#Syntax10.Scn.Fnt VAR i, j: INTEGER; BEGIN i := 0; j := 0; WHILE path[i] # 0X DO IF path[i] = Directories.delimiter THEN j := i END ; INC(i) END ; i := 0; IF j # 0 THEN INC(j) END ; WHILE path[j] # 0X DO name[i] := path[j]; INC(i); INC(j) END ; name[i] := 0X END ExtractLastname; 8 X,8#Syntax10.Scn.FntGG BEGIN Strings.Cap(a); Strings.Cap(b); RETURN a = b END EqualString; 8 X8#Syntax10.Scn.Fnt VAR ret: LONGINT; str: ARRAY 1024 OF CHAR; BEGIN Out.Ln; ret := FormatMessage(fromSystem, 0, GetLastError(), ASH(default, 10) + neutral, S.ADR(str), LEN(str), 0); IF ret = 0 THEN Out.String("last error code: "); Out.Int(GetLastError(), 0) ELSE Out.String(str) END END Err; 8X:P8#Syntax10.Scn.Fnt VAR f: File; BEGIN NEW(f); f.next := NIL; COPY(name, f.name); COPY(dir, f.dir); f.touched := FALSE; f.info := info; RETURN f END NewFile; 8 X(]8#Syntax10.Scn.Fnt VAR g: File; BEGIN g := d.files; WHILE (g # NIL) & ~EqualString(f.name, g.name) DO g := g.next END ; RETURN g END ThisFile; 8 X08}Syntax10.Scn.Fntk8FoldElemsNewCSyntax10.Scn.FntSyntax10b.Scn.FntOut.String(f.name); FullPathName(to.dir, f.name, s); IF g # NIL THEN done := DeleteFile(S.ADR(s)) ELSE NEW(g) END ; g.handle := CreateFile(S.ADR(s), GenReadWrite, ShareRead, NULL, CreateNew, f.info.attr, NULL); IF g.handle = InvalidHandle THEN Err; HALT(55); RETURN END ; Syntax10i.Scn.Fnt8{8CSyntax10.Scn.FntSyntax10b.Scn.FntCFullPathName(f.dir, f.name, s); f.handle := CreateFile(S.ADR(s), GenRead, ShareRead, NULL, OpenExisting, {FileAttrNormal}, NULL); IF f.handle = InvalidHandle THEN Err; HALT(54); RETURN END ; REPEAT done := ReadFile(f.handle, S.ADR(buf), LEN(buf), nofRead, NULL); done := WriteFile(g.handle, S.ADR(buf), nofRead, nofWritten, NULL) UNTIL nofRead = 0; done := CloseHandle(f.handle); ASSERT(done, 92); done := SetFileTime(g.handle, S.ADR(f.info.creation), S.ADR(f.info.lastAccess), S.ADR(f.info.lastWrite)); ASSERT(done); done := CloseHandle(g.handle); ASSERT(done, 91); 8> VAR done: BOOLEAN; nofRead, nofWritten: LONGINT; s: ARRAY 260 OF CHAR; buf: ARRAY 4096 OF CHAR; BEGIN create and open empty g on to copy data Out.String(" saved"); Out.Ln; INC(savedFiles) END SaveFile; 8 X((8#Syntax10.Scn.Fnt VAR d: Directory; BEGIN NEW(d); d.next := NIL; d.files := NIL; d.dirs := NIL; COPY(dir, d.dir); d.name := ""; d.info.attr := GetFileAttributes(S.ADR(dir)); RETURN d END NewDir; 8 KO&J8CSyntax10.Scn.FntPSyntax10i.Scn.Fnt-t VAR done: BOOLEAN; path: ARRAY 260 OF CHAR; pos: INTEGER; BEGIN pos := 2; (* skip first delimiter, e.g. c:\Users\cs\Oberon *) REPEAT pos := Strings.Pos(Directories.delimiter, dir, pos + 1); IF pos = -1 THEN Strings.Extract(dir, 0, 260, path) ELSE Strings.Extract(dir, 0, pos, path) END ; done := CreateDir(S.ADR(path), NULL) UNTIL pos = -1 END CreateDirectory; 8 X58#Syntax10.Scn.Fnt VAR g: File; a, b: ARRAY 260 OF CHAR; found: BOOLEAN; BEGIN g := dir.dirs; found := FALSE; ExtractLastname(name, a); WHILE (g # NIL) & ~found DO ExtractLastname(g.dir, b); IF EqualString(a, b) THEN found := TRUE ELSE g := g.next END END ; RETURN g END ThisDir; 8 X*X8#Syntax10.Scn.Fnt CONST TAB = 9X; VAR f: File; i: INTEGER; BEGIN FOR i := 1 TO indent DO Out.Char(TAB) END ; Out.String("--- "); Out.String(d.dir); Out.Ln; f := d.files; WHILE f # NIL DO FOR i := 1 TO indent DO Out.Char(TAB) END ; Out.String(" "); Out.String(f.name); Out.Ln; f := f.next END ; f := d.dirs; WHILE f # NIL DO PrintDir(f(Directory), indent + 1); f := f.next END END PrintDir; 8 X&8#Syntax10.Scn.FntTT VAR f: File; d1: Directory; path: ARRAY 512 OF CHAR; b: Win32FindData; sh: LONGINT; info: FileInfo; found: BOOLEAN; BEGIN Out.Char(prompt); FullPathName(d.dir, "*.*", path); sh := FindFirstFile(S.ADR(path), S.ADR(b)); IF sh # InvalidHandle THEN REPEAT info.attr := b.attrib; info.len := b.sizeL; info.creation := b.creation; info.lastAccess := b.lastAcc; info.lastWrite := b.lastWrite; IF FileAttrDirectory IN info.attr THEN IF (b.name # ".") & (b.name # "..") THEN FullPathName(d.dir, b.name, path); d1 := NewDir(path); d1.next := d.dirs; d.dirs := d1 END ELSE f := NewFile(d.dir, b.name, info); f.next := d.files; d.files := f END ; found := FindNextFile(sh, S.ADR(b)) UNTIL ~found; FindClose(sh) END ; f := d.dirs; WHILE f # NIL DO FillDir(f(Directory), prompt); f := f.next END END FillDir; 8 X T86Syntax10.Scn.FntSyntax10b.Scn.Fnt78FoldElemsNewCSyntax10.Scn.FntSyntax10i.Scn.Fnt(* st1.year = st2.year *)858CSyntax10.Scn.FntSyntax10i.Scn.Fnt/5(* (st1.year = st2.year) & (st1.month = st2.month) *)83s8CSyntax10.Scn.FntSyntax10i.Scn.FntFK(* (st1.year = st2.year) & (st1.month = st2.month) & (st1.day = st2.day) *)83Z8CSyntax10.Scn.FntSyntax10i.Scn.Fnt_d(* (st1.year = st2.year) & (st1.month = st2.month) & (st1.day = st2.day) & (st1.hour = st2.hour) *)81D8CSyntax10.Scn.FntSyntax10i.Scn.Fnttz(* (st1.year = st2.year) & (st1.month = st2.month) & (st1.day = st2.day) & (st1.hour = st2.hour) & (st1.min = st2.min) *)8 8QSyntax10.Scn.FntSyntax10i.Scn.Fnt/[(* (st1.year = st2.year) & (st1.month = st2.month) & (st1.day = st2.day) & (st1.hour = st2.hour) & (st1.min = st2.min) & (st1.sec = st2.sec) *)8-w VAR st1, st2: SystemTime; done: BOOLEAN; BEGIN done := FileTimeToSystemTime(S.ADR(f.info.lastWrite), S.ADR(st1)); ASSERT(done); done := FileTimeToSystemTime(S.ADR(g.info.lastWrite), S.ADR(st2)); ASSERT(done); IF st1.year # st2.year THEN RETURN st1.year > st2.year ELSIF st1.month # st2.month THEN  RETURN st1.month > st2.month ELSIF st1.day # st2.day THEN  RETURN st1.day > st2.day ELSIF st1.hour # st2.hour THEN  RETURN st1.hour > st2.hour ELSIF st1.min # st2.min THEN  RETURN st1.min > st2.min ELSIF st1.sec # st2.sec THEN  RETURN st1.sec > st2.sec ELSE  RETURN st1.millisec > st2.millisec END END Newer; 8 X8CSyntax10.Scn.Fnt^Syntax10i.Scn.Fnt(8 VAR f, g: File; first: BOOLEAN; name: ARRAY 260 OF CHAR; BEGIN CreateDirectory(to.dir); (* ensure that destination directory exists *) f := from.files; first := TRUE; WHILE f # NIL DO g := ThisFile(to, f); IF (g = NIL) OR Newer(f, g) THEN IF first THEN Out.String("-- "); Out.String(from.dir); Out.Ln; first := FALSE END ; SaveFile(f, g, to) END ; g.touched := TRUE; f := f.next END ; f := from.dirs; WHILE f # NIL DO g := ThisDir(f.dir, to); IF g = NIL THEN ExtractLastname(f.dir, name); FullPathName(to.dir, name, name); CreateDirectory(name); g := NewDir(name); END ; SaveDir(f(Directory), g(Directory)); g.touched := TRUE; f := f.next END END SaveDir; 8 X8QSyntax10.Scn.FntJSyntax10i.Scn.Fnt  VAR f: File; first, done: BOOLEAN; fullName: ARRAY 512 OF CHAR; BEGIN (*delete redundant files in d*) f := d.files; first := TRUE; WHILE f # NIL DO IF ~f.touched THEN IF first THEN Out.String("-- "); Out.String(d.dir); Out.Ln; first := FALSE END ; FullPathName(d.dir, f.name, fullName); done := DeleteFile(S.ADR(fullName)); Out.String(f.name); Out.String(" deleted$") END ; f := f.next END ; f := d.dirs; WHILE f # NIL DO CleanupDir(f(Directory)); done := DeleteFile(S.ADR(f.dir)); IF done THEN (*was empty*) IF first THEN Out.String("-- "); Out.String(d.dir); Out.Ln; first := FALSE END ; Out.String(f.name); Out.String(" deleted$") END ; f := f.next END END CleanupDir; 8 XSyntax10b.Scn.Fnt 8#Syntax10.Scn.FntMM VAR path: ARRAY 260 OF CHAR; from, to: Directory; BEGIN In.Open; savedFiles := 0; REPEAT IF In.Next() = In.string THEN In.String(path) ELSE In.Name(path) END ; IF In.Done THEN from := NewDir(path); IF In.Next() = In.string THEN In.String(path) ELSE In.Name(path) END ; IF In.Done THEN to := NewDir(path); Out.String("Reading directories"); FillDir(from, "-"); FillDir(to, "+"); Out.Ln; (*PrintDir(from, 0); PrintDir(to, 0);*) SaveDir(from, to); CleanupDir(to) END END UNTIL ~In.Done; Out.F("$# files saved$", savedFiles) END WriteFiles; 8 X8CSyntax10.Scn.FntWSyntax10i.Scn.FntL VAR mod: LONGINT; BEGIN mod := Kernel.LoadLibrary("Kernel32"); Kernel.GetAdr(mod, "CreateFileA", S.VAL(LONGINT, CreateFile)); Kernel.GetAdr(mod, "DeleteFileA", S.VAL(LONGINT, DeleteFile)); Kernel.GetAdr(mod, "CloseHandle", S.VAL(LONGINT, CloseHandle)); Kernel.GetAdr(mod, "GetFileSize", S.VAL(LONGINT, GetFileSize)); Kernel.GetAdr(mod, "ReadFile", S.VAL(LONGINT, ReadFile)); Kernel.GetAdr(mod, "FindFirstFileA", S.VAL(LONGINT, FindFirstFile)); Kernel.GetAdr(mod, "FindNextFileA", S.VAL(LONGINT, FindNextFile)); Kernel.GetAdr(mod, "FindClose", S.VAL(LONGINT, FindClose)); Kernel.GetAdr(mod, "WriteFile", S.VAL(LONGINT, WriteFile)); Kernel.GetAdr(mod, "GetFileTime", S.VAL(LONGINT, GetFileTime)); Kernel.GetAdr(mod, "SetFileTime", S.VAL(LONGINT, SetFileTime)); Kernel.GetAdr(mod, "FileTimeToSystemTime", S.VAL(LONGINT, FileTimeToSystemTime)); Kernel.GetAdr(mod, "GetFileAttributesA", S.VAL(LONGINT, GetFileAttributes)); Kernel.GetAdr(mod, "CreateDirectoryA", S.VAL(LONGINT, CreateDir)); mod := Kernel.LoadLibrary("Kernel32"); Kernel.GetAdr(mod, "FormatMessageA", S.VAL(LONGINT, FormatMessage)); Kernel.GetAdr(mod, "GetLastError", S.VAL(LONGINT, GetLastError)) END Init; 8`_j(* This module contains two versions. Versions: - PowerMac - Windows To switch versions click on WINDOWS VERSION with the middle mouse button. *) Documentation MODULE Backup; (* HM, CS (Windows version)  *) IMPORT Kernel, Directories, Strings, In, Out, S := SYSTEM; CONST  TYPE FileTime = RECORD  SystemTime = RECORD  FileInfo = RECORD  File = POINTER TO FileDesc;  Directory = POINTER TO DirectoryDesc;  Win32FindData = RECORD  VAR  (*--- auxiliaries*) PROCEDURE FullPathName (path: ARRAY OF CHAR; name: ARRAY OF CHAR; VAR fullName: ARRAY OF CHAR);  PROCEDURE ExtractLastname (path: ARRAY OF CHAR; VAR name: ARRAY OF CHAR);  PROCEDURE EqualString (a, b: ARRAY OF CHAR): BOOLEAN;  PROCEDURE Err;  (*--- files*) PROCEDURE NewFile (dir, name: ARRAY OF CHAR; info: FileInfo): File;  PROCEDURE ThisFile (d: Directory; f: File): File;  PROCEDURE SaveFile (f: File; VAR g: File; to: Directory);  (*--- directories*) PROCEDURE NewDir (dir: ARRAY OF CHAR): Directory;  PROCEDURE CreateDirectory (dir: ARRAY OF CHAR);  PROCEDURE ThisDir (name: ARRAY OF CHAR; dir: Directory): File;  PROCEDURE PrintDir (d: Directory; indent: INTEGER);  PROCEDURE FillDir (d: Directory; prompt: CHAR);  PROCEDURE Newer (f, g: File): BOOLEAN; (* TRUE, iff f is newer than g *)  PROCEDURE SaveDir (from, to: Directory);  PROCEDURE CleanupDir (d: Directory);  PROCEDURE WriteFiles*;  PROCEDURE Init;  BEGIN Init END Backup.WriteFiles c:\Users\cs\Oberon.NT c:\Temp\Oberon ~ System.Directory c:\Users\cs\Oberon.NT\*/ds System.Directory c:\Temp\Oberon\*/ds System.State Backup