home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxhll.zip / $.CMD next >
OS/2 REXX Batch file  |  1994-03-04  |  58KB  |  1,888 lines

  1. /**
  2. *** ╔════════════════════════════════════════════════════════════════════╗
  3. *** ║                                                                    ║
  4. *** ║  $.CMD - version 3.4.1                                             ║
  5. *** ║                                                                    ║
  6. *** ║ ────────────────────────────────────────────────────────────────── ║
  7. *** ║                                                                    ║
  8. *** ║ This is a collection of small execs put into one place to keep the ║
  9. *** ║ directory clutter down a little bit.  It also allows for local-    ║
  10. *** ║ ization of global variables and the reuse of general purpose       ║
  11. *** ║ routines.                                                          ║
  12. *** ║                                                                    ║
  13. *** ║ Many of the routines listed here are intended to be run while      ║
  14. *** ║ there is no other activities on the machine.  As such, these       ║
  15. *** ║ routines also serve as a free suppliment to the product Chron      ║
  16. *** ║ currently marketed by Hilbert Computing.                           ║
  17. *** ║                                                                    ║
  18. *** ║ This can also serve as a working example of several REXX program-  ║
  19. *** ║ ming techniques.                                                   ║
  20. *** ║                                                                    ║
  21. *** ║ ────────────────────────────────────────────────────────────────── ║
  22. *** ║                                                                    ║
  23. *** ║ This code is provided on an as-is basis.  There is no warranty     ║
  24. *** ║ expressed or implied in the code.  There is no official support    ║
  25. *** ║ for this code.  However, you are welcome to contact Hilbert        ║
  26. *** ║ Computing for questions or comments on the code.  If you make your ║
  27. *** ║ own changes to the code and wish to upload the modified code to    ║
  28. *** ║ a public forum, please note your modifications to the code.        ║
  29. *** ║                                                                    ║
  30. *** ║ Many of the routines require the REXX suppliment DLLs found in     ║
  31. *** ║ OS/2 v2.0 and later.                                               ║
  32. *** ║                                                                    ║
  33. *** ║ I can be reached at:                                               ║
  34. *** ║                                                                    ║
  35. *** ║              Gary Murphy, Sr. Programmer                           ║
  36. *** ║              Hilbert Computing                                     ║
  37. *** ║              1022 N. Cooper                                        ║
  38. *** ║              Olathe, KS 66061                                      ║
  39. *** ║                                                                    ║
  40. *** ║              BBS/Fax.. (913) 829-2450 8N1 14.4Kbps                 ║
  41. *** ║              CIS...... [73457,365]                                 ║
  42. *** ║                                                                    ║
  43. *** ║ ────────────────────────────────────────────────────────────────── ║
  44. *** ║                                                                    ║
  45. *** ║            Copyright (c) 1992-1994  Hilbert Computing              ║
  46. *** ║                                                                    ║
  47. *** ╚════════════════════════════════════════════════════════════════════╝
  48. **/
  49.  
  50. call LoadFunctions
  51.  
  52. /* The configuration information is kept in an INI file.  Make sure this */
  53. /* file exists.                                                          */
  54.  
  55. IniFile = GetIniFile()
  56.  
  57. /* Parse the command */
  58.  
  59. parse arg cmd parms
  60. cmd = translate(cmd)  /* Convert to uppercase */
  61.  
  62. /* Save the current directory */
  63.  
  64. Dir.Current = directory()
  65. select
  66.    when abbrev('BACKUP'     ,cmd,  3) then call Backup        parms
  67.    when abbrev('CHANGED'    ,cmd,  3) then call Changed       parms
  68.    when abbrev('CHECK'      ,cmd,  3) then call Check         parms
  69.    when abbrev('CHK'        ,cmd,  3) then call Check         parms
  70.    when abbrev('COPYSAFE'   ,cmd,  4) then call CopySafe      parms
  71.    when abbrev('ENVIRONMENT',cmd,  3) then call Environment   parms
  72.    when abbrev('MAXIMUS'    ,cmd,  3) then call Maximus       parms
  73.    when abbrev('MIGRATE'    ,cmd,  3) then call Migrate       parms
  74.    when abbrev('PROFILE'    ,cmd,  2) then call Profile       parms
  75.    when abbrev('PSTAT'      ,cmd,  2) then call PStat         parms
  76.    when abbrev('RECURSE'    ,cmd,  3) then call Recurse       parms
  77.    when abbrev('RESET'      ,cmd,  3) then call Reset         parms
  78.    when abbrev('SPACE'      ,cmd,  2) then call Space         parms
  79.    when abbrev('ZIP'        ,cmd,  1) then call Zip           parms
  80.    otherwise
  81.       say "Command '"cmd"' not recognized"
  82. end /* Select */
  83.  
  84. /* Return to the starting directory */
  85.  
  86. Dir.Current = directory(Dir.Current)
  87. exit
  88.  
  89.  
  90. /**
  91. *** ┌──────────────────────────────────────────────────────────────────────┐
  92. *** │                          Backup Subroutines                          │
  93. *** └──────────────────────────────────────────────────────────────────────┘
  94. **/
  95.  
  96.  
  97. Backup: procedure expose IniFile
  98.    parse arg cmd parms
  99.    parse upper var cmd cmd
  100.  
  101.    select
  102.       when abbrev('CHRON'  ,cmd,  5) then call BackupChron   parms
  103.       when abbrev('CONFIG' ,cmd,  4) then call BackupConfig  parms
  104.       otherwise
  105.          say "Subcommand (BACKUP): '"cmd"' not recognized"
  106.    end /* Select */
  107.    return
  108.  
  109.  
  110. BackupConfig: procedure expose IniFile
  111.    /**
  112.    ***  This will backup multiple generations of the CONFIG.SYS file.  It
  113.    ***  will only back it up if it has changed (i.e. the archive bit is on)
  114.    **/
  115.  
  116.  
  117.    Boot = GetIni('Directory','Boot','c:\')
  118.    Backup = GetIni('Directory','Backup','d:\backup')
  119.    call SysFileTree Boot'CONFIG.SYS', 'Found', 'F', '+****', '-****'
  120.    if Found.0 then
  121.       do
  122.       FileExt = right(date("days"),3,"0")  /* Julian date padded w/ 0's */
  123.       'copy' Boot'CONFIG.SYS' Backup'\CONFIG.'FileExt
  124.       '@attrib -A' Boot'CONFIG.SYS'
  125.       end
  126.  
  127.    /* Keep the number of config backups to a reasonable number */
  128.  
  129.    DeleteCount = DeleteOldFiles(Backup'\CONFIG.*', 10)
  130.    return;
  131.  
  132.  
  133. BackupChron: procedure expose IniFile
  134.    /**
  135.    ***  This will backup the CHRON.DAT file.  If this is a daily backup,
  136.    ***  the file is created with an extension equal to the first three
  137.    ***  letters of the day of the week.  If this is a weekly backup, the
  138.    ***  file is created with an extension of ".BKW".  Otherwise, the
  139.    ***  file is ".SAV"
  140.    **/
  141.  
  142.    arg parms
  143.  
  144.    select
  145.       when abbrev('DAILY' ,parms, 1) then
  146.          Destination = 'chron.'left(date('W'),3)
  147.       when abbrev('WEEKLY',parms, 1) then
  148.          Destination = 'chron.bkw'
  149.       otherwise
  150.          Destination = 'chron.sav'
  151.    end /* select */
  152.  
  153.    ChronDir  = GetIni('Directory','Chron','')
  154.    BackupDir = GetIni('Directory','Backup','')
  155.  
  156.    'copy' ChronDir'\chron.dat' BackupDir'\'Destination
  157.    return;
  158.  
  159. /**
  160. *** ┌──────────────────────────────────────────────────────────────────────┐
  161. *** │ CopySafe Subroutines                                                 │
  162. *** └──────────────────────────────────────────────────────────────────────┘
  163. **/
  164.  
  165. CopySafe: procedure expose IniFile
  166.    /**
  167.    ***  This will check the time/date stamps on the files before copying
  168.    ***  them.
  169.    **/
  170.  
  171.    parse arg Options
  172.  
  173.    /* Parse the command line parameters */
  174.  
  175.    Opt.Flag.P = '-'     /* Don't prompt before copying */
  176.    Opt.Flag.C = '-'     /* Don't compare before copying */
  177.    Opt.Flag.V = '-'     /* Default to non-verbose output */
  178.  
  179.    call ParseOptions Options
  180.  
  181.    if Opt.Flag.SYNTAX = '+' then
  182.       call Syntax
  183.  
  184.    if Opt.Flag.C = '+' then
  185.       Opt.Flag.P = '+'
  186.  
  187.    /* The destination must be a directory */
  188.  
  189.    DestDir = QualifiedDirectory(Opt.Parm.2)
  190.    if DestDir = '' then
  191.       do
  192.       say 'The destination must be a directory.'
  193.       end
  194.  
  195.    if Opt.Flag.C = '+' then
  196.       contrast = GetIni('Program','Contrast','contrast.exe')
  197.  
  198.    /* Generate the list of file to potentially copy */
  199.  
  200.    CopyCount = 0
  201.    call SysFileTree Opt.Parm.1,'File','f'
  202.    do i = 1 to File.0
  203.       code = CopyFile(File.i, DestDir)
  204.    end
  205.    say "       " CopyCount "file(s) copied."
  206.    exit
  207.  
  208.  
  209. CopyFile: procedure expose Opt.  CopyCount contrast
  210.    /**
  211.    ***  Copy the file to the destination if the dest is older than the
  212.    ***  source.  Otherwise, compare or prompt as appropriate.
  213.    **/
  214.  
  215.    parse arg fdate ftime . . SourceFile, DestDir
  216.  
  217.    DestDir = strip(DestDir,'Trailing','\')
  218.    DestFile = DestDir'\'filespec('Name',SourceFile)
  219.    SourceFile = strip(SourceFile,'Both')
  220.  
  221.    /* See if the file exists */
  222.  
  223.    call SysFileTree DestFile,'File','F'
  224.    select
  225.       when File.0 = 0 then /* No file */
  226.          CopyState = 'Yes'
  227.       when File.0 = 1 then /* Found */
  228.          do
  229.          parse var File.1 dfdate dftime .
  230.  
  231.          TimeStamp = CompareFileTimes(dfdate dftime,fdate ftime)
  232.  
  233.          select
  234.             when TimeStamp = '<' then
  235.                CopyState = 'Yes'
  236.             when TimeStamp = '=' then
  237.                CopyState = 'No'
  238.             otherwise
  239.                CopyState = 'Conditional'
  240.          end /* select */
  241.          end
  242.       otherwise
  243.          return 4
  244.    end /* select */
  245.  
  246.  
  247.    if CopyState = 'Conditional' then
  248.       do
  249.  
  250.       /* Do any necessary displays and prompting */
  251.  
  252.       if Opt.Flag.C = '+' then
  253.          '@'contrast SourceFile DestFile
  254.  
  255.       if Opt.Flag.P = '+' then
  256.          do
  257.          say 'Copy: ('left(fdate ftime, 16)')' SourceFile
  258.          call charout ,'To:   ('left(dfdate dftime, 16)')' DestFile'? '
  259.          CopyState = GetPromptForCopy()
  260.          end /* Prompt */
  261.       end /* conditional */
  262.  
  263.    if CopyState = 'Yes' then
  264.       do
  265.       if Opt.Flag.V = '+' then
  266.          say 'Copying "'SourceFile'" to "'DestFile'"...'
  267.       else
  268.          say SourceFile
  269.       '@COPY' SourceFile DestFile '> nul'
  270.       CopyCount = CopyCount + 1
  271.       end
  272.    else
  273.       if Opt.Flag.V = '+' then
  274.          say 'Skipping "'SourceFile'"...'
  275.    return 0
  276.  
  277. GetPromptForCopy: procedure
  278.    /**
  279.    ***  This will get the response from the prompt for copy
  280.    **/
  281.  
  282.    Key = SysGetKey('NOECHO')
  283.    Key = translate(Key)
  284.    if Key = 'Y' then
  285.       do
  286.       /* Verify */
  287.  
  288.       call charout ,"Sure?"
  289.       Key = SysGetKey('NOECHO')
  290.       Key = translate(Key)
  291.       if Key = 'Y' then
  292.          CopyState = 'Yes'
  293.       else
  294.          CopyState = 'No'
  295.       end
  296.    else
  297.       CopyState = 'No'
  298.    say
  299.    return CopyState
  300.  
  301.  
  302. /**
  303. *** ┌──────────────────────────────────────────────────────────────────────┐
  304. *** │ Reset Subroutines                                                    │
  305. *** └──────────────────────────────────────────────────────────────────────┘
  306. **/
  307.  
  308. Reset: procedure expose IniFile
  309.    /**
  310.    ***  The PROFILE command will configure an OS/2 command prompt session
  311.    **/
  312.  
  313.    parse arg cmd parms
  314.    cmd = translate(cmd)
  315.  
  316.    select
  317.       when abbrev('ENVIRONMENT',cmd, 3)  then call ResetEnvironment  parms
  318.       when abbrev('SET',        cmd, 3)  then call ResetEnvironment  parms
  319.       otherwise
  320.          say "Subcommand (RESET): '"cmd"' not recognized"
  321.    end /* Select */
  322.    return
  323.  
  324.  
  325. ResetEnvironment: procedure expose IniFile
  326.    /**
  327.    ***  This will reset the enviroment variables back to the values in the
  328.    ***  CONFIG.SYS
  329.    **/
  330.  
  331.    Grep = GetIni('Program','Grep','grep.exe')
  332.    Boot = GetIni('Directory','Boot','c:\')
  333.  
  334.    '@'Grep '-i "^set .*\="' Boot'config.sys | rxqueue'
  335.  
  336.    say 'Resetting' queued() 'environment variables...'
  337.  
  338.    do i = 1 to queued()
  339.       parse pull SetStatement
  340.       '@'SetStatement
  341.    end
  342.    say 'Done.'
  343.    return
  344.  
  345. /**
  346. *** ┌──────────────────────────────────────────────────────────────────────┐
  347. *** │ Profile Subroutines                                                  │
  348. *** └──────────────────────────────────────────────────────────────────────┘
  349. **/
  350.  
  351. Profile: procedure expose IniFile
  352.    /**
  353.    ***  The PROFILE command will configure an OS/2 command prompt session
  354.    **/
  355.  
  356.    parse arg cmd parms
  357.    parse upper var cmd cmd
  358.  
  359.    /* Change the number of lines on the screen */
  360.  
  361.    mode = GetIni('Global','Mode','co80,25')
  362.    '@mode' mode
  363.    call SysCls
  364.    say 'Setting environment variables...'
  365.  
  366.    select
  367.       when abbrev('AWK'    ,cmd, 1)      then call ProfileAWK        parms
  368.       when abbrev('IBMC'   ,cmd, 3)      then call ProfileIBM        parms
  369.       when abbrev('IBMCPP' ,cmd, 5)      then call ProfileIBM        parms
  370.       when abbrev('CPP'    ,cmd, 5)      then call ProfileIBM        parms
  371.       when abbrev('CSET'   ,cmd, 5)      then call ProfileIBM        parms
  372.       when abbrev('IPF'    ,cmd, 3)      then call ProfileIPF        parms
  373.       when abbrev('MSFTC'  ,cmd, 2)      then call ProfileMS         parms
  374.       when abbrev('MSC'    ,cmd, 2)      then call ProfileMS         parms
  375.       when abbrev('REXX'   ,cmd, 2)      then call ProfileRexx       parms
  376.       when abbrev('CMD'    ,cmd, 2)      then call ProfileRexx       parms
  377.       otherwise
  378.          say "Subcommand (PROFILE): '"cmd"' not recognized"
  379.    end /* Select */
  380.    return
  381.  
  382.  
  383. ProfileIBM: procedure expose IniFile
  384.    /**
  385.    ***  This will configure an OS/2 session for using the IBM C Set/2
  386.    ***  compiler
  387.    **/
  388.  
  389.    parse arg project
  390.  
  391.    /* Get profile information */
  392.  
  393.    Toolkit = GetIni('Directory','2.x Toolkit','')
  394.    CBase   = GetIni('Directory','IBM C Base','')
  395.  
  396.    Include = Toolkit"\cplus\os2h;"Toolkit"\c\os2h;"CBase"\include;"CBase"\ibmclass"
  397.  
  398.    Env = value("PROJECT"      ,project                         ,"OS2ENVIRONMENT")
  399.    Env = value("PCALLX"       ,project".c"                     ,"OS2ENVIRONMENT")
  400.    Env = value("PCALLXO"      ,project".cpp"                   ,"OS2ENVIRONMENT")
  401.    Env = value("INCLUDE"      ,Include                         ,"OS2ENVIRONMENT")
  402.    Env = value("INCLUDETOOLS" ,Toolkit"\c\os2h"                ,"OS2ENVIRONMENT")
  403.    Env = value("INCLUDEC"     ,CBase"\include;"CBase"\ibmclass","OS2ENVIRONMENT")
  404.    Env = value("LIB"          ,Toolkit"\os2lib;"CBase"\lib"    ,"OS2ENVIRONMENT")
  405.    Env = value("IPFC"         ,Toolkit"\ipfc"                  ,"OS2ENVIRONMENT")
  406.  
  407.    /* Re-build the path with the executables for this compiler and toolkit */
  408.    /* in front.                                                            */
  409.  
  410.    EnvVal  = value("PATH", , "OS2ENVIRONMENT")
  411.    EnvPath = value("PATH", CBase"\bin;"Toolkit"\os2bin;"EnvVal,  "OS2ENVIRONMENT")
  412.  
  413.    /* Do the same to the HELP environment variable */
  414.  
  415.    EnvVal  = value("HELP", , "OS2ENVIRONMENT")
  416.    EnvHelp = value("HELP", Toolkit"\os2help;"EnvVal,  "OS2ENVIRONMENT")
  417.  
  418.    /* Do the same to the BOOKSHELF environment variable */
  419.  
  420.    EnvVal  = value("BOOKSHELF", , "OS2ENVIRONMENT")
  421.    EnvBook = value("BOOKSHELF", CBase"\book;"Toolkit"\book;"EnvVal,  "OS2ENVIRONMENT")
  422.    return
  423.  
  424.  
  425. ProfileMS: procedure expose IniFile
  426.    /**
  427.    ***  This will configure an OS/2 session for using MSC and the OS/2 v1.3
  428.    ***  Toolkit
  429.    **/
  430.  
  431.    parse arg project
  432.  
  433.    /* Get profile information */
  434.  
  435.    Toolkit = GetIni('Directory','1.3 Toolkit','')
  436.    CBase   = GetIni('Directory','IBM C Base','')
  437.  
  438.    Env = value("PROJECT",      project,                            "OS2ENVIRONMENT")
  439.    Env = value("PCALLX",       project".c" ,                       "OS2ENVIRONMENT")
  440.    Env = value("INCLUDE",      Toolkit"\c\include;"CBase"\include","OS2ENVIRONMENT")
  441.    Env = value("INCLUDETOOLS", Toolkit"\c\include",                "OS2ENVIRONMENT")
  442.    Env = value("INCLUDEC",     CBase"\include",                    "OS2ENVIRONMENT")
  443.    Env = value("LIB",          Toolkit"\lib;"CBase"\lib" ,         "OS2ENVIRONMENT")
  444.    Env = value("IPFC",         Toolkit"\ipfc" ,                    "OS2ENVIRONMENT")
  445.  
  446.    EnvPath = value("PATH", , "OS2ENVIRONMENT")
  447.    EnvPath = value("PATH", CBase"\bin;"Toolkit"\bin;"EnvPath, "OS2ENVIRONMENT")
  448.  
  449.    /* Do the same to the HELP environment variable */
  450.  
  451.    EnvHelp = value("HELP", , "OS2ENVIRONMENT")
  452.    EnvHelp = value("HELP", Toolkit"\os2help;"EnvHelp, "OS2ENVIRONMENT")
  453.    return
  454.  
  455.  
  456. ProfileRexx: procedure expose IniFile
  457.    /**
  458.    ***  This will configure an OS/2 session for working with REXX
  459.    **/
  460.  
  461.    parse arg project
  462.  
  463.    RexxDir = GetIni('Directory','REXX','')
  464.  
  465.    Env = value("MMAKE.OPT", "NOEDIT QUIET",  "OS2ENVIRONMENT")
  466.    Env = value("INCLUDE", RexxDir"\Include", "OS2ENVIRONMENT")
  467.    Env = value("PROJECT", project,           "OS2ENVIRONMENT")
  468.    Env = value("PCALLX",  project".rex",     "OS2ENVIRONMENT")
  469.    return
  470.  
  471.  
  472.  
  473. ProfileAWK: procedure expose IniFile
  474.    /**
  475.    ***  This will configure an OS/2 session for AWK development
  476.    **/
  477.  
  478.    parse arg project
  479.  
  480.    Env = value("PROJECT", project, "OS2ENVIRONMENT")
  481.    Env = value("PCALLX", project".awk" , "OS2ENVIRONMENT")
  482.    return
  483.  
  484.  
  485. ProfileIPF: procedure expose IniFile
  486.    /**
  487.    ***  This will configure an OS/2 session for IPF (View Books) development
  488.    **/
  489.  
  490.    parse arg project
  491.  
  492.    Include = GetIni('Directory','IPF Include','')
  493.  
  494.    Env = value("INCLUDE", Include,"OS2ENVIRONMENT")
  495.    Env = value("PROJECT", project,       "OS2ENVIRONMENT")
  496.    Env = value("PCALLX", project".ipf" , "OS2ENVIRONMENT")
  497.    return
  498.  
  499.  
  500. /**
  501. *** ┌──────────────────────────────────────────────────────────────────────┐
  502. *** │                            Zip Subroutines                           │
  503. *** └──────────────────────────────────────────────────────────────────────┘
  504. **/
  505.  
  506. Zip: procedure expose IniFile
  507.    /**
  508.    ***  This will call a compression program to create a package in
  509.    ***  the correct directory.  It looks for a zip list file of with an
  510.    ***  extension of ".ZPL"
  511.    **/
  512.  
  513.    parse arg ZipFile .
  514.  
  515.    /* If there wasn't a zip file passed, use the project environment  */
  516.    /* for the name.                                                   */
  517.  
  518.    if ZipFile = '' then
  519.       do
  520.       ZipFile = value("PROJECT", , "OS2ENVIRONMENT")
  521.       if ZipFile = '' then
  522.          do
  523.          say "Project environment variable not set."
  524.          return
  525.          end
  526.       end
  527.  
  528.    TempDir = GetIni('Directory','Temp','')
  529.    Zip     = GetIni('Program','Zip','')
  530.  
  531.    /* Make a copy of the existing ZIP file if there is one */
  532.  
  533.    ZipDest = 'archive\'ZipFile'.ZIP'
  534.  
  535.    if Exists(ZipDest) then
  536.       do
  537.       '@copy' ZipDest TempDir
  538.       '@del'  ZipDest
  539.       end
  540.  
  541.    '@'Zip '-o@' ZipDest '< archive\'ZipFile'.zpl'
  542.    return
  543.  
  544. /**
  545. *** ┌──────────────────────────────────────────────────────────────────────┐
  546. *** │                         Recurse Subroutines                          │
  547. *** └──────────────────────────────────────────────────────────────────────┘
  548. **/
  549.  
  550. Recurse: procedure expose IniFile
  551.    /**
  552.    ***  This will execute the command on each directory starting with
  553.    ***  the first
  554.    **/
  555.  
  556.    parse arg command
  557.  
  558.    call RecurseDirectory ".", command
  559.    return
  560.  
  561.  
  562. RecurseDirectory: procedure expose IniFile
  563.    /**
  564.    ***  This will execute the command against this direct and all children
  565.    **/
  566.  
  567.    parse arg dir, command
  568.  
  569.    old = directory(dir)
  570.    say left("---" directory() copies('-',79), 79)
  571.    '@'command
  572.    call SysFileTree '.', 'Current', 'DO'
  573.    do i = 1 to Current.0
  574.       call RecurseDirectory Current.i, command
  575.    end
  576.    return 0
  577.  
  578. /**
  579. *** ┌──────────────────────────────────────────────────────────────────────┐
  580. *** │                          Space Subroutines                           │
  581. *** └──────────────────────────────────────────────────────────────────────┘
  582. **/
  583.  
  584. Space: procedure expose IniFile
  585.    /**
  586.    ***  This will recurse through all the specified drives and generate
  587.    ***  a disk utilization report on the space used by directory.
  588.    **/
  589.  
  590.    arg DisplayLevel DriveList
  591.  
  592.    Report.  = ''
  593.    Report.0 = 0
  594.  
  595.    /* Give defaults for missing parameters */
  596.  
  597.    if DisplayLevel = ''  then DisplayLevel = 32768
  598.    if DisplayLevel = '*' then DisplayLevel = 32768
  599.    if DisplayLevel = '.' then DisplayLevel = 32768
  600.  
  601.    if DriveList = '' then DriveList = SysDriveMap('C:', 'LOCAL')
  602.  
  603.  
  604.    do i = 1 to words(DriveList)
  605.       Drive = word(DriveList, i)
  606.       BytesDrive = SpaceDirectory(Drive'\*.*', 0, DisplayLevel)
  607.    end
  608.  
  609.    /* Get the INI values */
  610.  
  611.    TempFile = GetIni('File','Temp Space','c:\temp.1')
  612.    Editor   = GetIni('Program','Editor','e.exe')
  613.  
  614.    /* Erase the old and open a new file */
  615.  
  616.    '@erase' TempFile '> nul'
  617.    ReportFile = Open(TempFile 'WRITE')
  618.  
  619.    /* Write the headers */
  620.  
  621.    call lineout ReportFile, center("File", 10) center("w/ Child", 12) center("Directory", 54)
  622.    call lineout ReportFile, copies('-', 10)    copies("-", 12)        copies("-", 54)
  623.  
  624.    /* Write the space utilization report */
  625.  
  626.    do i = Report.0 to 1 by -1
  627.       call lineout ReportFile, Report.i
  628.    end
  629.    ReportFile = Close(ReportFile)
  630.  
  631.    /* Start the editor on the report file */
  632.  
  633.    '@'Editor TempFile
  634.    return
  635.  
  636.  
  637. SpaceDirectory: procedure expose Report.
  638.    /**
  639.    ***  This will generate a space utilization report for a given drive
  640.    **/
  641.  
  642.    arg Directory, Level, DisplayLevel
  643.  
  644.    /* Sum the size of all files in this directory */
  645.  
  646.    call SysFileTree Directory, 'Current', 'F'
  647.  
  648.    BytesDir = 0
  649.    do i = 1 to Current.0
  650.       parse var Current.i . . BytesFile . FileName
  651.       BytesDir = BytesDir + BytesFile
  652.    end
  653.  
  654.    /* Determine the size of all the files in all the subtrees under this */
  655.    /* directory.                                                         */
  656.  
  657.    call SysFileTree Directory, 'Current', 'D'
  658.  
  659.    BytesChildren = 0
  660.    do i = 1 to Current.0
  661.       parse var Current.i . . BytesFile . SubDirName
  662.       SubDirName = strip(SubDirName, 'Both')
  663.       BytesChildren = BytesChildren + SpaceDirectory(SubDirName'\*.*', (Level+1), DisplayLevel)
  664.    end
  665.  
  666.    /* Generate the statistics for this directory and its descendants */
  667.  
  668.    BytesSum = BytesDir + BytesChildren
  669.  
  670.    if DisplayLevel >= Level then
  671.       do
  672.  
  673.       /* Format the line for column output and add to the report */
  674.  
  675.       BytesDirFmt = FormatComma(BytesDir)
  676.       BytesSumFmt = FormatComma(BytesSum)
  677.       Report.0 = Report.0 + 1
  678.       q = Report.0
  679.       Report.q = right(BytesDirFmt, 10) right(BytesSumFmt, 12) copies(" ", Level*3) Directory
  680.       end
  681.    return BytesSum
  682.  
  683. /**
  684. *** ┌──────────────────────────────────────────────────────────────────────┐
  685. *** │                          Pstat Subroutines                           │
  686. *** └──────────────────────────────────────────────────────────────────────┘
  687. **/
  688.  
  689. PStat: procedure expose IniFile
  690.    /**
  691.    ***  This will place you in the editor on a list of files that was
  692.    ***  generated from the PSTAT command
  693.    **/
  694.  
  695.    arg parms
  696.  
  697.    if parms = 'ALL' then
  698.       pstatopt = ''
  699.    else
  700.       pstatopt = '/c'
  701.  
  702.    say "Working.  Please wait..."
  703.  
  704.    Editor   = GetIni('Program','Editor','e.exe')
  705.    TempFile = GetIni('File','Temp 2','c:\temp.1')
  706.  
  707.    '@pstat' pstatopt '>' TempFile
  708.    '@'Editor TempFile
  709.    return
  710.  
  711.  
  712. /**
  713. *** ┌──────────────────────────────────────────────────────────────────────┐
  714. *** │                         Migrate Subroutines                          │
  715. *** └──────────────────────────────────────────────────────────────────────┘
  716. **/
  717.  
  718. Migrate: procedure expose IniFile
  719.    /**
  720.    ***  This will move the file from the working directory to the production
  721.    ***  directory based on the file name if passed.  If the filename is not
  722.    ***  passed, it will migrate by the current directory and the project
  723.    ***  environment variable
  724.    **/
  725.  
  726.    arg FileSpec
  727.    if FileSpec = '' then
  728.       call MigrateByDir
  729.    else
  730.       call MigrateByExt FileSpec
  731.    return
  732.  
  733.  
  734.  
  735. MigrateByDir: procedure expose IniFile
  736.    /**
  737.    ***  This will migrate the file from the development directory to the
  738.    ***  production directory based on the current path and the project
  739.    ***  variable.
  740.    **/
  741.  
  742.    Project = value("PROJECT", , "OS2ENVIRONMENT")
  743.    if Project = '' then
  744.       do
  745.       say "Project environment variable not set."
  746.       return
  747.       end
  748.  
  749.    Current = UpperCase(directory())
  750.  
  751.    call MigrateByExt Project'.EXE'
  752.    return
  753.  
  754.  
  755.  
  756. MigrateByExt: procedure expose IniFile
  757.    /**
  758.    ***  This will migrate the file from the development directory to the
  759.    ***  production directory based on the file extension.
  760.    **/
  761.  
  762.    arg FileSpec
  763.  
  764.    if verify(FileSpec, '\*?:', 'Match') > 0 then
  765.       do
  766.       say "The file must be specified with no wildcard or path information."
  767.       return
  768.       end
  769.  
  770.    ProdDLL    = GetIni('Directory','Products DLL','')
  771.    ProdCmd    = GetIni('Directory','Products Command','')
  772.    Products   = GetIni('Directory','Products','')
  773.  
  774.    parse var FileSpec FileName '.' FileExt
  775.    select
  776.       when FileExt = 'DLL' then Target = ProdDll
  777.       when FileExt = 'CMD' then Target = ProdCmd
  778.       when FileExt = 'EXE' then Target = Products
  779.       otherwise
  780.          do
  781.          say "Unrecognized extension:" FileExt".  No action taken."
  782.          return
  783.          end
  784.    end /* select */
  785.    'copy' FileSpec Target
  786.    return
  787.  
  788. /**
  789. *** ┌──────────────────────────────────────────────────────────────────────┐
  790. *** │                         Maximus Subroutines                          │
  791. *** └──────────────────────────────────────────────────────────────────────┘
  792. **/
  793.  
  794. Maximus: procedure expose IniFile
  795.  
  796.    parse arg cmd parms
  797.    cmd = translate(cmd)
  798.  
  799.    select
  800.       when abbrev('CLEANLOG'  ,cmd,  6) then call MaximusCleanLog   parms
  801.       when abbrev('CLEANFILES',cmd,  6) then call MaximusCleanFiles parms
  802.       when abbrev('LOGONS'    ,cmd,  3) then call MaximusLogons     parms
  803.       when abbrev('TODAY'     ,cmd,  3) then call MaximusToday      parms
  804.       when abbrev('DOWNLOADS' ,cmd,  2) then call MaximusDownloads  parms
  805.       when abbrev('DL'        ,cmd,  2) then call MaximusDownloads  parms
  806.       otherwise
  807.          say "Subcommand (MAXIMUS): '"cmd"' not recognized"
  808.    end /* Select */
  809.    return
  810.  
  811.  
  812. MaximusCleanLog: procedure expose IniFile
  813.    /**
  814.    ***  This will trim the log for the Maximus BBS by keeping only those
  815.    ***  lines that being with a '+' or '='.  These are the logon, logoff
  816.    ***  and download messages.
  817.    **/
  818.  
  819.    '@echo off'
  820.  
  821.    /* Get the INI information */
  822.  
  823.    MaxDir   = GetIni('Directory','Maximus','')
  824.    Grep     = GetIni('Program','Grep','GREP.EXE')
  825.    MaxLog   = GetIni('File','Maximus Log','')
  826.    TempFile = GetIni('File','Temp 1','')
  827.  
  828.    MaxDir = directory(MaxDir)
  829.    Grep '"^[\+\=]"' MaxLog '>' TempFile
  830.    '@copy' TempFile MaxLog
  831.  
  832.    /* Clean up the temporary files */
  833.  
  834.    '@erase' TempFile
  835.    return
  836.  
  837.  
  838. MaximusCleanFiles: procedure expose IniFile
  839.    /**
  840.    ***  This will look for the files that are created by the Maximus BBS
  841.    ***  when a path override is done by the sysop and a file is uploaded.
  842.    ***  When those files are found, they are deleted.
  843.    **/
  844.  
  845.    /* Get the INI information */
  846.  
  847.    MaxDir   = GetIni('Directory','Maximus','')
  848.    BBSFile  = GetIni('File','Maximus BBS File','')
  849.  
  850.    '@erase' TempFile
  851.    map = SysDriveMap('C:', 'USED')
  852.    i = 1
  853.    drive = word(map, i)
  854.    do while(drive \= '')
  855.       call SysFileTree drive'\'BBSFile, 'Found', 'FSO'
  856.       do j = 1 to Found.0
  857.          'erase' found.j
  858.       end
  859.       i = i + 1
  860.       drive = word(map, i)
  861.    end /* do */
  862.    return
  863.  
  864.  
  865. MaximusLogons: procedure expose IniFile
  866.    /**
  867.    ***
  868.    **/
  869.  
  870.    '@echo off'
  871.    MaxDir   = GetIni('Directory','Maximus','')
  872.    Grep     = GetIni('Program','Grep','GREP.EXE')
  873.    MaxLog   = GetIni('File','Maximus Log','')
  874.  
  875.    MaxDir = directory(MaxDir)
  876.    Grep '"^\+.*calling ("' MaxLog
  877.    return
  878.  
  879.  
  880. MaximusDownloads: procedure expose IniFile
  881.    /**
  882.    ***
  883.    **/
  884.  
  885.    MaxDir   = GetIni('Directory','Maximus','')
  886.    Grep     = GetIni('Program','Grep','GREP.EXE')
  887.    MaxLog   = GetIni('File','Maximus Log','')
  888.    Awk      = GetIni('Program','Awk','gawk.exe')
  889.    AwkDir   = GetIni('Directory','Awk','')
  890.    TempFile = GetIni('File','Temp Maximus Download','c:\temp.1')
  891.    Editor   = GetIni('Program','Editor','e.exe')
  892.  
  893.    '@echo off'
  894.    MaxDir = directory(MaxDir)
  895.    Awk '-f' AwkDir'\MaxDLByFile.awk' MaxLog '>'  TempFile
  896.    Awk '-f' AwkDir'\MaxDL.awk'       MaxLog '>>' TempFile
  897.    Editor TempFile
  898.    return
  899.  
  900.  
  901. MaximusToday: procedure expose IniFile
  902.    /**
  903.    ***
  904.    **/
  905.  
  906.    MaxDir   = GetIni('Directory','Maximus','')
  907.    MaxLog   = GetIni('File','Maximus Log','')
  908.    Awk      = GetIni('Program','Awk','gawk.exe')
  909.    AwkDir   = GetIni('Directory','Awk','')
  910.  
  911.    MaxDir = directory(MaxDir)
  912.  
  913.    parse value date('N') with dd mmm .
  914.    dd = right(dd, 2, '0')
  915.    "@"Grep '"'dd mmm'"' MaxLog '|' Awk '-f' AwkDir'\MaxToday.AWK'
  916.    return
  917.  
  918. /**
  919. *** ┌──────────────────────────────────────────────────────────────────────┐
  920. *** │                     Environment Subroutines                          │
  921. *** └──────────────────────────────────────────────────────────────────────┘
  922. **/
  923.  
  924. Environment: procedure expose IniFile
  925.    /**
  926.    ***  This will list the contents of the environment variable in a list.
  927.    ***  It was designed to list those environment variables that are a
  928.    ***  list of directories, separated by semicolons, such as a PATH or
  929.    ***  DPATH variable.  Although it is not an environment variable, this
  930.    ***  code will do the same for the LIBPATH by looking in the CONFIG.SYS
  931.    **/
  932.  
  933.    arg EnvVariable .
  934.  
  935.    if EnvVariable = '' then
  936.       EnvVariable = 'PATH'
  937.  
  938.    /* Take care of the special case for LIBPATH */
  939.  
  940.    if EnvVariable = 'LIBPATH' then
  941.       EnvValue = GetLibpath()
  942.    else
  943.       EnvValue = value(EnvVariable,,"OS2ENVIRONMENT")
  944.  
  945.    /* Create the list of directories and display them in a nicely formatted */
  946.    /* list.                                                                 */
  947.  
  948.    Count = PathSplit(EnvValue)       /* Set DirList. */
  949.    say "The following" Count "directories were found in the" EnvVariable
  950.    say copies("─",78)
  951.    do i = 1 to DirList.0
  952.       say "   " DirList.i
  953.    end
  954.    return
  955.  
  956. /**
  957. *** ┌──────────────────────────────────────────────────────────────────────┐
  958. *** │ Check Subroutines                                                    │
  959. *** └──────────────────────────────────────────────────────────────────────┘
  960. **/
  961.  
  962.  
  963. Check: procedure expose IniFile
  964.  
  965.    parse arg cmd parms
  966.    cmd = translate(cmd)
  967.  
  968.    select
  969.       when abbrev('DRIVES'   ,cmd,  2) then call CheckDrives  parms
  970.       when abbrev('MAIL'     ,cmd,  2) then call CheckMail    parms
  971.       when abbrev('MOUNTS'   ,cmd,  2) then call CheckMount   parms
  972.       when abbrev('OS2BBS'   ,cmd,  3) then call CheckOS2BBS  parms
  973.       when abbrev('BBS'      ,cmd,  3) then call CheckOS2BBS  parms
  974.       when abbrev('NETSTAT'  ,cmd,  3) then call CheckNetStat parms
  975.       otherwise
  976.          say "Subcommand (CHECK): '"cmd"' not recognized"
  977.    end /* Select */
  978.    return
  979.  
  980.  
  981. CheckNetStat: procedure expose IniFile
  982.    /**
  983.    ***  This will check the TCP/IP routing information and make sure that
  984.    ***  the default route is set up correctly.
  985.    **/
  986.  
  987.    /* Clear the queue */
  988.  
  989.    do i = 1 to queued()
  990.       pull .
  991.    end
  992.  
  993.    '@netstat -r | rxqueue'
  994.    pull . /* Header line */
  995.    pull . /* Header line */
  996.    pull . /* Header line */
  997.  
  998.    OK = 1
  999.    do i = 1 to queued()
  1000.       parse pull destination router .
  1001.       select
  1002.          when destination = 'default' then
  1003.             do
  1004.             if router <> '144.223.12.33' then
  1005.                OK = 0
  1006.             end
  1007.          when destination = '144.223.12.0' then
  1008.             do
  1009.             if router <> '144.223.12.3' then
  1010.                OK = 0
  1011.             end
  1012.          when destination = '144.223.12.60' then
  1013.             do
  1014.             if router <> '144.223.12.61' then
  1015.                OK = 0
  1016.             end
  1017.          when destination = '144.223.12.61' then
  1018.             do
  1019.             if router <> '144.223.12.60' then
  1020.                OK = 0
  1021.             end
  1022.          otherwise
  1023.             OK = 0
  1024.       end /* select */
  1025.    end /* do */
  1026.  
  1027.    if OK = 0 then
  1028.       do
  1029.       '@route -fh'
  1030.       '@arp -f'
  1031.       '@route add default 144.223.12.33 1'
  1032.       Notify = GetIni('Program','Notify','pmmessag.exe')
  1033.       '@start' Notify 'Default route definition was reset.'
  1034.       end
  1035.    return
  1036.  
  1037.  
  1038. CheckMount: procedure expose IniFile
  1039.    /**
  1040.    ***  This will check to see if the NFS drives are mounted.  If not,
  1041.    ***  a mount is attempted.
  1042.    **/
  1043.  
  1044.    MountList = 'G: L: M: R:'
  1045.    DriveList = SysDriveMap('C:', 'REMOTE')
  1046.  
  1047.    if wordpos('G:', DriveList) = 0 then
  1048.       '@mount -u0 -g0 g: gilligan:d:/pub'
  1049.    if wordpos('L:', DriveList) = 0 then
  1050.       '@mount -u0 -g0 l: ts54lpar:d:/'
  1051.    if wordpos('M:', DriveList) = 0 then
  1052.       call ! 'mount m: ts54sys1:/home/m747025'
  1053.    if wordpos('R:', DriveList) = 0 then
  1054.       call ! 'mount r: ts54sys1:/home/share'
  1055.  
  1056.    DriveList = SysDriveMap('C:', 'REMOTE')
  1057.    do i = 1 to words(MountList)
  1058.       Drive = word(MountList,i)
  1059.       if wordpos(Drive, DriveList) = 0 then
  1060.          do
  1061.          Notify = GetIni('Program','Notify','pmmessag.exe')
  1062.          '@start' Notify 'One or more of the remote drives did not mount properly.'
  1063.          return
  1064.          end
  1065.    end
  1066.    return
  1067.  
  1068.  
  1069. CheckMail: procedure expose IniFile
  1070.    /**
  1071.    ***  This will see if there has been any new SprintMail loaded down.  It
  1072.    ***  checks by looking for the archive bit on the files in the IN box.
  1073.    ***  This is intended to be run by CHRON.
  1074.    **/
  1075.  
  1076.    MailDir = GetIni('Directory','SprintMail','')
  1077.    call SysFileTree MailDir'\IN.BOX\*.ASC', 'Found', 'F', '+****', '-****'
  1078.    if Found.0 > 0 then
  1079.       do
  1080.       Notify = GetIni('Program','Notify','pmmessag.exe')
  1081.       '@start' Notify 'You have new SprintMail'
  1082.       end
  1083.    return
  1084.  
  1085.  
  1086. CheckOS2BBS: procedure expose IniFile
  1087.    /**
  1088.    ***  This will see if there has been any new OS2BBS information loaded
  1089.    ***  down from IBMLink
  1090.    ***
  1091.    ***  This is intended to be run by CHRON.
  1092.    **/
  1093.  
  1094.    BBSDir = GetIni('Directory','OS/2 BBS','')
  1095.    call SysFileTree BBSDir'\Data\*', 'Found', 'F', '+****', '-****'
  1096.    if Found.0 > 0 then
  1097.       do
  1098.       Notify = GetIni('Program','Notify','pmmessag.exe')
  1099.       '@start' Notify 'You have new information from OS2BBS on IBMLink'
  1100.       end
  1101.    return
  1102.  
  1103.  
  1104. CheckDrives: procedure expose IniFile
  1105.    /**
  1106.    ***  This will run a CHKDSK on both the local  drives and pipe the output
  1107.    ***  into a file.  Once both have been run, the editor is started with the
  1108.    ***  output file to display the results.   This is intended to be run by
  1109.    ***  CHRON.
  1110.    **/
  1111.  
  1112.    TempFile = GetIni('File','Temp Check Disk','c:\temp.1')
  1113.    '@erase' TempFile
  1114.    map = SysDriveMap('C:', 'LOCAL')
  1115.    i = 1
  1116.    drive = word(map, i)
  1117.    do while(drive \= '')
  1118.       say "Checking drive" drive"..."
  1119.       "@echo Checking drive" drive"...   >>" TempFile
  1120.       "@chkdsk" drive                   ">>" TempFile
  1121.       "@echo" copies("─",78)            ">>" TempFile
  1122.       i = i + 1
  1123.       drive = word(map, i)
  1124.    end
  1125.  
  1126.    Editor = GetIni('Program','Editor','e.exe')
  1127.    '@'Editor TempFile
  1128.    return
  1129.  
  1130. /**
  1131. *** ┌──────────────────────────────────────────────────────────────────────┐
  1132. *** │ Support Routines                                                     │
  1133. *** └──────────────────────────────────────────────────────────────────────┘
  1134. **/
  1135.  
  1136. GetIni: procedure expose IniFile
  1137.    /**
  1138.    ***  This will pull a value from the INI file or the default value if
  1139.    ***  there is no entry in the INI file.
  1140.    **/
  1141.  
  1142.    parse arg Application, Key, Default
  1143.  
  1144.    IniValue = SysIni(IniFile,Application,Key)
  1145.    if IniValue = 'ERROR:' then
  1146.       do
  1147.       call charout ,"Enter value for" Application"/"key":"
  1148.       parse pull IniValue
  1149.       code = SysIni(IniFile,Application,Key,IniValue)
  1150.       end
  1151.    return IniValue
  1152.  
  1153.  
  1154. GetIniFile: procedure
  1155.    /**
  1156.    ***  This will find the INI file that contains profile information.
  1157.    **/
  1158.  
  1159.    /* Look for an environment variable first */
  1160.  
  1161.    IniFile = value('Hilbert.Ini',,"OS2ENVIRONMENT")
  1162.    if IniFile = '' then
  1163.       IniFile = SysSearchPath("DPATH","Hilbert.Ini")
  1164.    if IniFile = '' then
  1165.       do
  1166.       This = ThisDirectory()
  1167.       if Exists(This"\Hilbert.Ini") then
  1168.          IniFile = This"\Hilbert.Ini"
  1169.       end
  1170.    if IniFile = '' then
  1171.       call Error 2002,1,"Hilbert.Ini"
  1172.    return IniFile
  1173.  
  1174. /**
  1175. *** ┌──────────────────────────────────────────────────────────────────────┐
  1176. *** │ Changed Subroutines                                                  │
  1177. *** └──────────────────────────────────────────────────────────────────────┘
  1178. **/
  1179.  
  1180. Changed: procedure expose IniFile
  1181.    /**
  1182.    ***  This will recurse through all the specified drives and generate
  1183.    ***  a byte count on the files with the archive bit on
  1184.    **/
  1185.  
  1186.    arg DisplayLevel DriveList
  1187.  
  1188.    Report.  = ''
  1189.    Report.0 = 0
  1190.  
  1191.    /* Give defaults for missing parameters */
  1192.  
  1193.    if DisplayLevel = ''  then DisplayLevel = 32768
  1194.    if DisplayLevel = '*' then DisplayLevel = 32768
  1195.    if DisplayLevel = '.' then DisplayLevel = 32768
  1196.  
  1197.    if DriveList = '' then DriveList = SysDriveMap('C:', 'LOCAL')
  1198.  
  1199.  
  1200.    do i = 1 to words(DriveList)
  1201.       Drive = word(DriveList, i)
  1202.       BytesDrive = ChangedDirectory(Drive'\*.*', 0, DisplayLevel)
  1203.    end
  1204.  
  1205.    /* Erase the old and open a new file */
  1206.  
  1207.    TempFile = GetIni('File','Temp Changed','c:\temp.1')
  1208.    '@erase' TempFile '> nul'
  1209.    ReportFile = Open(TempFile 'WRITE')
  1210.  
  1211.    /* Write the headers */
  1212.  
  1213.    call lineout ReportFile, center("File", 10) center("w/ Child", 12) center("Directory", 54)
  1214.    call lineout ReportFile, copies('-', 10)    copies("-", 12)        copies("-", 54)
  1215.  
  1216.    /* Write the space utilization report */
  1217.  
  1218.    do i = Report.0 to 1 by -1
  1219.       call lineout ReportFile, Report.i
  1220.    end
  1221.    ReportFile = Close(ReportFile)
  1222.  
  1223.    /* Start the editor on the report file */
  1224.  
  1225.    Editor = GetIni('Program','Editor','e.exe')
  1226.    '@'Editor TempFile
  1227.    return
  1228.  
  1229.  
  1230. ChangedDirectory: procedure expose IniFile Report.
  1231.    /**
  1232.    ***  This will generate a changed files report for a given drive
  1233.    **/
  1234.  
  1235.    arg Directory, Level, DisplayLevel
  1236.  
  1237.    /* Sum the size of all files in this directory */
  1238.  
  1239.    call SysFileTree Directory, 'Current', 'F', '+****'
  1240.  
  1241.    BytesDir = 0
  1242.    Detail.  = ''
  1243.    Detail.0 = 0
  1244.  
  1245.    do i = 1 to Current.0
  1246.       parse var Current.i . . BytesFile . FileName
  1247.       FileName = strip(FileName, 'Both')
  1248.       BytesDir = BytesDir + BytesFile
  1249.       if DisplayLevel = 0 then
  1250.          do
  1251.          Detail.0 = Detail.0 + 1
  1252.          q = Detail.0
  1253.          Detail.q = copies(" ", 25+Level*3) FileName
  1254.          end
  1255.    end
  1256.  
  1257.    /* Determine the size of all the files in all the subtrees under this */
  1258.    /* directory.                                                         */
  1259.  
  1260.    call SysFileTree Directory, 'Current', 'D'
  1261.  
  1262.    BytesChildren = 0
  1263.    do i = 1 to Current.0
  1264.       parse var Current.i . . BytesFile . SubDirName
  1265.       SubDirName = strip(SubDirName, 'Both')
  1266.       BytesChildren = BytesChildren + ChangedDirectory(SubDirName'\*.*', (Level+1), DisplayLevel)
  1267.    end
  1268.  
  1269.    /* Generate the statistics for this directory and its descendants */
  1270.  
  1271.    BytesSum = BytesDir + BytesChildren
  1272.  
  1273.    if (DisplayLevel = 0) | (DisplayLevel >= Level) then
  1274.       do
  1275.  
  1276.       if DisplayLevel = 0 then
  1277.          do i = 1 to Detail.0
  1278.             Report.0 = Report.0 + 1
  1279.             q = Report.0
  1280.             Report.q = Detail.i
  1281.          end
  1282.  
  1283.       /* Format the line for column output and add to the report */
  1284.  
  1285.       BytesDirFmt = FormatComma(BytesDir)
  1286.       BytesSumFmt = FormatComma(BytesSum)
  1287.       Report.0 = Report.0 + 1
  1288.       q = Report.0
  1289.       Report.q = right(BytesDirFmt, 10) right(BytesSumFmt, 12) copies(" ", Level*3) Directory
  1290.       end
  1291.    return BytesSum
  1292.  
  1293.  
  1294. DeleteOldFiles: procedure
  1295.    /**
  1296.    ***  This will keep 'x' versions of the filename that matches the
  1297.    ***  pattern passed and delete the rest.
  1298.    **/
  1299.  
  1300.    arg SearchFor, Keep
  1301.  
  1302.    /* Keep the number of message file backups to a reasonable number */
  1303.  
  1304.    call SysFileTree SearchFor, 'Sort', 'FT'
  1305.  
  1306.    /* If there are a bunch of them, delete the oldest ones */
  1307.  
  1308.    if Sort.0 > Keep then
  1309.       do
  1310.       call SortStem
  1311.       do j = 1 to (Sort.0 - Keep)
  1312.          parse var Sort.j . . . DeleteFile
  1313.          'erase' DeleteFile
  1314.       end
  1315.       end /* if */
  1316.    return (Sort.0 - Keep)
  1317.  
  1318.  
  1319. SortStem: procedure expose Sort.
  1320.    /**
  1321.    ***  This will sort the stem variable passed in.  It is assumed that the
  1322.    ***  stem variable is formatted in the "standard" way of Stem.0 containing
  1323.    ***  the number of items
  1324.    **/
  1325.  
  1326.    do i = 1 to Sort.0
  1327.  
  1328.       /* Find the lowest value in the list */
  1329.  
  1330.       low = i;
  1331.       do j = (i+1) to Sort.0
  1332.          if Sort.j < Sort.low then
  1333.             low = j
  1334.       end
  1335.  
  1336.       /* Swap the two */
  1337.  
  1338.       temp = Sort.i
  1339.       Sort.i = Sort.low
  1340.       Sort.low = temp
  1341.    end
  1342.    return
  1343.  
  1344.  
  1345. /**
  1346. *** ┌──────────────────────────────────────────────────────────────────────┐
  1347. *** │ "To-Be" Included routines                                            │
  1348. *** └──────────────────────────────────────────────────────────────────────┘
  1349. **/
  1350.  
  1351.  
  1352. PathSplit: procedure expose DirList.
  1353.    /**
  1354.    ***  This will create a stem variable out of the semicolon-delimited
  1355.    ***  variable that is presumably retreived from a PATH or DPATH
  1356.    ***  environment.
  1357.    **/
  1358.  
  1359.    arg PathString .
  1360.  
  1361.    DirList = ''
  1362.    j = 1
  1363.    parse var PathString DirList.j ';' PathString
  1364.    do while DirList.j \= ''
  1365.       j = j + 1
  1366.       parse var PathString DirList.j ';' PathString
  1367.    end /* while */
  1368.    DirList.0 = j - 1
  1369.    return DirList.0
  1370.  
  1371.  
  1372. GetLibpath: procedure
  1373.    /**
  1374.    ***  This will return the LIBPATH string
  1375.    **/
  1376.  
  1377.    Boot = SystemDrive()
  1378.    call SysFileSearch 'LIBPATH=', Boot':\CONFIG.SYS', 'Libpath'
  1379.    select
  1380.       when Libpath.0 = 0 then
  1381.          Dlls = ''
  1382.       when Libpath.0 = 1 then
  1383.          Dlls = Libpath.0
  1384.       otherwise
  1385.          do
  1386.          Dlls = ''
  1387.          do j = 1 to Libpath.0
  1388.             Path = translate(Libpath.j)
  1389.             Path = strip(Path)
  1390.             if left(Path,8) = 'LIBPATH=' then
  1391.                Dlls = Libpath.j
  1392.          end
  1393.          end
  1394.    end /* select */
  1395.    return substr(Dlls, 9)  /* Remove the "LIBPATH=" */
  1396.  
  1397. /**
  1398. *** ┌──────────────────────────────────────────────────────────────────────┐
  1399. *** │ Included routines                                                    │
  1400. *** └──────────────────────────────────────────────────────────────────────┘
  1401. **/
  1402.  
  1403.  
  1404. /* #include LoadFunctions.rex */
  1405.  
  1406. LoadFunctions: procedure
  1407.    /**
  1408.    ***   This will load the DLL for the Rexx system functions supplied
  1409.    ***   with OS/2 v2.0
  1410.    **/
  1411.    call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  1412.    call SysLoadFuncs
  1413.    return
  1414.  
  1415.  
  1416. /* #include <error.rex> */
  1417.  
  1418. /**
  1419. *** ╔═══════════════════════════════════════════════════════════════════════╗
  1420. *** ║ Error Handler                                                         ║
  1421. *** ╚═══════════════════════════════════════════════════════════════════════╝
  1422. **/
  1423.  
  1424.  
  1425. Error: procedure
  1426.    /**
  1427.    ***  This is a centralized processor for error messages and error handling
  1428.    **/
  1429.  
  1430.    parse arg ErrNo,Fatal,String1,String2,String3
  1431.  
  1432.    /* Select the error string based on the error number */
  1433.  
  1434.    select
  1435.       when ErrNo = 1001 then Msg = "Return code %1 from RxFuncAdd for SQLEXEC"
  1436.       when ErrNo = 1002 then Msg = "Return code [%1] from SQLEXEC.  You are probably out-of-storage."
  1437.       when ErrNo = 1003 then Msg = "SQL code [%1]: %2"
  1438.       when ErrNo = 2002 then Msg = "File '%1' not found."
  1439.       when ErrNo = 2003 then Msg = "Directory '%1' doesn't exist."
  1440.       when ErrNo = 2004 then Msg = "Missing parameter."
  1441.       when ErrNo = 3000 then Msg = "Urecognized message '%1' passed from message queue."
  1442.       when ErrNo = 3001 then Msg = "Error from server: %1."
  1443.       when ErrNo = 4000 then Msg = "Host screen doesn't match expected value of '%1'"
  1444.       when ErrNo = 5005 then Msg = "Return code 5 from RxQueue. Not a valid queue name: '%1'"
  1445.       when ErrNo = 5009 then Msg = "Return code 9 from RxQueue. Queue does not exist: '%1'"
  1446.       when ErrNo = 5010 then Msg = "Return code 10 from RxQueue. Queue is busy: '%1'"
  1447.       when ErrNo = 5012 then Msg = "Return code 12 from RxQueue. Memory failure on queue: '%1'"
  1448.       when ErrNo = 6000 then Msg = "Return code 1000 from RxQueue. Initialization error on queue: '%1'"
  1449.  
  1450.       when ErrNo = 9999 then Msg = "%1"
  1451.       otherwise              Msg = "[%1,%2,%3]"
  1452.    end /* select */
  1453.  
  1454.    /* Render the string with the substituted parameters */
  1455.  
  1456.    Msg = ErrorRender('%1',String1,Msg)
  1457.    Msg = ErrorRender('%2',String2,Msg)
  1458.    Msg = ErrorRender('%3',String3,Msg)
  1459.  
  1460.    /* Determine how to handle the error. This was a temp hack and should */
  1461.    /* go away.  I think the only client that is using it is SUPPD        */
  1462.  
  1463.    Client = value("CLIENT",,"OS2ENVIRONMENT")
  1464.    if Client <> '' then
  1465.       call Post Client "status" tag Msg
  1466.  
  1467.    /* -- End of Hack -- */
  1468.  
  1469.    Callback = value("REXX.CALLBACK",,"OS2ENVIRONMENT")
  1470.    if Callback = '1' then
  1471.       call ErrorHandler Msg
  1472.    else
  1473.       say Msg
  1474.  
  1475.    /* Should we terminate? */
  1476.  
  1477.    if Fatal then exit ErrNo
  1478.    return 0
  1479.  
  1480.  
  1481. ErrorRegister: procedure
  1482.    /**
  1483.    *** This will register a callback to the calling routine for error handling
  1484.    *** after the error message has been rendered.
  1485.    ***
  1486.    *** If this code is called, the caller MUST have a routine called
  1487.    *** 'ErrorHandler' that is used to display the error message in an
  1488.    *** appropriate way.
  1489.    ***
  1490.    **/
  1491.  
  1492.    parse arg callback
  1493.    if callback = '' then
  1494.       callback = '1'
  1495.  
  1496.    code = value("REXX.CALLBACK",callback,"OS2ENVIRONMENT")
  1497.    return 0
  1498.  
  1499.  
  1500. ErrorRender: procedure
  1501.  
  1502.    parse arg Symbol,SymValue,Line
  1503.  
  1504.    if pos(Symbol, Line) > 0 then
  1505.       do
  1506.       parse var Line prefix (Symbol) suffix
  1507.       Line = prefix || SymValue || suffix
  1508.       end
  1509.    return Line
  1510.  
  1511. /* #include <system.rex> */
  1512.  
  1513. /**
  1514. *** ┌───────────────────────────────────────────────────────────────────────┐
  1515. *** │ Misc system functions                                                 │
  1516. *** └───────────────────────────────────────────────────────────────────────┘
  1517. **/
  1518.  
  1519. ThisDirectory: procedure
  1520.    /**
  1521.    ***  This will return the directory from which this exec was run
  1522.    **/
  1523.  
  1524.    parse source . . ThisFile
  1525.    LastSlash = lastpos('\', ThisFile)
  1526.    ThisDir = left(ThisFile, (LastSlash-1))
  1527.    return ThisDir
  1528.  
  1529.  
  1530. SystemDirectory: procedure
  1531.    /**
  1532.    ***  This will try to determine where the OS/2 system is located by
  1533.    ***  looking for a key DLL
  1534.    **/
  1535.  
  1536.    dir = "C:\OS2"
  1537.  
  1538.    code = RxQueue('Create','SysDir')
  1539.    que  = RxQueue('Set'   ,'SysDir')
  1540.    '@pstat /L | rxqueue SysDir'
  1541.  
  1542.    do while queued() > 0
  1543.       pull line
  1544.       if pos('DOSCALL1.DLL', line) > 0 then
  1545.          do
  1546.          line = word(line, words(line))
  1547.          parse var line dir '\DLL\DOSCALL1.DLL'
  1548.          do queued();pull .;end
  1549.          end
  1550.    end
  1551.  
  1552.    code = RxQueue('Delete','SysDir')
  1553.    que  = RxQueue('Set'   ,que)
  1554.    return strip(dir)
  1555.  
  1556.  
  1557. SystemDrive: procedure
  1558.    /**
  1559.    ***  This will return the single drive letter for the system
  1560.    **/
  1561.    path = translate(value("PATH",,"OS2ENVIRONMENT"))
  1562.    psn = pos(":\OS2",path)
  1563.    if psn < 1 then
  1564.       BootDrive = 'C'
  1565.    else
  1566.       BootDrive = substr(path,(psn-1),1)
  1567.    return BootDrive
  1568.  
  1569.  
  1570. /* #include <filesystem.rex> */
  1571.  
  1572.  
  1573. CompareFileTimes: procedure
  1574.    /**
  1575.    ***  This returns a boolean that indicates if the datetime stamps from
  1576.    ***  first file is older than the datetime stamp from the second file.
  1577.    ***  the file formats are the syntax from the SysFileTree
  1578.    **/
  1579.  
  1580.    parse arg Stamp.1, Stamp.2
  1581.  
  1582.    do i = 1 to 2
  1583.       parse var Stamp.i mon '/' day '/' year hour ':' temp
  1584.       parse var temp min 3 meridian
  1585.       hour = right(hour,2,'0')
  1586.       mon = right(mon,2,'0')
  1587.       if hour = 12 then hour = 0
  1588.       if meridian = 'p' then
  1589.          hour = hour + 12
  1590.       CompareStamp.i = year||mon||day||hour||min
  1591.    end
  1592.    select
  1593.       when CompareStamp.1 < CompareStamp.2 then
  1594.          return '<'
  1595.       when CompareStamp.1 > CompareStamp.2 then
  1596.          return '>'
  1597.       otherwise
  1598.          return '='
  1599.    end /* select */
  1600.    return '='
  1601.  
  1602.  
  1603. QualifiedDirectory: procedure
  1604.    /**
  1605.    ***  This determines if the file passed is a directory
  1606.    **/
  1607.  
  1608.    parse arg DirSpec
  1609.  
  1610.    Current = directory()           /* Save current directory */
  1611.    NewDir  = directory(DirSpec)    /* Get the fully qualified name */
  1612.    Current = directory(Current)    /* Restore directory */
  1613.    return NewDir
  1614.  
  1615. /* #include <io.rex> */
  1616.  
  1617. Close: procedure
  1618.    /**
  1619.    ***  Close a file I/O stream
  1620.    **/
  1621.    parse arg file
  1622.    message = stream(file,c,'CLOSE')
  1623.    if (message <> 'READY:') & (message <> '') then
  1624.       do
  1625.       say 'Error: Close failure on' file'.' message
  1626.       exit
  1627.       end
  1628.    return file
  1629.  
  1630.  
  1631. Exists: procedure
  1632.    /**
  1633.    *** Return a Boolean indicating whether the file exists or not
  1634.    **/
  1635.    arg file
  1636.  
  1637.    file = stream(file,c,'QUERY EXIST')
  1638.    if (file = '') then
  1639.       return 0
  1640.    else
  1641.       return 1
  1642.  
  1643.  
  1644. Open: procedure
  1645.    /**
  1646.    *** Open a file for READ, WRITE, APPEND or RANDOM (read/write)
  1647.    **/
  1648.    parse arg file, rw
  1649.    rw = translate(rw)
  1650.  
  1651.    select
  1652.       when rw = 'WRITE' then
  1653.          do
  1654.          file_ = stream(file,c,'QUERY EXIST')
  1655.          if file_ <> '' then
  1656.             '@erase "'file'" 2> NUL'
  1657.          end
  1658.       when rw = 'APPEND' then
  1659.          rw = 'WRITE'
  1660.       when rw = 'READ' then
  1661.          rw = 'READ'
  1662.       when rw = 'RANDOM' then
  1663.          rw = ''
  1664.       otherwise
  1665.          rw = 'READ'
  1666.    end /* select */
  1667.  
  1668.    message = stream(file,c,'OPEN' rw)
  1669.    if (message \= 'READY:') then
  1670.       do
  1671.       say 'Error: Open failure on' file'.' message
  1672.       return message
  1673.       end
  1674.    return file
  1675.  
  1676. /* #include <string.rex> */
  1677.  
  1678. MapSymbol: procedure
  1679.    /**
  1680.    ***  This will translate the input string to the output string.
  1681.    **/
  1682.  
  1683.    parse arg string, in, out
  1684.  
  1685.    outstring = ''
  1686.    psn = pos(in, string)
  1687.    do while(psn > 0)
  1688.       if psn > 1 then
  1689.          outstring = outstring || substr(string, 1, psn-1)
  1690.       outstring = outstring || out
  1691.       string = substr(string, psn+length(in))
  1692.       psn = pos(in, string)
  1693.    end
  1694.    outstring = outstring || string
  1695.    return outstring
  1696.  
  1697.  
  1698. UpperCase: procedure
  1699.    /**
  1700.    ***  This will convert the string to uppercase
  1701.    **/
  1702.  
  1703.    parse upper arg string
  1704.    return string
  1705.  
  1706.  
  1707. GetNoEcho: procedure
  1708.    /**
  1709.    ***  This will grab keystrokes and enter them back as '*' characters
  1710.    **/
  1711.  
  1712.    Password = ''
  1713.    Key = SysGetKey('NoEcho')
  1714.    do while c2x(Key) <> '0D'
  1715.       select
  1716.          when c2x(Key) = '08' then
  1717.             Password = left(Password, (length(password)-1))
  1718.          otherwise
  1719.             Password = Password || Key
  1720.       end /* select */
  1721.       Key = SysGetKey('NoEcho')
  1722.    end
  1723.    return Password
  1724.  
  1725.  
  1726. LowerCase: procedure
  1727.    /**
  1728.    ***  This will return the string passed after converting it to lowercase
  1729.    **/
  1730.  
  1731.    parse arg String
  1732.    String = translate(String, "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  1733.    return String
  1734.  
  1735.  
  1736. FormatComma: procedure
  1737.    /**
  1738.    ***  This will take a string (that is presumably numeric, but not verified
  1739.    ***  to be) and insert commas after groups of three digits
  1740.    **/
  1741.  
  1742.    arg Raw .
  1743.  
  1744.    Formatted = ''
  1745.    do while Raw \= 0
  1746.       Formatted = right(Raw, 3)','Formatted
  1747.       Raw = Raw % 1000
  1748.    end
  1749.    if Formatted = '' then
  1750.       Formatted = 0
  1751.    else
  1752.       do
  1753.       Formatted = Strip(Formatted,'Trailing',',')
  1754.       Formatted = Strip(Formatted,'Leading',' ')
  1755.       end
  1756.    return Formatted
  1757.  
  1758. /* #include <parseopt.rex> */
  1759.  
  1760. ParseOptions: procedure expose Opt.
  1761.    /**
  1762.    ***  This will parse the command line options.  Those parameters that
  1763.    ***  begin with a minus (-) or forward slash (/) are considered flags
  1764.    ***  and are placed in Opt.Flag.   The remaining options are placed
  1765.    ***  into Opt.parm.<x>.
  1766.    ***
  1767.    ***  NOTE:  This code does not clear out the 'Opt.' stem variable since
  1768.    ***         the caller may want to establish defaults prior to calling
  1769.    ***         this code.
  1770.    ***
  1771.    ***  LIMITATIONS:  The code currently only looks for the double quote
  1772.    ***         character (").  The apostrophe is treated like any other
  1773.    ***         character.  The way this is currently coded, multiple blanks
  1774.    ***         in a quoted string are compressed to a single blanks and
  1775.    ***         probably should not be.
  1776.    ***
  1777.    **/
  1778.  
  1779.    parse arg arguments
  1780.  
  1781.    Opt.Flag.List = ''
  1782.    Opt.State = 'Normal'
  1783.    j = 0
  1784.    do i = 1 to words(arguments)
  1785.       argument = word(arguments, i)
  1786.  
  1787.       select
  1788.          when Opt.State = 'Quoted Positional' then
  1789.             do
  1790.             /* Keep appending the words to this parm until an ending quote */
  1791.             /* is found.                                                   */
  1792.  
  1793.             Opt.Parm.j = Opt.Parm.j argument
  1794.             if right(argument,1) = '"' then
  1795.                do
  1796.                Opt.Parm.j = strip(Opt.Parm.j, 'Both', '"')
  1797.                Opt.State = 'Normal'
  1798.                end
  1799.             end
  1800.          when Opt.State = 'Quoted Flag' then
  1801.             do
  1802.             /* Keep appending until the terminating quote is found */
  1803.  
  1804.             Opt.Flag.Flagname = Opt.Flag.FlagName argument
  1805.             if right(argument,1) = '"' then
  1806.                do
  1807.                Opt.Flag.Flagname = strip(Opt.Flag.Flagname, 'Both', '"')
  1808.                Opt.State = 'Normal'
  1809.                end
  1810.             end
  1811.          when Opt.State = 'Normal' then
  1812.             do
  1813.             FirstChar = left(argument, 1)
  1814.             if ((FirstChar = '-') | (FirstChar = '/')) then
  1815.                do
  1816.                /*  This is a flag.  The value of the flag is the remainder of  */
  1817.                /*  the string.  If the remainder is the null string, then it   */
  1818.                /*  has an implicit value of '+' implying "on" or "true"        */
  1819.  
  1820.                FlagName = substr(argument, 2, 1)   /* Second character     */
  1821.                FlagName = translate(FlagName)      /* Convert to uppercase */
  1822.  
  1823.                /* See if this flag parm is quoted */
  1824.  
  1825.                if substr(argument, 3, 1) = '"' then
  1826.                   Opt.State = 'Quoted Flag'
  1827.  
  1828.                /* If any of the flag names are not a valid character for a REXX */
  1829.                /* variable, we have to translate into a mnemonic.               */
  1830.  
  1831.                if ((FlagName < 'A') | (FlagName > 'Z')) then
  1832.                   do
  1833.                   select
  1834.                      when FlagName = '?' then FlagName = 'SYNTAX'
  1835.                      when FlagName = '!' then FlagName = 'BANG'
  1836.                      when FlagName = '*' then FlagName = 'STAR'
  1837.                      when FlagName = '#' then FlagName = 'POUND'
  1838.                      when FlagName = '$' then FlagName = 'DOLLAR'
  1839.                      when FlagName = '%' then FlagName = 'PERCENT'
  1840.                      when FlagName = '^' then FlagName = 'HAT'
  1841.                      when FlagName = '&' then FlagName = 'AMP'
  1842.                      when FlagName = '(' then FlagName = 'LPAR'
  1843.                      when FlagName = ')' then FlagName = 'RPAR'
  1844.                      when FlagName = '-' then FlagName = 'DASH'
  1845.                      when FlagName = '=' then FlagName = 'EQUAL'
  1846.                      otherwise /* Force a syntax message */
  1847.                         FlagName = 'SYNTAX'
  1848.                   end /* select */
  1849.                   end /* if */
  1850.  
  1851.                FlagValue = substr(argument, 3)     /* Remainder of string */
  1852.                if FlagValue = '' then
  1853.                   FlagValue = '+'
  1854.  
  1855.                Opt.Flag.FlagName = FlagValue
  1856.                Opt.Flag.List = FlagName Opt.Flag.List
  1857.                end
  1858.             else /* it is a positional parameter */
  1859.                do
  1860.                j = j + 1
  1861.                Opt.Parm.j = argument
  1862.                if left(argument,1) = '"' then
  1863.                   Opt.State = 'Quoted Positional'
  1864.                end
  1865.          end /* 'Normal' */
  1866.       otherwise
  1867.          nop
  1868.       end /* select */
  1869.    end /* do i... */
  1870.    Opt.Parm.0 = j
  1871.    return
  1872.  
  1873. /**
  1874. *** ═══════════════════════════════════════════════════════════════════════
  1875. *** Change History:
  1876. ***      3.0   - Changed to use INI services.  Removed some rarely-used
  1877. ***              routines.  Changed code to use the preprocessor and common
  1878. ***              included code.
  1879. ***      3.1   - Prompt for INI information on 'ERROR:'.
  1880. ***      3.2   - Added RECURSE
  1881. ***              Changed the INCLUDE env var for IBMC profile
  1882. ***      3.3   - Added COPYSAFE to the code
  1883. ***      3.4   - Added BACKUP CONFIG and BACKUP CHRON
  1884. ***      3.4.1 - Fixed bug where INIFILE wasn't exposed properly for BACKUP
  1885. ***              subcommand.
  1886. *** ═══════════════════════════════════════════════════════════════════════
  1887. **/
  1888.