_STRUCTURED PROGRAMMING_

by Kent Porter

[LISTING ONE]


   1| MODULE Memory;
   2| 
   3| (* Reports amount of memory available, excluding this program       *)
   4| (* JPI TopSpeed Modula-2                                            *)
   5| (* K. Porter, DDJ, January '89                                      *)
   6| 
   7| IMPORT SYSTEM, IO, Lib;
   8| 
   9| VAR   MainMem, MemUsable      : LONGCARD;
  10|       MemSize [0040H : 0013H] : CARDINAL;
  11| (* ---------------------------------------------------------------- *)
  12| 
  13| PROCEDURE PSP() : LONGCARD;           (* Return byte address of PSP *)
  14| 
  15| VAR   Reg : SYSTEM.Registers;
  16| 
  17| BEGIN
  18|   Reg.AH := 51H;  (* Undocumented: same as 62H but works in DOS 2.n *)
  19|   Lib.Intr (Reg, 21H);
  20|   RETURN (LONGCARD (Reg.BX) * 16);
  21| END PSP;
  22| 
  23| (* ---------------------------------------------------------------- *)
  24| 
  25| BEGIN
  26|   MainMem := LONGCARD (MemSize) * 1024;    (* Total memory in bytes *)
  27|   MemUsable := MainMem - PSP();
  28|   IO.WrStr ('Available memory is ');
  29|   IO.WrLngCard (MemUsable, 1);
  30|   IO.WrStr (' bytes');
  31|   IO.WrLn;
  32| END Memory.


[LISTING TWO]

   1| MODULE sd;
   2| 
   3| (* Lists all subdirectories in the current directory *)
   4| (* JPI TopSpeed Modula-2                             *)
   5| (* K. Porter, DDJ, January '89                       *)
   6| 
   7| IMPORT FIO, IO;
   8| 
   9| VAR    F     : FIO.DirEntry;
  10|        Found : BOOLEAN;
  11|        Count : CARDINAL;
  12| 
  13| BEGIN
  14|   Count := 0;
  15|   Found := FIO.ReadFirstEntry ("*.*",
  16|                FIO.FileAttr {FIO.directory}, F);
  17|   WHILE Found DO
  18|     IF FIO.directory IN F.attr THEN
  19|       IF F.Name[0] # '.' THEN
  20|         IO.WrStr (F.Name); IO.WrLn;
  21|         INC (Count);
  22|       END;
  23|     END;
  24|     Found := FIO.ReadNextEntry (F);
  25|   END;
  26|   IO.WrCard (Count, 1);
  27|   IO.WrStr (' directories found');
  28|   IO.WrLn;
  29| END sd.


[LISTING THREE]

   1| MODULE Where;
   2| 
   3| (* Searches directory structure from the root, listing all occur-   *)
   4| (*   rences of a filename matching the search argument              *)
   5| (* JPI TopSpeed Modula-2                                            *)
   6| (* K. Porter, DDJ, January '89                                      *)
   7| 
   8| IMPORT FIO, IO, SYSTEM, Lib, Str;
   9| FROM FIO IMPORT FileAttr, readonly, hidden, system, directory,
  10|                 archive;
  11| 
  12| TYPE  string = ARRAY [0..79] OF CHAR;
  13| 
  14| CONST DefaultDrive = 0;
  15|       Backspace = CHR(8);
  16| 
  17| VAR   arg, curdir, xfer  : string;
  18|       DriveName          : ARRAY [0..3] OF CHAR;
  19|       count, p, s, d     : CARDINAL;
  20|       curdrive, newdrive : SHORTCARD;
  21|       cx [40H:50H]       : SHORTCARD;        (* ROM BIOS cursor col *)
  22| 
  23| (* ---------------------------------------------------------------- *)
  24| 
  25| PROCEDURE ClrSol;             (* Clear from cursor to start of line *)
  26| 
  27| BEGIN
  28|   WHILE cx # 0 DO
  29|     IO.WrChar (Backspace);
  30|     IO.WrChar (' ');
  31|     IO.WrChar (Backspace);
  32|   END;
  33| END ClrSol;
  34| 
  35| (* ---------------------------------------------------------------- *)
  36| 
  37| PROCEDURE SearchDir (Path : ARRAY OF CHAR);
  38|                               (* Recursive directory search routine *)
  39| 
  40| VAR  F         : FIO.DirEntry;
  41|      WholePath : string;
  42|      Found     : BOOLEAN;
  43| 
  44| BEGIN
  45|   FIO.ChDir (Path);                                (* Set directory *)
  46|   FIO.GetDir (DefaultDrive, WholePath);        (* Get full pathname *)
  47|   Str.Concat (WholePath, DriveName, WholePath);        (* Add drive *)
  48|   ClrSol;                                 (* Clear to start of line *)
  49|   IO.WrStr (WholePath);                           (* List directory *)
  50| 
  51|   (* Search for filename matches in this directory *)
  52|   Found := FIO.ReadFirstEntry (arg, FileAttr {readonly, hidden,
  53|                                system, directory, archive}, F);
  54|   WHILE Found DO
  55|     IF Str.Length (WholePath) > 3 THEN IO.WrChar ('\') END;
  56|     IO.WrStr (F.Name);
  57|     IF directory IN F.attr THEN
  58|       IO.WrStr (" <DIR>");
  59|     END;
  60|     IO.WrLn;                                            (* New line *)
  61|     IO.WrStr (WholePath);
  62|     INC (count);                                (* Count occurrence *)
  63|     Found := FIO.ReadNextEntry (F);               (* Get next match *)
  64|   END;
  65| 
  66|   (* Now recursively search any subs under this directory *)
  67|   Found := FIO.ReadFirstEntry ("*.*", FileAttr {directory}, F);
  68|   WHILE Found DO
  69|     IF (directory IN F.attr) AND (F.Name[0] # '.') THEN
  70|       SearchDir (F.Name);                         (* Recursive call *)
  71|       FIO.ChDir (WholePath);           (* Restore dir to this level *)
  72|     END;
  73|     Found := FIO.ReadNextEntry (F);                  (* Do next sub *)
  74|   END;
  75| END SearchDir;
  76| 
  77| (* ---------------------------------------------------------------- *)
  78| 
  79| PROCEDURE GetDrive() : SHORTCARD;     (* Get currently active drive *)
  80| 
  81| VAR   Reg : SYSTEM.Registers;
  82| 
  83| BEGIN
  84|   Reg.AH := 19H;
  85|   Lib.Intr (Reg, 21H);
  86|   RETURN (Reg.AL);
  87| END GetDrive;
  88| 
  89| (* ---------------------------------------------------------------- *)
  90| 
  91| PROCEDURE SetDrive (Drive : SHORTCARD);        (* Set default drive *)
  92| 
  93| VAR   Reg : SYSTEM.Registers;
  94| 
  95| BEGIN
  96|   Reg.AH := 0EH;
  97|   Reg.DL := Drive;
  98|   Lib.Intr (Reg, 21H);
  99| END SetDrive;
 100| 
 101| (* ---------------------------------------------------------------- *)
 102| 
 103| BEGIN   (* Main body of WHERE *)
 104| 
 105|   (* Initialize *)
 106|   FIO.GetDir (0, curdir);                  (* Remember where we are *)
 107|   curdrive := GetDrive();                              (* and drive *)
 108|   count := 0;
 109|   FOR p := 0 TO 3 DO DriveName[p] := CHR(0) END;
 110| 
 111|   (* Get the name to search for *)
 112|   IF Lib.ParamCount() > 0 THEN
 113|     Lib.ParamStr (arg, 1);
 114|   ELSE
 115|     IO.WrStr ("Filename? ");
 116|     IO.RdStr (arg);
 117|   END;
 118| 
 119|   (* Select another drive, strip out designator if necessary *)
 120|   IF arg[1] = ':' THEN
 121|     DriveName[0] := CAP (arg[0]);
 122|     newdrive := SHORTCARD (ORD (CAP (arg[0])) - ORD ('A'));
 123|     SetDrive (newdrive);                           (* Set new drive *)
 124|     IF arg[2] = '\' THEN s := 3 ELSE s := 2 END;
 125|     d := 0;
 126|     FOR p := s TO Str.Length (arg) DO (* Strip out drive designator *)
 127|       xfer[d] := arg[p];
 128|       INC (d);
 129|       xfer[d] := CHR (0);
 130|     END;
 131|     Str.Copy (arg, xfer);                       (* Copy back to arg *)
 132|   END;
 133| 
 134|   (* Build name of target drive *)
 135|   IF DriveName[0] = CHR(0) THEN
 136|     DriveName[0] := CHR (curdrive + 65)
 137|   END;
 138|   Str.Concat (DriveName, DriveName, ":\");
 139| 
 140|   (* Add wildcard prefix/suffix as necessary *)
 141|   IF arg[0] = '.' THEN
 142|     Str.Concat (arg, "*", arg);         (* Stick in wildcard prefix *)
 143|   END;
 144|   IF Str.Pos (arg, ".") = MAX (CARDINAL) THEN
 145|     Str.Concat (arg, arg, ".*");          (* Append wildcard suffix *)
 146|   END;
 147| 
 148|   (* Begin search at root *)
 149|   SearchDir ("\");
 150| 
 151|   (* Report matches found *)
 152|   ClrSol;
 153|   IO.WrCard (count, 1);
 154|   IO.WrStr (" matches found");
 155|   IO.WrLn;
 156| 
 157|   (* Restore user's original environment *)
 158|   SetDrive (curdrive);
 159|   FIO.ChDir (curdir);
 160| END Where.
