home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / SHWINI.ZIP / SHOWINI.CMD < prev    next >
OS/2 REXX Batch file  |  1992-06-01  |  125KB  |  3,371 lines

  1. /*
  2. program: showini.cmd
  3. type:    REXXSAA-OS/2, OS/2 2.0
  4. purpose: allow for viewing, editing, backing up & restoring of OS/2-INI-files
  5. version: 1.04
  6. date:    1992-06-01
  7.  
  8. author:  Rony G. Flatscher
  9.          RONY@AWIWUW11.BITNET
  10.          rony@wu-wien.ac.at
  11.  
  12. usage:   
  13.    SHOWINI: allow to view, edit, print, backup, restore OS/2-INI-files
  14.             (e.g. OS2.INI, OS2SYS.INI)
  15.  
  16.    showini                       ... allow to work interactively
  17.  
  18.    backing up: (backing up an OS/2-INI-file entirely)
  19.    ===========
  20.      showini /B  ini-file        ... Backup will be put in a newly created ini-file
  21.      showini /BT ini-file        ... Backup will be put in a newly created Text-file
  22.  
  23.    restoring: (resets values according to backup & deletes keys which are not saved in backup)
  24.    ==========
  25.      showini /R  BKP-INI-file    ... Restore from a backup-ini-file
  26.      showini /RT BKP-TEXT-file   ... Restore from a backup-Text-file
  27.  
  28.    updating: (just resets values according to backup)
  29.    =========
  30.      showini /U  BKP-INI-file    ... Update from a backup-ini-file
  31.      showini /UT BKP-TEXT-file   ... Update from a backup-Text-file
  32.  
  33.  
  34. needs:   all RxUtil-functions loaded, BOXEDIT.CMD
  35.  
  36.  
  37. 1) Working interactively with OS/2-INI-files
  38. ============================================
  39.  
  40. SHOWINI.CMD allows you to interactively
  41.  
  42.     a) view
  43.     b) print to text-(ASCII)-file
  44.     c) edit
  45.     d) move/copy
  46.     e) delete
  47.  
  48. Toplevel entries ("Application entries") and key-entries in OS/2-INI-files. Just
  49. enter:
  50.  
  51.      showini
  52.  
  53. Initially you will **not** see the menu choices for editing, moving/copying and
  54. deleting INI-entries for safety reasons. Also, you will get a choice to work 
  55. with OS2.INI (USER) and OS2SYS.INI (SYSTEM). With "s" for scan you can have 
  56. SHOWINI.CMD to automatically scan for valid OS/2-INI-files on all local and/or 
  57. remote drives or a specific drive, it will successfully ignore 
  58. Winodows-INI-files.
  59.  
  60. Once you configure one of the above manipulative functions the configuration 
  61. choice will be shown, if you reset them, it will not be shown anymore.  
  62. Therefore you could safely leave this program on a machine for end-users.
  63.  
  64. In order to activate the edit, move/copy and/or delete functions, you need to 
  65. enter "c" (configure) on the main menu.  This option will allways be accessible 
  66. from the INI- and TopLevel-menus, no matter whether it is displayed or not.  All 
  67. these settings will be stored in OS2.INI under the TopLevel-entry called "RGF 
  68. Showini.cmd".  Hint:  If there are many entries in an INI-file, use the 
  69. MODE-command to get more lines or more columns and/or lines:
  70.  
  71.        e.g. "MODE co80,100" for 100 lines or
  72.             "MODE co132,50" for 132 columns and 50 lines on an XGA-adapter
  73.  
  74. Hint: Wherever it is possible from the program logic, you may immeditiately end 
  75. SHOWINI.CMD by typing "q" (quit). Attention: if quitting the program, changes to
  76. the settings are not stored in OS2.INI.
  77.  
  78.  
  79. 2) Batchfile-commands
  80. =====================
  81.  
  82. SHOWINI.CMD allows for
  83.  
  84.         backing up and ***restoring*** INI-files while the system is running ! 
  85.  
  86. This means that you can backup even OS2.INI and OS2SYS.INI while the system is 
  87. up and restore them from a backup while the system is running. SHOWINI.CMD 
  88. automatically produces **10-generation** backups.
  89.  
  90.  
  91. a) BACKUP
  92. =========
  93.  
  94. syntax:
  95.  
  96.     showini /B INI-file
  97.     showini /BT INI-file
  98.  
  99. This will produce a backup-file, which is **allways** located in the drive and 
  100. subdirectory of the given INI-file.  If you do not give a drive and a path, 
  101. SHOWINI.CMD assumes that your INI-file is located in the current drive and path.  
  102. By default SHOWINI.CMD produces 10 generations of backup, thereafter deleting 
  103. the oldest to make room for the new backup.  
  104.  
  105. Depending on the switch, /B or /BT, the backup file will be an OS/2-INI-file or 
  106. a plain text-(ASCII)-file. Backups in the OS/2-INI-file format will have a filename 
  107. which corresponds to the original file-name where the last letter will be 
  108. replaced by the digits 0 thru 9, e.g. OS2.IN0, OS2.IN1, OS2.IN2, ..., OS2.IN9.
  109. Backups in the text-(ASCII)-file format will get a file-extension of TX0, TX1, TX2, ..,
  110. TX9.
  111.  
  112. examples:
  113.  
  114.       showini /b c:\os2\os2.ini
  115.               ... make a backup, the resulting backup will be of type OS/2-INI,
  116.                   and will get a name of "c:\os2\os2.in0", ..., 
  117.                   "c:\os2\os2.in9"; generations are counted from 0 to 9;
  118.                   subsequent backups will cause the backup numbered with 0 to 
  119.                   be deleted, all others backups being renamed by subtracting
  120.                   one from their number, such that the backup to be generated
  121.                   will safely get the number 9 assigned.
  122.  
  123.       showini /bt os2sys.ini
  124.               ... make a backup of the OS/2-INI-file called "os2sys.ini" located
  125.                   in the actual drive and path, the resulting backup will be of
  126.                   type TEXT (ASCII), and will get a name of "d:\os2\os2sys.tx0",
  127.                   ..., "d:\os2\os2sys.tx9", **if** the present drive and path is
  128.                   "D:\OS2"; generations are counted from 0 to 9; subsequent
  129.                   backups will cause the backup numbered with 0 to be deleted,
  130.                   all others backups being renamed by subtracting one from their
  131.                   number, such that the backup to be generated will safely get
  132.                   the number 9 assigned.
  133.  
  134.  
  135. b) RESTORE
  136. ==========
  137.  
  138. syntax:
  139.  
  140.     showini /R backup-file
  141.     showini /RT backup-file
  142.  
  143. This will restore an OS/2-INI-file from the given backup-file, which is 
  144. **allways** located in the drive and subdirectory of the INI-file to be 
  145. restored.
  146.  
  147. Depending on the switch, /R or /RT, the backup file will be an OS/2-INI-file or 
  148. a plain text-(ASCII)-file.  SHOWINI.CMD will use the filename information stored 
  149. in the backup-file (in the case of an OS/2-INI-type backup, the original 
  150. filename is stored in the TopLevel-entry "RGF Showini.cmd"), ***but*** will 
  151. ignore the stored drive and path information, instead it will use the drive and 
  152. path (for security reasons) given in the command-line (i.e.  "backup-file") !!!  
  153.  
  154. If the text-backup-file (ASCII-file) contains blank lines or ones having a 
  155. semicolon (;) as the first character, they will be ignored. 
  156.  
  157. ***Attention*** In the restore-mode all keys not being in the backup-file but 
  158. existing in the INI-file will be ***deleted*** from the OS/2-INI-file, thereby 
  159. producing an exact copy of the backup ! If you do not want this behavior use the
  160. update-mode, which just updates the TopLevels and Keys found in the backup-file.
  161.  
  162. Hint: If you want to delete numerous keys or TopLevels, then make a text-backup 
  163. (switch "/BT") and either delete or remark those lines with the appropriate 
  164. entries and run a restore-operation (using any editor like EPM, which is my 
  165. preferred one).
  166.  
  167.  
  168. examples:
  169.  
  170.       showini /r d:\apps\mamamia.in9
  171.               ... restore the OS/2-INI-file located in "D:\APPS", get the name
  172.                   of it from the backup "mamamia.in9", if not found, then assume
  173.                   that the INI-file is called "MAMAMIA.INI"; restore the 
  174.                   INI-file from the backup, delete all TopLevels and keys in
  175.                   target which are not found in the backup. The backup is a true
  176.                   OS/2-INI-file and could therefore also be copied over the
  177.                   original OS/2-INI-file. Note: drive and path information 
  178.                   stored in the backup are ignored for security reasons.
  179.  
  180.       showini /rt papatuo.tx0
  181.               ... restore the OS/2-INI-file located in the actual drive and 
  182.                   subdirectory, get the name of it from the backup
  183.                   "papatuo.tx0". Restore the INI-file from the backup, delete
  184.                   all TopLevels and keys in target which are not found in the
  185.                   backup.  The backup is a TXT-(ASCII)-file.  Note:  drive and
  186.                   path information stored in the backup are ignored for security
  187.                   reasons.
  188.  
  189.  
  190. c) UPDATE
  191. =========
  192.  
  193. syntax:
  194.  
  195.     showini /U backup-file
  196.     showini /UT backup-file
  197.  
  198. This will update an OS/2-INI-file with the information from the given 
  199. backup-file, which is **allways** located in the drive and subdirectory of the 
  200. INI-file to be restored.  
  201.  
  202. Depending on the switch, /U or /UT, the backup file will be an OS/2-INI-file or
  203. a plain text-(ASCII)-file. SHOWINI.CMD will use the filename information stored in the
  204. backup-file (in the case of an OS/2-INI-type backup, the original filename is
  205. stored in the TopLevel-entry "RGF Showini.cmd"), ***but*** will ignore the 
  206. stored drive and path information, instead it will use the drive and path (for
  207. security reasons) given in the command-line (i.e.  "backup-file") !!!  
  208.  
  209.  
  210. If the text-backup-file (ASCII-file) contains blank lines or ones having a 
  211. semicolon (;) as the first character, they will be ignored. 
  212.  
  213. examples:
  214.  
  215.       showini /u g:\aha\ok\epm.in3
  216.               ... restore the OS/2-INI-file located in "G:\AHA\OK", get the name
  217.                   of it from the backup "epm.in3", if not found, then assume
  218.                   that the INI-file is called "EPM.INI"; restore the INI-file
  219.                   from the backup. In contrast to the restore mode, superfluous
  220.                   TopLevels and keys in the target are ***not*** deleted! The
  221.                   backup is a true OS/2-INI-file and could therefore also be
  222.                   copied over the original OS/2-INI-file.  Note:  drive and path
  223.                   information stored in the backup are ignored for security
  224.                   reasons.
  225.  
  226.       showini /ut klondike.tx9
  227.               ... restore the OS/2-INI-file located in the actual drive and 
  228.                   subdirectory, get the name of it from the backup
  229.                   "klondike.tx9", if not found, then assume that the INI-file is
  230.                   called "KLONDIKE.INI"; restore the INI-file from the backup,
  231.                   delete all TopLevels and keys in target which are not found 
  232.                   in the backup.  The backup is a TXT-(ASCII)-file.  Note: 
  233.                   drive and path information stored in the backup are ignored 
  234.                   for security reasons.
  235.  
  236.  
  237. 3) EXIT-codes
  238. =============
  239.  
  240.  0 ... everything went o.k.
  241. -1 ... user aborted program
  242. -2 ... wrong switch or invalid filename
  243. -3 ... invalid backup-file
  244.  
  245.  
  246. 4) minimal layout of text-(ASCII)-backup-files
  247. ==============================================
  248.  
  249.         ; a line starting with a semi-column is a comment and is ignored
  250.         ; blank lines are ignored as well
  251.  
  252.         ; the file entry must be included and be given before the TopLevel- and
  253.         ; key-entries; it may span multiple lines (for long filenames) and has
  254.         ; the principal layout
  255.         ;
  256.         ;          "File [file name]"
  257.         ; delimiter for the value is allways an opening and ending square 
  258.         ; bracket
  259.  
  260.         File  [D:\work\klondike.ini] 
  261.         
  262.         ; A TopLevel (application) entry starts with the keyword "Top"; is being
  263.         ; followed by the datatype [A], [A0] or [H] for ASCII, ASCII-Z, resp.
  264.         ; hexadecimal; the last entry is the value enclosed in square brackets.
  265.         ; 
  266.         ; The same syntax applies to the key-names ("Key") and finally to the
  267.         ; values themselves ("Val").
  268.         ;
  269.         ; Any Value for TopLevel-names, Key-names and Key-values may span 
  270.         ; multiple lines; if so, subsequent lines must not contain a key-word,
  271.         ; but the data-type and the value.
  272.  
  273.  
  274.         Top [A]  [PATIENCE]
  275.             Key  [A]  [CardBack]
  276.  
  277.         ; the key-value is of ASCII-string, terminated by \0; note that the 
  278.         ; terminating '00'x is not contained within the value part:
  279.  
  280.                  Val  [A0] [2]
  281.  
  282.         ; the following key-value spans two lines:
  283.  
  284.             Key  [A]  [ColorSet]
  285.                  Val  [A0] [13]
  286.                       [A0] [03]
  287.         
  288.         ; this is an example for hexadecimal values for all three, 
  289.         ;TopLevel-name, key-name and key-value:
  290.  
  291.         Top [H]  [01020304050607]
  292.             Key  [H]  [08091011]
  293.                  Val  [H]  [12131415]
  294.  
  295.         ; note values enclosed in the square-bracket-delimiters may contain
  296.         ; square brackets themselves:
  297.  
  298.         Top [A]  [This is another TopLevel-entry [yes, another]]
  299.             Key  [A]  [This is another key-entry]
  300.                  Val  [A]  [This is a plain ASCII-entry.]
  301.             Key  [A]  [This is the second key-entry, within this TopLevel.]
  302.                  Val  [A0] [This is an ASCII-Z entry.]
  303.  
  304. For further examples of the syntax of the text-(ASCII)-file see any printout or
  305. text-(ASCII)-backup.
  306.         
  307.  
  308. All rights reserved, copyrighted 1992, no guarantee that it works without
  309. errors, etc. etc.
  310.  
  311. donated to the public domain granted that you are not charging anything (money
  312. etc.) for it and derivates based upon it, as you did not write it,
  313. etc. if that holds you may bundle it with commercial programs too
  314.  
  315. you may freely distribute this program, granted that no changes are made
  316. to it
  317.  
  318. Please, if you find an error, post me a message describing it, I will
  319. try to fix and rerelease it to the net.
  320.  
  321. */
  322.  
  323. SIGNAL ON HALT
  324.  
  325. CALL initialize                 /* initialize array "global."           */
  326.  
  327. IF ARG() > 0 THEN               /* arguments are given */
  328.    CALL backup_restore_update ARG(1)
  329.  
  330. CALL show_inis                  /* show OS/2-INI-files                  */
  331. CALL write_ini_settings         /* write settings for this program      */
  332.  
  333. EXIT 0                          /* normal exit */
  334.  
  335. /****************************************************************/
  336.  
  337. INITIALIZE: PROCEDURE EXPOSE global.
  338.     /* check whether RxFuncs are loaded, if not, load them */
  339.     IF RxFuncQuery('SysLoadFuncs') THEN
  340.     DO
  341.         /* load the load-function */
  342.         CALL RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'       
  343.  
  344.         /* load the Sys* utilities */
  345.         CALL SysLoadFuncs                                                 
  346.     END
  347.  
  348.     /* define some ANSI.SYS-colors */
  349.     esc    = '1B'x          /* escape-char */
  350.     
  351.     global. = ""
  352.     
  353.     /* define ANSI-colors */
  354.     global.iRedWhite    = esc||"[31;47m"    /* ANSI.SYS-control for red foreground */
  355.     global.iYellow = esc||"[33;40m"    /* ANSI.SYS-control for yellow foreground */
  356.     global.iCyan   = esc||"[36;40m"    /* ANSI.SYS-control for cyan foreground */
  357.     global.iNormal = esc||"[0;40m"     /* ANSI.SYS-control for resetting attributes to normal */
  358.     global.iScrLength = LENGTH(global.iRedWhite)
  359.  
  360.     /* hint for options */
  361.     global.defaultHint = global.iCyan || "(" || global.iYellow || "default" || global.iCyan || ")"
  362.     /* hint for default yes or no */
  363.     global.yesHint = global.iCyan || " (" || global.iYellow || "Y" || global.iCyan || "/N) " || global.iYellow
  364.     global.noHint  = global.iCyan || " (Y/" || global.iYellow || "N" || global.iCyan || ") " || global.iYellow
  365.  
  366.     /* get screen dimensions */
  367.     PARSE VALUE SysTextScreenSize() WITH row columns
  368.     global.iRows = row
  369.     global.iColumns = columns
  370.     global.iBlankLine = global.iRedWhite || RIGHT("", columns - 1) || global.iCyan
  371.     
  372.     global.iNonPrintable = XRANGE("00"x, "1F"x) || D2C(255)
  373.     global.iFilter       = COPIES("FA"x, 256)
  374.  
  375.     /* define leadin for menus */
  376.     global.enterString = global.iCyan || "Enter:" global.iYellow || "1" || global.iCyan || "-" || global.iYellow
  377.  
  378.     /* define data-type strings */
  379.     global.dType.H        = "[H]"
  380.     global.dType.H.long   = "hexadecimal"
  381.     global.dType.A        = "[A]"
  382.     global.dType.A.long   = "ASCII"
  383.     global.dType.A0       = "[A0]"
  384.     global.dType.A0.long  = "ASCII delimited by \0"
  385.     global.dType.F        = "[F]"
  386.     global.dType.longest  = 4           /* length of "[A0]" */
  387.  
  388.     /* define leadins for printout */
  389.     global.format.forTop        = "Top "
  390.     global.format.forTop.Length = LENGTH(global.format.forTop)
  391.     global.format.forTop.LeadIn = COPIES(" ", global.format.forTop.Length) 
  392.     global.format.forKey        = "    Key  "
  393.     global.format.forKey.Length = LENGTH(global.format.forKey)
  394.     global.format.forKey.LeadIn = COPIES(" ", global.format.forKey.Length) 
  395.     global.format.forVal        = "         Val  "
  396.     global.format.forVal.Length = LENGTH(global.format.forVal)
  397.     global.format.forVal.LeadIn = COPIES(" ", global.format.forVal.Length) 
  398.  
  399.  
  400.     /* define information for Level of depth */
  401.     global.depthOfOutput.T = "TopLevels only"
  402.     global.depthOfOutput.K = "TopLevels + Keys"
  403.     global.depthOfOutput.V = "TopLevels + Keys + Key-Values"
  404.  
  405.     /* define information for range of printout */
  406.     global.rangeOfPrintout.AI   = "ALL OS/2-INI-files in hand"
  407.     global.rangeOfPrintout.AT   = "ALL TopLevel-entries"
  408.     global.rangeOfPrintout.AK   = "ONE TopLevel-entry, ALL keys"
  409.     global.rangeOfPrintout.K    = "ONE Key"
  410.  
  411.     /* define information for output type, if hexadecimal value in hand */
  412.     global.hextypeOfOutput.H = "hexadecimal-string only"
  413.     global.hextypeOfOutput.F = "filtered ASCII-string only"
  414.     global.hextypeOfOutput.B = "both, hexadecimal- and filtered ASCII-string"
  415.  
  416.  
  417.     /* get defaults from previous settings of user from USER ("OS2.INI") */
  418.     global.config.showTopLevel      = "RGF Showini.cmd"   /* TopLevel name for this application */
  419.     global.config.add.indTopLevel   = 0         /* configuration defaults */
  420.     global.config.add.indKey        = 0         /* configuration defaults */
  421.     global.config.change.indKey     = 0         /* configuration defaults */
  422.     global.config.delete.indAllKeys = 0         /* configuration defaults */
  423.     global.config.delete.indKey     = 0         /* configuration defaults */
  424.     global.config.move.indAllKeys   = 0         /* configuration defaults */
  425.     global.config.move.indKey       = 0         /* configuration defaults */
  426.     global.config.copy.indAllKeys   = 0         /* configuration defaults */
  427.     global.config.copy.indKey       = 0         /* configuration defaults */
  428.     CALL read_ini_settings                      /* read previous values from USER */
  429.     CALL check_option_set                       /* show configuration option ? */
  430.  
  431.     /* Keys for backup-entries into USER resp. backup */
  432.     global.bkp.iOName      = "backup.info1.origName"
  433.     global.bkp.iBName      = "backup.info2.bkpName"
  434.     global.bkp.iTLentries  = "backup.info3.# of TopLevels"
  435.     global.bkp.iDTimeStart = "backup.info4.date/time.start"
  436.     global.bkp.iDTimeEnd   = "backup.info5.date/time.end"
  437.  
  438.     RETURN
  439.  
  440. /*
  441.    check whether configuration-option should be displayed
  442. */
  443. CHECK_OPTION_SET: PROCEDURE EXPOSE global.
  444.     /* if any of the options are set, show configuration option in first menu */
  445.     global.showConfigure = global.config.add.indTopLevel | global.config.add.indKey | global.config.change.indKey |,
  446.                            global.config.delete.indAllKeys | global.config.delete.indKey | global.config.move.indAllKeys |,
  447.                            global.config.move.indKey | global.config.copy.indAllKeys | global.config.copy.indKey          
  448.     RETURN
  449.  
  450.  
  451. /* 
  452.    read settings stored in OS2.INI and define default settings
  453. */
  454. READ_INI_SETTINGS: PROCEDURE EXPOSE global.
  455.  
  456.     tmp = SysIni("USER", global.config.showTopLevel,"add.TopLevel")
  457.     IF tmp <>"ERROR:" THEN global.config.add.indTopLevel = tmp
  458.  
  459.     tmp = SysIni("USER", global.config.showTopLevel,"add.Key")
  460.     IF tmp <>"ERROR:" THEN global.config.add.indKey = tmp
  461.  
  462.     tmp = SysIni("USER", global.config.showTopLevel,"change.Key")
  463.     IF tmp <>"ERROR:" THEN global.config.change.indKey = tmp
  464.  
  465.  
  466.     tmp = SysIni("USER", global.config.showTopLevel,"delete.AllKeys")
  467.     IF tmp <>"ERROR:" THEN global.config.delete.indAllKeys  = tmp
  468.  
  469.     tmp = SysIni("USER", global.config.showTopLevel,"delete.Key")
  470.     IF tmp <>"ERROR:" THEN global.config.delete.indKey  = tmp
  471.  
  472.     tmp = SysIni("USER", global.config.showTopLevel,"move.AllKeys")
  473.     IF tmp <>"ERROR:" THEN global.config.move.indAllKeys = tmp
  474.  
  475.     tmp = SysIni("USER", global.config.showTopLevel,"move.Key")
  476.     IF tmp <>"ERROR:" THEN global.config.move.indKey = tmp
  477.  
  478.     tmp = SysIni("USER", global.config.showTopLevel,"copy.AllKeys")
  479.     IF tmp <>"ERROR:" THEN global.config.copy.indAllKeys = tmp
  480.  
  481.     tmp = SysIni("USER", global.config.showTopLevel,"copy.Key")
  482.     IF tmp <>"ERROR:" THEN global.config.copy.indKey = tmp
  483.  
  484.  
  485.     tmp = SysIni("USER", global.config.showTopLevel, "showDepth")
  486.     IF tmp <> "ERROR:" THEN global.config.showDepth = tmp
  487.                        ELSE global.config.showDepth = "K"      /* default: TopLevels + Keys to show in output */
  488.  
  489.     tmp = SysIni("USER", global.config.showTopLevel, "showHexAs")
  490.     IF tmp <> "ERROR:" THEN global.config.showHexAs = tmp
  491.                        ELSE global.config.showHexAs = "H"      /* default: show them as hexadecimal-string */
  492.  
  493.     tmp = SysIni("USER", global.config.showTopLevel, "showLineLength")
  494.     IF tmp <> "ERROR:" THEN global.config.showLineLength = tmp
  495.  
  496.     IF tmp = "ERROR:" | tmp < "40" THEN
  497.        global.config.showLineLength = 120
  498.  
  499.     global.old.config.add.indTopLevel   = global.config.add.indTopLevel    
  500.     global.old.config.add.indKey        = global.config.add.indKey         
  501.     global.old.config.change.indKey     = global.config.change.indKey      
  502.     global.old.config.delete.indAllKeys = global.config.delete.indAllKeys  
  503.     global.old.config.delete.indKey     = global.config.delete.indKey      
  504.     global.old.config.move.indAllKeys   = global.config.move.indAllKeys    
  505.     global.old.config.move.indKey       = global.config.move.indKey        
  506.     global.old.config.copy.indAllKeys   = global.config.copy.indAllKeys    
  507.     global.old.config.copy.indKey       = global.config.copy.indKey        
  508.     global.old.config.showDepth         = global.config.showDepth
  509.     global.old.config.showHexAs         = global.config.showHexAs
  510.     global.old.config.showLineLength    = global.config.showLineLength
  511.  
  512.     RETURN
  513.  
  514.  
  515. /* 
  516.    write settings into OS2.INI, if values were changed
  517. */
  518. WRITE_INI_SETTINGS: PROCEDURE EXPOSE global.
  519.  
  520.     IF global.old.config.add.indTopLevel   <> global.config.add.indTopLevel    THEN
  521.        CALL SysIni"USER", global.config.showTopLevel,"add.TopLevel", global.config.add.indTopLevel
  522.  
  523.     IF global.old.config.add.indKey        <> global.config.add.indKey         THEN
  524.        CALL SysIni"USER", global.config.showTopLevel,"add.Key", global.config.add.indKey
  525.  
  526.     IF global.old.config.change.indKey     <> global.config.change.indKey      THEN
  527.        CALL SysIni"USER", global.config.showTopLevel,"change.Key", global.config.change.indKey
  528.  
  529.     IF global.old.config.delete.indAllKeys <> global.config.delete.indAllKeys  THEN
  530.        CALL SysIni"USER", global.config.showTopLevel,"delete.AllKeys", global.config.delete.indAllKeys
  531.  
  532.     IF global.old.config.delete.indKey     <> global.config.delete.indKey      THEN
  533.        CALL SysIni"USER", global.config.showTopLevel,"delete.Key", global.config.delete.indKey
  534.  
  535.     IF global.old.config.move.indAllKeys   <> global.config.move.indAllKeys    THEN
  536.        CALL SysIni"USER", global.config.showTopLevel,"move.AllKeys", global.config.move.indAllKeys
  537.  
  538.     IF global.old.config.move.indKey       <> global.config.move.indKey        THEN
  539.        CALL SysIni"USER", global.config.showTopLevel,"move.Key", global.config.move.indKey
  540.  
  541.     IF global.old.config.copy.indAllKeys   <> global.config.copy.indAllKeys    THEN
  542.        CALL SysIni"USER", global.config.showTopLevel,"copy.AllKeys", global.config.copy.indAllKeys
  543.  
  544.     IF global.old.config.copy.indKey       <> global.config.copy.indKey        THEN
  545.        CALL SysIni"USER", global.config.showTopLevel,"copy.Key", global.config.copy.indKey
  546.  
  547.  
  548.     IF global.old.config.showDepth <> global.config.showDepth THEN
  549.        CALL SysIni "USER", global.config.showTopLevel, "showDepth", global.config.showDepth 
  550.  
  551.     IF global.old.config.showHexAs <> global.config.showHexAs THEN
  552.        CALL SysIni "USER", global.config.showTopLevel, "showHexAs", global.config.showHexAs 
  553.  
  554.     IF global.old.config.showLineLength <> global.config.showLineLength THEN
  555.        CALL SysIni "USER", global.config.showTopLevel, "showLineLength", global.config.showLineLength 
  556.     RETURN
  557.  
  558.  
  559.  
  560. /*
  561.    show argument, if any, &
  562.    get yes/no answer
  563. */
  564. GET_YES_NO: PROCEDURE EXPOSE global.
  565.     IF ARG(1) <> "" THEN
  566.        CALL CHAROUT , ARG(1)
  567.  
  568.     CALL CHAROUT , global.iYellow
  569.     answer = get_answer("QYN")
  570.     CALL CHAROUT , global.iCyan
  571.  
  572.     SELECT
  573.        WHEN answer = "Q"   THEN SIGNAL halt
  574.        WHEN answer = "1B"x THEN RETURN 0                /* abort module */
  575.        WHEN answer = ""    THEN NOP                     /* do not change value */
  576.        OTHERWISE 
  577.             INTERPRET ARG(2) " = (answer = 'Y')"
  578.     END  
  579.     RETURN 1            /* everything went o.k. */
  580.  
  581. /*
  582.    allow changing the settings for menus
  583. */
  584. SETTINGS_MENU: PROCEDURE EXPOSE global.
  585.     SAY
  586.     SAY
  587.     SAY "Settings for menu abilities:"
  588.     SAY
  589.  
  590.     tmp = "Allow adding a new TopLevel entry ?"
  591.     IF global.config.add.indTopLevel THEN tmp = tmp global.yesHint
  592.                                      ELSE tmp = tmp global.noHint
  593.     IF \get_yes_no(tmp, "global.config.add.indTopLevel") THEN
  594.        RETURN
  595.     SAY
  596.  
  597.     tmp = "Allow deleting ALL Keys in a TopLevel (= deleting a TopLevel) ?"
  598.     IF global.config.delete.indAllKeys THEN tmp = tmp global.yesHint
  599.                                        ELSE tmp = tmp global.noHint
  600.     IF \get_yes_no(tmp, "global.config.delete.indAllKeys") THEN
  601.        RETURN
  602.  
  603.     tmp = "Allow moving ALL Keys to another TopLevel ?"
  604.     IF global.config.move.indAllKeys THEN tmp = tmp global.yesHint
  605.                                      ELSE tmp = tmp global.noHint
  606.     IF \get_yes_no(tmp, "global.config.move.indAllKeys") THEN
  607.        RETURN
  608.  
  609.     tmp = "Allow copying ALL Keys to another TopLevel ?"
  610.     IF global.config.copy.indAllKeys THEN tmp = tmp global.yesHint
  611.                                      ELSE tmp = tmp global.noHint
  612.     IF \get_yes_no(tmp, "global.config.copy.indAllKeys") THEN
  613.        RETURN
  614.  
  615.     SAY
  616.  
  617.  
  618.  
  619.  
  620.     tmp = "Allow adding a new Key entry ?"
  621.     IF global.config.add.indKey THEN tmp = tmp global.yesHint
  622.                                 ELSE tmp = tmp global.noHint
  623.     IF \get_yes_no(tmp, "global.config.add.indKey") THEN
  624.        RETURN
  625.  
  626.     tmp = "Allow deleting a single Key ?"
  627.     IF global.config.delete.indKey THEN tmp = tmp global.yesHint
  628.                                    ELSE tmp = tmp global.noHint
  629.     IF \get_yes_no(tmp, "global.config.delete.indKey") THEN
  630.        RETURN
  631.  
  632.     tmp = "Allow moving a single Key ?"
  633.     IF global.config.move.indKey THEN tmp = tmp global.yesHint
  634.                                  ELSE tmp = tmp global.noHint
  635.     IF \get_yes_no(tmp, "global.config.move.indKey") THEN
  636.        RETURN
  637.  
  638.     tmp = "Allow copying a single Key ?"
  639.     IF global.config.copy.indKey THEN tmp = tmp global.yesHint
  640.                                  ELSE tmp = tmp global.noHint
  641.     IF \get_yes_no(tmp, "global.config.copy.indKey") THEN
  642.        RETURN
  643.  
  644.     tmp = "Allow changing (editing) a Key value ?"
  645.     IF global.config.change.indKey THEN tmp = tmp global.yesHint
  646.                                    ELSE tmp = tmp global.noHint
  647.     IF \get_yes_no(tmp, "global.config.change.indKey") THEN
  648.        RETURN
  649.  
  650.  
  651.     RETURN
  652.  
  653.  
  654.  
  655.  
  656. /*
  657.    allow changing the settings for printout
  658. */
  659. SETTINGS_PRINTOUT: PROCEDURE EXPOSE global.
  660.     SAY
  661.     SAY "Settings for formatting the printout:"
  662.     SAY
  663.  
  664.     /* how much information should be produced ? */
  665.     SAY global.iCyan || "How much information to include in output:" global.iYellow
  666.     SAY
  667.     choice = ""
  668.  
  669.     tmp = "       " global.iYellow || "T" global.iCyan global.depthOfOutput.T
  670.     IF global.config.showDepth = "T" THEN 
  671.        tmp = tmp global.defaultHint
  672.     SAY  tmp
  673.  
  674.     /* if no previous preferences, then this is the default */
  675.     tmp = "       " global.iYellow || "K" global.iCyan global.depthOfOutput.K
  676.     IF global.config.showDepth = "K" THEN 
  677.        tmp = tmp global.defaultHint
  678.     SAY tmp
  679.  
  680.     tmp = "       " global.iYellow || "V" global.iCyan global.depthOfOutput.V
  681.     IF global.config.showDepth = "V" THEN 
  682.        tmp = tmp global.defaultHint
  683.     SAY tmp
  684.  
  685.     SAY "       " global.iCyan   || "   [Esc] to return"
  686.  
  687.     /* define choices and get answer from user */
  688.     CALL CHAROUT , global.iYellow
  689.     answer = get_answer(choice || "TKVQ")
  690.     CALL CHAROUT , global.iCyan
  691.  
  692.     SELECT
  693.        WHEN answer = "1B"x THEN RETURN    /* Escape was pressed */
  694.        WHEN answer = "Q" THEN SIGNAL halt
  695.        WHEN answer = "" THEN NOP          /* do not change present setting */
  696.        OTHERWISE global.config.showDepth = answer
  697.     END  
  698.  
  699.     /* should hex value be presented additionally with a filtered ASCII-string ? */
  700.  
  701.     SAY global.iCyan || "hexadecimal values should be showed as:"
  702.     SAY
  703.     tmp = "       " global.iYellow || "H" global.iCyan global.hextypeOfOutput.H
  704.     IF global.config.showHexAs = "H" THEN
  705.        tmp = tmp global.defaultHint
  706.     SAY tmp
  707.  
  708.     tmp = "       " global.iYellow || "F" global.iCyan global.hextypeOfOutput.F
  709.     IF global.config.showHexAs = "F" THEN
  710.        tmp = tmp global.defaultHint
  711.     SAY tmp
  712.  
  713.     tmp = "       " global.iYellow || "B" global.iCyan global.hextypeOfOutput.B
  714.     IF global.config.showHexAs = "B" THEN
  715.        tmp = tmp global.defaultHint
  716.     SAY tmp
  717.  
  718.     SAY "       " global.iCyan   || "   [Esc] to return"
  719.  
  720.     /* define choices and get answer from user */
  721.     CALL CHAROUT , global.iYellow
  722.     answer = get_answer("HFBQ")
  723.     CALL CHAROUT , global.iCyan
  724.  
  725.     SELECT
  726.        WHEN answer = "1B"x THEN RETURN
  727.        WHEN answer = ""    THEN NOP
  728.        WHEN answer = "Q"   THEN SIGNAL halt
  729.        OTHERWISE global.config.showHexAs = answer       /* assign new value */
  730.     END
  731.  
  732.  
  733.     /* get desired line-length */
  734.     DO FOREVER
  735.        SAY global.iCyan || "How many characters per line (" || global.iYellow || global.config.showLineLength || global.iCyan "default, 40 minimum) ? " global.iYellow
  736.        /* define choices and get answer from user */
  737.        CALL CHAROUT , global.iYellow
  738.        answer = get_answer("Q", "999999")
  739.        CALL CHAROUT , global.iCyan
  740.  
  741.        SELECT
  742.           WHEN answer = "Q"   THEN SIGNAL halt
  743.           WHEN answer = "1B"x THEN RETURN
  744.           WHEN answer = ""    THEN LEAVE        /* do not change setting */
  745.           OTHERWISE
  746.                IF answer >= 40 THEN          /* minimum line-length >= 40 characters */
  747.                DO
  748.                   global.config.showLineLength = answer  /* new value */
  749.                   LEAVE
  750.                END
  751.        END  
  752.  
  753.        SAY
  754.        CALL error_msg "A minimum line-length of 40 characrters is required !", "come back"
  755.        SAY
  756.        SAY "please retry."
  757.        SAY
  758.     END
  759.  
  760.     RETURN
  761.  
  762.  
  763.  
  764.  
  765. /* 
  766.    determine largest entry
  767. */
  768. LARGEST_GENERIC: PROCEDURE EXPOSE global. stemIni. stemTopLevel. stemKey.
  769.     largest = 0
  770.     dynCode =         "DO i = 1 TO" ARG(1) || ".0;"
  771.     dynCode =         dynCode "largest = MAX(largest, LENGTH(" ARG(1) || ".i));"
  772.     dynCode = dynCode "END;"
  773.     dynCode = dynCode ARG(1) || ".iLargest = MIN(largest, (global.iColumns - (2+ LENGTH(" || ARG(1) || ".0))))"
  774.     INTERPRET dynCode                /* execute REXX-code in variable dynCode */
  775.  
  776.     RETURN 
  777.  
  778.  
  779. /* 
  780.   display stem-contents on screen
  781. */
  782. SHOW_GENERIC: PROCEDURE EXPOSE global. stemIni. stemTopLevel. stemKey.
  783.     stemName = ARG(1)
  784.  
  785.     tmpANSILength = global.iScrLength * 2       /* length of the two ANSI-color control chars */
  786.  
  787.     dyncode =         "nrLength = LENGTH(" || stemName || ".0);"
  788.     dyncode = dyncode "columns = global.iColumns % (" || stemName || ".iLargest + nrLength + 2);"
  789.  
  790.     dyncode = dyncode "IF columns < 1 THEN columns = 1;"
  791.  
  792.     dynCode = dyncode "j = (" || stemName || ".0 + columns - 1) % columns;"
  793.  
  794.     dynCode = dynCode "DO i = 1 TO j;"
  795.     dynCode = dynCode "   tmp = '';" 
  796.     dynCode = dynCode "   DO k = 1 TO columns;" /*  m = (i - 1) * columns + k    /* order in lines */ */
  797.     dynCode = dynCode "       m = (k - 1) * j + i;"
  798.     dynCode = dynCode "       IF " stemName || ".m <> '' THEN;"
  799.     dynCode = dynCode "       tmp = tmp LEFT((global.iCyan || RIGHT(m, nrLength) global.iYellow || "stemName ||".m), (" stemName || ".iLargest + nrLength + 1 + tmpANSILength));"
  800.     dynCode = dynCode "    END;" 
  801.     dynCode = dynCode "    CALL CHAROUT , tmp;"
  802.     dynCode = dyncode "    IF (LENGTH(tmp) - tmpANSILength * columns) < global.iColumns THEN SAY;"
  803.  
  804.     dynCode = dyncode "END"
  805.  
  806.     INTERPRET dynCode
  807.  
  808.     RETURN
  809.  
  810.  
  811.  
  812. /* 
  813.    one of Knuth's algorithms to sort
  814.    ARG(1) ... stemname of array to sort
  815.    ARG(2) ... optional, if given, exact comparison (no forced uppercase), taking leading
  816.               and trailing blanks into account
  817. */
  818. SORT_GENERIC: PROCEDURE EXPOSE stemIni. stemTopLevel. stemKey. stemTargetTopLevel. stemTargetKey.
  819.  
  820.    /* define M for passes, build REXX-code */
  821.    dynCode = "M = 1; DO WHILE (9 * M + 4) <" ARG(1) || ".0 ; M = M * 3 + 1; END"
  822.    INTERPRET dynCode                /* execute REXX-code in variable dynCode */
  823.  
  824.    /* sort stem, build REXX-code */
  825.    dynCode = "DO WHILE M > 0; K = " ARG(1) || ".0 - M; DO J = 1 TO K; Q = J;"
  826.    dynCode = dynCode "DO WHILE Q > 0; L = Q + M;"
  827.  
  828.    IF ARG() < 2 THEN    /* uppercase comparison, ignore leading and trailing blanks */
  829.       dynCode = dynCode "IF TRANSLATE(" || ARG(1) || ".Q) <= TRANSLATE(" || ARG(1) || ".L) THEN LEAVE;"
  830.    ELSE                 /* exact comparison */ 
  831.       dynCode = dynCode "IF" ARG(1) || ".Q <<=" ARG(1) || ".L THEN LEAVE;"
  832.  
  833.    dynCode = dynCode "tmp =" ARG(1) || ".Q; tmp.origValue =" ARG(1) || ".Q.origValue;"
  834.    dynCode = dynCode "tmp.type =" ARG(1) || ".Q.type; tmp.filterValue =" ARG(1) || ".Q.filterValue;"
  835.  
  836.    dynCode = dynCode ARG(1) || ".Q =" ARG(1) || ".L;" ARG(1) || ".Q.origValue =" ARG(1) || ".L.origValue;"
  837.    dynCode = dynCode ARG(1) || ".Q.type =" ARG(1) || ".L.type;" ARG(1) || ".Q.filterValue =" ARG(1) || ".L.filterValue;"
  838.  
  839.    dynCode = dynCode ARG(1) || ".L = tmp;" ARG(1) || ".L.origValue = tmp.origValue;"
  840.    dynCode = dynCode ARG(1) || ".L.type = tmp.type;" ARG(1) || ".L.filterValue  = tmp.filterValue;"
  841.  
  842.    dynCode = dynCode "Q = Q - M; END; END; M = M % 3; END"
  843.  
  844.    INTERPRET dynCode                /* execute REXX-code in variable dynCode */
  845.  
  846.    RETURN
  847.  
  848.  
  849. /*
  850.     get answer from user, if a 3rd argument is supplied, then force an entry
  851.     ARG(1) ... string of valid letters
  852.     ARG(2) ... upper bound of an arithmetic value
  853.     ARG(3) ... if given, force user to enter at least one character
  854. */
  855. GET_ANSWER: PROCEDURE EXPOSE global.
  856.     validLetters = ARG(1)
  857.     upperBound   = ARG(2)       /* 0 - upperBound */
  858.  
  859.     i = 0
  860.     answer = ""
  861.  
  862.     DO FOREVER
  863.        tmp = TRANSLATE(SysGetKey("noecho"))
  864.  
  865.        IF tmp = "0D"x THEN                      /* CR-was pressed */
  866.        DO
  867.           IF ARG(3) = "" | i > 0 THEN LEAVE
  868.           CALL BEEP 2000, 250
  869.           ITERATE
  870.        END
  871.  
  872.        IF tmp = "1B"x THEN                      /* Escape was pressed */
  873.        DO
  874.           answer = tmp
  875.           LEAVE
  876.        END
  877.  
  878.        IF tmp = "08"x THEN                      /* Backspace was pressed */
  879.        DO
  880.           IF i = 0 THEN                         /* already at first position */
  881.           DO
  882.              CALL BEEP 2000, 250
  883.              ITERATE
  884.           END
  885.  
  886.           CALL CHAROUT , tmp                    /* backspace */
  887.           CALL CHAROUT , " "                    /* erase character */
  888.           CALL CHAROUT , tmp
  889.           i = i - 1
  890.  
  891.           IF i = 0 THEN answer = ""             /* adjust value of answer */
  892.           ELSE answer = SUBSTR(answer, 1, i)
  893.  
  894.           ITERATE
  895.        END
  896.  
  897.        IF POS(tmp, validLetters) > 0 THEN
  898.        DO
  899.           IF answer = "" THEN
  900.           DO
  901.              answer = tmp
  902.              CALL CHAROUT , answer
  903.              LEAVE
  904.           END
  905.  
  906.           CALL BEEP 2000, 250
  907.           ITERATE
  908.        END
  909.  
  910.        IF upperBound <> "" THEN
  911.        DO
  912.           IF i = 0 THEN
  913.           DO
  914.              IF POS(tmp, "0123456789") > 0 & tmp <= upperBound THEN
  915.              DO
  916.                 CALL CHAROUT , tmp
  917.                 answer = tmp
  918.                 i = i + 1
  919.                 IF answer = 0 | LENGTH(upperBound) = 1 | (answer || "0" > upperBound) THEN LEAVE
  920.                 ITERATE
  921.              END
  922.           END
  923.           ELSE
  924.           DO
  925.              IF POS(tmp, "0123456789") > 0 THEN
  926.              DO
  927.                 IF answer || tmp <= upperBound THEN
  928.                 DO
  929.                    CALL CHAROUT , tmp 
  930.                    answer = answer || tmp
  931.                    i = i + 1
  932.    
  933.                    IF LENGTH(answer) = LENGTH(upperBound) | (answer || "0" > upperBound) THEN LEAVE
  934.                    ITERATE
  935.                 END
  936.              END
  937.           END
  938.        END
  939.  
  940.        CALL BEEP 2000, 250
  941.     END
  942.     SAY
  943.  
  944.     RETURN answer
  945.  
  946.  
  947. /* supply defaults */
  948. INI_DEFAULT: PROCEDURE EXPOSE stemIni. global.
  949.     DROP stemIni.
  950.     stemIni.   = ""
  951.  
  952.     IF ARG(1) = "1" THEN        /* show user INI-names themselves */
  953.     DO
  954.        stemIni.1 = "USER (OS2.INI)"   /* OS2.INI */
  955.        stemIni.2 = "SYSTEM (OS2SYS.INI)"/* OS2SYS.INI */
  956.     END
  957.     ELSE
  958.     DO
  959.        stemIni.1 = "USER"               /* OS2.INI */
  960.        stemIni.2 = "SYSTEM"             /* OS2SYS.INI */
  961.     END
  962.  
  963.     stemIni.0 = 2                       /* number of elements in array */
  964.  
  965. /*
  966. /* debug */
  967. stemIni.3 = "D:\work\klondike.ini"
  968. stemIni.0 = 3
  969. */
  970.  
  971.     CALL largest_generic("stemIni")
  972.     RETURN
  973.  
  974.  
  975.  
  976. SEARCH_INI: PROCEDURE EXPOSE global. stemIni.
  977.     SAY
  978.     SAY global.iCyan || "Enter:"
  979.     SAY
  980.     SAY "       " global.iYellow "1" global.iCyan " to scan all attached drives" global.defaultHint
  981.     SAY "       " global.iYellow "2" global.iCyan " to scan all local drives"
  982.     SAY "       " global.iYellow "3" global.iCyan " to scan remote drives"
  983.     SAY "       " global.iYellow "->" global.iCyan 'or any valid drive letter from "' || global.iYellow || 'A' || global.iCyan || '"-"' || global.iYellow || 'Z' || global.iCyan || '"'
  984.  
  985.     /* allow for choices 1-3 and drive letters A-Z */
  986.     CALL CHAROUT , global.iYellow
  987.     answer = get_answer("123ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  988.     CALL CHAROUT , global.iCyan
  989.  
  990.     SELECT
  991.        WHEN answer = "1B"x THEN                 /* user aborted, return unchanged array */
  992.             RETURN 
  993.        WHEN answer = "1" | answer = "" THEN
  994.              map = SysDriveMap(, "USED")        /* get a list of all used drives */
  995.        WHEN answer = "2" THEN
  996.              map = SysDriveMap(, "LOCAL")       /* get a list of all local drives */
  997.        WHEN answer = "3" THEN
  998.              map = SysDriveMap(, "REMOTE")      /* get a list of all remote drives */
  999.        OTHERWISE
  1000.              map = answer || ":"                /* drive - letter */
  1001.     END  
  1002.  
  1003.     /* drop existing array */
  1004.     DROP stemIni.
  1005.     stemIni.  = ""
  1006.     stemIni.0 = 0
  1007.  
  1008.     DO WHILE map <> ""
  1009.        PARSE VAR map drive map
  1010.  
  1011.        SAY "scanning drive" global.iYellow ||drive||global.iCyan "for accessible INI-files..."
  1012.        CALL SysFileTree drive || "\*.ini", "file", "FSO"
  1013.  
  1014.        DO i = 1 TO file.0
  1015.           /* check whether accessible from OS/2, i.e. an OS/2 INI-file */
  1016.           ok = SysIni(file.i, 'ALL:', 'TopLevel')
  1017.           IF ok <> "ERROR:" & TopLevel.0 > 0 THEN
  1018.           DO
  1019.              SAY "     file" global.iYellow || file.i || global.iCyan "found..."
  1020.              stemIni.0 = stemIni.0 + 1
  1021.              j = stemIni.0
  1022.              stemIni.j = file.i
  1023.           END
  1024.        END
  1025.        SAY 
  1026.     END
  1027.  
  1028.     CALL largest_generic("stemIni")
  1029.     RETURN 
  1030.  
  1031.  
  1032. /* 
  1033.         Display INI-files which are accessible
  1034. */
  1035. SHOW_INIS: PROCEDURE EXPOSE global. stemIni. stemTopLevel. stemKey.
  1036.  
  1037.    stemIni.0 = 0        /* no INI-files initially, setup */
  1038.  
  1039.    DO FOREVER
  1040.       IF WORD(stemIni.1, 1) = "USER" | stemIni.0 = 0 THEN
  1041.          CALL ini_default("1")     /* show file-names of system-INIs */
  1042.  
  1043.       SAY
  1044.       SAY global.iRedWhite || CENTER("accessible OS/2-INI-files", global.iColumns) || global.iCyan
  1045.       SAY 
  1046.       SAY global.iCyan'The following' global.iYellow || stemIni.0 global.iCyan'OS/2 INI-files are accessible:'
  1047.       SAY
  1048.  
  1049.       CALL show_generic "stemIni"      /* show stem contents */
  1050.  
  1051.       IF WORD(stemIni.1, 1) = "USER" THEN       /* if initial settings, then */
  1052.          CALL ini_default                       /* get symbolic-names only for RxUtils-functions */
  1053.  
  1054.       SAY
  1055.       tmp = global.enterString || stemIni.0 global.iCyan || 'to view INI-file,',
  1056.             global.iYellow || '0' || global.iCyan 'to end;',
  1057.             global.iYellow || 's' || global.iCyan || 'can drive[s] for INI-files,',
  1058.             global.iYellow || 'p' || global.iCyan || 'rint all INI-files'
  1059.  
  1060.       IF global.showConfigure THEN              /* show configuration option ? */
  1061.           tmp = tmp || ", " ||  global.iYellow || 'c' || global.iCyan || 'onfigure'
  1062.  
  1063.       SAY tmp
  1064.  
  1065.       /* define choices and upper numeric boundary and get answer from user */
  1066.       CALL CHAROUT , global.iYellow
  1067.       answer = get_answer("PQCS", stemIni.0)
  1068.       CALL CHAROUT , global.iCyan
  1069.       SAY
  1070.  
  1071.       SELECT
  1072.          WHEN answer = "" | answer = 0 | answer = "1B"x THEN LEAVE
  1073.  
  1074.          WHEN answer = "Q" THEN SIGNAL halt
  1075.    
  1076.          WHEN answer = "C" THEN         /* configure program */
  1077.               DO
  1078.                  CALL settings_printout
  1079.                  CALL settings_menu
  1080.                  CALL check_option_set  /* show configuration option ? */
  1081.               END
  1082.    
  1083.          WHEN answer = 'S' THEN         /* search for all OS/2-INI-files */
  1084.                CALL search_ini
  1085.                                        
  1086.          WHEN answer = 'P' THEN         /* print all OS/2-INI-files */
  1087.               CALL print
  1088.  
  1089.          OTHERWISE                      /* display top-levels of chosen INI-file */
  1090.               DO
  1091.                  CALL show_toplevel answer
  1092.                  SAY
  1093.               END
  1094.       END  
  1095.       SAY
  1096.       SAY
  1097.    END
  1098.    SAY global.iNormal
  1099.    RETURN
  1100.  
  1101.  
  1102. /*
  1103.         read TopLevel-entries
  1104. */
  1105. READ_TOPLEVEL: PROCEDURE EXPOSE stemIni. stemTopLevel. stemKey. global. 
  1106.     DROP stemTopLevel.
  1107.     stemTopLevel. = ""
  1108.  
  1109.     iIni = ARG(1)
  1110.     ok = SysIni(stemIni.iIni, 'ALL:', 'stemTopLevel')
  1111.     IF ok = "ERROR:" THEN
  1112.     DO
  1113.        stemTopLevel.0 = 0
  1114.     END
  1115.     ELSE
  1116.     DO i = 1 TO stemTopLevel.0
  1117.        CALL check_value stemTopLevel.i  /* determine and prepare value in hand */
  1118.        stemTopLevel.i.origValue   = stemTopLevel.i
  1119.        stemTopLevel.i             = strings.displayValue
  1120.        stemTopLevel.i.type        = strings.type
  1121.        stemTopLevel.i.filterValue = strings.filterValue
  1122.     END
  1123.  
  1124.     CALL largest_generic("stemTopLevel")
  1125.     RETURN 
  1126.  
  1127.  
  1128. /*
  1129.    ask for new TopLevel-name,
  1130.    return name, if it does not exist, NULL-string if it exists
  1131. */
  1132. CREATE_NEW_TOPLEVEL: PROCEDURE EXPOSE global. stemIni.
  1133.     iniName = VALUE("stemIni." || ARG(1))
  1134.  
  1135.     PARSE VALUE edit_value("A", "new Top-Level-name ('Application'):", , "H A", "Enter new Top-Level-Name") WITH tmpState tmpResult
  1136.  
  1137.     IF tmpState = "NOK" THEN RETURN ""          /* user aborted entry */
  1138.  
  1139.     /* check whether Top-Level exists already */
  1140.     ok = SysIni(iniName, tmpResult, 'ALL:', 'stemKey')
  1141.  
  1142.     IF ok <> "ERROR:" THEN
  1143.     DO
  1144.        CALL check_value tmpResult
  1145.        CALL error_msg "TopLevel:" || global.iCyan "[" || global.iYellow || strings.displayValue || global.iCyan || "]" global.iRedWhite || "exists already !"
  1146.        RETURN ""
  1147.     END
  1148.  
  1149.     RETURN tmpResult
  1150.  
  1151.  
  1152. /*
  1153.    ask for new Key-name,
  1154.    return name, if it does not exist, NULL-string if it exists
  1155. */
  1156. CREATE_NEW_KEY: PROCEDURE EXPOSE global. stemIni. stemTopLevel.
  1157.     iniName = ARG(1)                            /* INI-name */
  1158.     topName = ARG(2)                            /* Top Level name */
  1159.  
  1160.     PARSE VALUE edit_value("A", "new Key-name:", , "H A", "Enter new Key-Name") WITH tmpState tmpResult
  1161.  
  1162.     IF tmpState = "NOK" THEN RETURN ""          /* user aborted entry */
  1163.  
  1164.     /* check whether Key exists already */
  1165.     ok = SysIni(iniName, topName, tmpResult)
  1166.  
  1167.     IF ok <> "ERROR:" THEN
  1168.     DO
  1169.        CALL check_value tmpResult
  1170.        CALL error_msg "Key:" || global.iCyan "[" || global.iYellow || strings.displayValue || global.iCyan || "]" global.iRedWhite || "exists already !"
  1171.        RETURN ""
  1172.     END
  1173.  
  1174.     RETURN tmpResult
  1175.  
  1176.  
  1177.  
  1178. /* 
  1179.         Display TOPLEVEL-entries of chosen INI-file
  1180. */
  1181. SHOW_TOPLEVEL: PROCEDURE EXPOSE global. stemIni. stemTopLevel. stemKey. 
  1182.    iIni     = ARG(1)
  1183.    filename = stemIni.iIni
  1184.  
  1185.    CALL read_toplevel(iIni)               /* read all toplevel-entries */
  1186.    global.TopLSortState = "U"                  /* unsorted */
  1187.  
  1188.    DO FOREVER
  1189.       IF stemTopLevel.0 = 0 THEN
  1190.       DO
  1191.         
  1192.       END
  1193.  
  1194.       SAY
  1195.       SAY global.iRedWhite || CENTER("available TopLevel-entries (Application entries)", global.iColumns) || global.iCyan
  1196.       SAY
  1197.       SAY global.iCyan'INI-file:' global.iYellow ||filename
  1198.       SAY
  1199.       SAY global.iCyan'The following' global.iYellow||stemTopLevel.0 global.iCyan'TopLevel entries are available:'
  1200.       SAY
  1201.       CALL show_generic "stemTopLevel"      /* show stem contents */
  1202.  
  1203.       SAY
  1204.  
  1205.       choices = "CPSUQ"                  /* define choices */
  1206.  
  1207.       tmp = global.enterString || stemTopLevel.0 global.iCyan || 'to view TopLevel-entries,',
  1208.             global.iYellow || '0' || global.iCyan 'to return;'
  1209.  
  1210.       IF global.config.add.indTopLevel THEN
  1211.       DO
  1212.          tmp = tmp global.iYellow || 'a' || global.iCyan || 'dd,'
  1213.          choices = choices || "A"         /* add the adding choice */
  1214.       END
  1215.  
  1216.       tmp = tmp global.iYellow || 's' || global.iCyan || 'ort,',
  1217.             global.iYellow || 'u' || global.iCyan || 'nsort,',
  1218.             global.iYellow || 'p' || global.iCyan || 'rint'
  1219.  
  1220.       SAY tmp
  1221.  
  1222.       /* define choices and upper numeric boundary and get answer from user */
  1223.       CALL CHAROUT , global.iYellow
  1224.       answer = get_answer(choices, stemTopLevel.0)
  1225.       CALL CHAROUT , global.iCyan
  1226.       SAY
  1227.  
  1228.       SELECT
  1229.          WHEN answer = "" | answer = 0 | answer = "1B"x THEN LEAVE
  1230.  
  1231.          WHEN answer = "Q" THEN SIGNAL halt
  1232.  
  1233.          WHEN answer = 'P' THEN    /* print all TopLevel-entries */
  1234.               DO
  1235.                  CALL print iIni                        /* all TopLevel-entries will be sorted */
  1236.                  IF global.TopLSortState = "U" THEN
  1237.                     CALL read_toplevel(iIni)       /* reread all toplevel-entries */
  1238.  
  1239.               END
  1240.    
  1241.          WHEN answer = "C" THEN         /* configure program */
  1242.               DO
  1243.                  CALL settings_printout
  1244.                  CALL settings_menu
  1245.                  CALL check_option_set  /* show configuration option ? */
  1246.               END
  1247.  
  1248.          WHEN answer = 'S' THEN    /* sort TopLevel-entries */
  1249.               DO
  1250.                  CALL sort_generic "stemTopLevel"
  1251.                  global.TopLSortState = "S"
  1252.               END
  1253.     
  1254.          WHEN answer = 'U' THEN    /* unsort TopLevel-entries, i.e. reread */
  1255.               DO
  1256.                  CALL read_toplevel(iIni)          /* read all toplevel-entries */
  1257.                  global.TopLSortState = "U"  
  1258.               END
  1259.    
  1260.          WHEN answer = "A" THEN      /* add a new key-entry */
  1261.               DO
  1262.                  newTopLevel = create_new_toplevel(iIni)
  1263.                  IF newTopLevel = "" THEN ITERATE       /* no entry, or exists already */
  1264.         
  1265.                  CALL check_value newTopLevel
  1266.                  newTopLevel.displayValue = strings.displayValue
  1267.                  SAY
  1268.                  SAY "new Top-Level:" global.iRedWhite || newTopLevel.displayValue || global.iCyan
  1269.                  SAY
  1270.         
  1271.                  newKey = create_new_key(stemIni.iIni, newTopLevel)
  1272.                  IF newKey = "" THEN ITERATE            /* no entry, or exists already */
  1273.  
  1274.                  SAY
  1275.                  SAY "new Top-Level:" global.iRedWhite || newTopLevel.displayValue || global.iCyan
  1276.                  SAY
  1277.                  CALL check_value newKey
  1278.                  newKey.displayValue = strings.displayValue
  1279.         
  1280.                  PARSE VALUE edit_value("A", "new value for Key:" global.iRedWhite || newKey.displayValue || global.iCyan, , , "Enter new Key-Value") WITH tmpState tmpResult
  1281.                  IF tmpState = "NOK" THEN ITERATE
  1282.  
  1283.                  newKeyValue = tmpResult
  1284.         
  1285.                  val = SysIni(stemIni.iIni, newTopLevel, newKey, newKeyValue)
  1286.         
  1287.                  CALL read_toplevel(iIni)               /* read all toplevel-entries */
  1288.         
  1289.                  IF global.TopLSortState = "S" THEN
  1290.                     CALL sort_generic "stemTopLevel"
  1291.               END
  1292.     
  1293.          OTHERWISE              /* show keys of chosen TopLevel */
  1294.               DO
  1295.                  IF show_key(ARG(1), answer) THEN
  1296.                  DO
  1297.                     CALL read_toplevel(iIni)               /* read all toplevel-entries */
  1298.            
  1299.                     IF global.TopLSortState = "S" THEN
  1300.                        CALL sort_generic "stemTopLevel"
  1301.                  END
  1302.            
  1303.                  SAY
  1304.               END
  1305.       END  
  1306.       SAY
  1307.    END
  1308.    SAY global.iNormal
  1309.    RETURN
  1310.  
  1311.  
  1312. /*
  1313.      copy keys to another TopLevel
  1314. */
  1315. COPY_KEYS: PROCEDURE EXPOSE global. stemIni. stemTopLevel. stemKey.
  1316.     iIni     = ARG(1)           /* OS/2-ini file */
  1317.     iTopL    = ARG(2)           /* index into stemTopLevel */
  1318.     all_keys = ARG(3)           /* true if all keys to be copied, else false */
  1319.     iKey     = ARG(4)           /* index into stemKey., if only one key is to be copied */
  1320.  
  1321.     dirty = 0                   /* reread TopLevel entries, if one was added as a target */
  1322.  
  1323.     SAY
  1324.  
  1325.     DO FOREVER
  1326.        tmp = "copy" 
  1327.    
  1328.        IF all_keys THEN
  1329.           tmp = tmp "ALL keys ... "
  1330.        ELSE
  1331.           tmp = tmp "key ... "
  1332.    
  1333.        SAY global.iRedWhite 
  1334.        SAY tmp
  1335.        SAY global.iRedWhite || CENTER("available TopLevel-entries (Application entries)", global.iColumns) || global.iCyan
  1336.        SAY
  1337.    
  1338.        SAY global.iCyan'INI-file:' global.iYellow || stemIni.iIni
  1339.        SAY global.iCyan'TopLevel:' global.iYellow || stemTopLevel.iTopL
  1340.    
  1341.        IF \all_keys THEN        /* single key, show it */
  1342.        DO
  1343.           SAY global.iCyan'     Key:' global.iYellow || stemKey.iKey
  1344.        END
  1345.    
  1346.        SAY
  1347.        SAY global.iCyan'The following' global.iYellow||stemTopLevel.0 global.iCyan'TopLevel entries are available:'
  1348.        SAY
  1349.        CALL show_generic "stemTopLevel"      /* show stem contents */
  1350.        SAY
  1351.    
  1352.        tmp = global.iCyan || "Enter the TopLevel you wish to" global.iYellow|| "copy" || global.iCyan "to:",
  1353.              global.iYellow || "1" || global.iCyan || "-" ||,
  1354.              global.iYellow|| stemTopLevel.0 global.iCyan || 'to identify target TopLevel,',
  1355.              global.iYellow || '0' || global.iCyan 'to return;',
  1356.              global.iYellow || 'c' || global.iCyan || 'reate new TopLevel'
  1357.    
  1358.        SAY tmp
  1359.    
  1360.        /* define choices and upper numeric boundary and get answer from user */
  1361.        CALL CHAROUT , global.iYellow
  1362.        answer = get_answer("CQ", stemTopLevel.0)
  1363.        CALL CHAROUT , global.iCyan
  1364.    
  1365.        SAY
  1366.        SELECT
  1367.           WHEN answer = "" | answer = 0 | answer = "1B"x THEN LEAVE
  1368.    
  1369.           WHEN answer = "Q" THEN SIGNAL halt
  1370.    
  1371.           WHEN answer = "C" THEN              /* create new TopLevel */
  1372.                DO
  1373.                   newTopLevel = create_new_toplevel(iIni)
  1374.                   IF newTopLevel = "" THEN ITERATE    /* no entry, or exists already */
  1375.          
  1376.                   CALL check_value newTopLevel
  1377.                   SAY
  1378.                   SAY "new Top-Level:" global.iRedWhite || strings.displayValue || global.iCyan
  1379.                   SAY
  1380.    
  1381.                   targetTopLevel = newTopLevel
  1382.                   dirty = 1                   /* reread TopLevels */
  1383.                END
  1384.    
  1385.           WHEN answer = iTopL THEN    /* target same as source ? */
  1386.                DO
  1387.                   CALL error_msg "Target TopLevel:" || global.iCyan "[" || global.iYellow || stemTopLevel.iTopL || global.iCyan || "]" global.iRedWhite || "same as source TopLevel !"
  1388.                   ITERATE
  1389.                END
  1390.    
  1391.           OTHERWISE targetTopLevel = stemTopLevel.answer.origValue
  1392.        END
  1393.    
  1394.        /* copy keys to TopLevel */
  1395.        SAY global.iCyan || "Copying keys into TopLevel [" || global.iYellow || stemTopLevel.answer || global.iCyan || "] ..."
  1396.        DO i = 1 TO stemKey.0
  1397.           IF \all_keys THEN i = iKey       /* assign key-index */
  1398.    
  1399.           val = SysIni(stemIni.iIni, stemTopLevel.iTopL.origValue, stemKey.i.origValue)
  1400.           CALL SysIni stemIni.iIni, targetTopLevel, stemKey.i.origValue, val
  1401.  
  1402.           SAY global.iCyan"Key: [" || global.iYellow || stemKey.i || global.iCyan || "] copied."
  1403.    
  1404.           IF \all_keys THEN LEAVE          /* leave loop prematurely */
  1405.        END
  1406.        LEAVE
  1407.     END
  1408.  
  1409.     RETURN dirty
  1410.  
  1411.  
  1412.  
  1413. /*
  1414.         move keys to another TopLevel, if only one key, then allow for renaming it
  1415. */
  1416. MOVE_KEYS: PROCEDURE EXPOSE global. stemIni. stemTopLevel. stemKey.
  1417.     iIni     = ARG(1)           /* OS/2-ini file */
  1418.     iTopL    = ARG(2)           /* index into stemTopLevel */
  1419.     all_keys = ARG(3)           /* true if all keys to be moved, else false */
  1420.     iKey     = ARG(4)           /* index into stemKey., if only one key is to be moved */
  1421.  
  1422.     TopLevelCreated = 0         /* was a new TopLevel created ? */
  1423.     KeyMoved = 0                /* was a key moved ? */
  1424.  
  1425.     SAY
  1426.     DO FOREVER
  1427.        tmp = "move"
  1428.    
  1429.        IF all_keys THEN
  1430.           tmp = tmp "ALL keys ... "
  1431.        ELSE
  1432.           tmp = tmp "key ... "
  1433.  
  1434.        SAY global.iRedWhite 
  1435.        SAY tmp
  1436.        SAY global.iRedWhite || CENTER("available TopLevel-entries (Application entries)", global.iColumns) || global.iCyan
  1437.  
  1438.        SAY
  1439.        SAY global.iCyan'INI-file:' global.iYellow || stemIni.iIni
  1440.        SAY global.iCyan'TopLevel:' global.iYellow || stemTopLevel.iTopL
  1441.  
  1442.        IF \all_keys THEN        /* single key, show it */
  1443.        DO
  1444.           SAY global.iCyan'     Key:' global.iYellow || stemKey.iKey
  1445.        END
  1446.  
  1447.  
  1448.        SAY
  1449.        SAY global.iCyan'The following' global.iYellow||stemTopLevel.0 global.iCyan'TopLevel entries are available:'
  1450.        SAY
  1451.        CALL show_generic "stemTopLevel"      /* show stem contents */
  1452.        SAY
  1453.        choices = "CQ"
  1454.    
  1455.        tmp = global.iCyan || "Enter the TopLevel you wish to" global.iYellow|| "move" 
  1456.    
  1457.        IF all_keys THEN
  1458.           tmp = tmp || global.iCyan "these keys to:"
  1459.        ELSE
  1460.           tmp = tmp || global.iCyan "the key to:"
  1461.    
  1462.        tmp = tmp  global.iYellow || "1" || global.iCyan || "-" ||,
  1463.              global.iYellow|| stemTopLevel.0 global.iCyan || 'to identify target TopLevel,',
  1464.              global.iYellow || '0' || global.iCyan 'to return;'
  1465.    
  1466.        IF \all_keys THEN
  1467.        DO
  1468.           tmp = tmp global.iYellow || 'r' || global.iCyan || 'ename key,'
  1469.           choices = choices || "R"
  1470.        END
  1471.           tmp = tmp global.iYellow || 'c' || global.iCyan || 'reate new TopLevel'
  1472.    
  1473.        SAY tmp
  1474.    
  1475.        /* define choices and upper numeric boundary and get answer from user */
  1476.        CALL CHAROUT , global.iYellow
  1477.        answer = get_answer(choices, stemTopLevel.0)
  1478.        CALL CHAROUT , global.iCyan
  1479.    
  1480.        SAY
  1481.        SELECT
  1482.           WHEN answer = "" | answer = 0 | answer = "1B"x THEN LEAVE
  1483.    
  1484.           WHEN answer = "Q" THEN SIGNAL halt
  1485.    
  1486.           WHEN answer = "R" THEN              /* just rename present key */
  1487.                DO
  1488.                   PARSE VALUE edit_value("E", stemKey.iKey, , "H A", "Enter new Key-Name") WITH tmpState tmpResult
  1489.                   IF tmpState = "NOK" | tmpResult = "" THEN RETURN TopLevelCreated
  1490.                   newKey = tmpResult
  1491.                   CALL check_value newKey
  1492.                END
  1493.    
  1494.           WHEN answer = "C" THEN              /* create new TopLevel */
  1495.                DO
  1496.                   newTopLevel = create_new_toplevel(iIni)
  1497.                   IF newTopLevel = "" THEN ITERATE    /* no entry, or exists already */
  1498.          
  1499.                   CALL check_value newTopLevel
  1500.                   SAY
  1501.                   SAY "new Top-Level:" global.iRedWhite || strings.displayValue || global.iCyan
  1502.                   SAY
  1503.    
  1504.                   targetTopLevel = newTopLevel
  1505.                   targetTopLevel.displayValue = strings.displayValue
  1506.                   TopLevelCreated = 1
  1507.                END
  1508.    
  1509.           WHEN answer = iTopL THEN    /* target same as source ? */
  1510.                DO
  1511.                   CALL error_msg "Target TopLevel:" || global.iCyan "[" || global.iYellow || stemTopLevel.iTopL || global.iCyan || "]" global.iRedWhite || "same as source TopLevel !"
  1512.                   ITERATE
  1513.                END
  1514.    
  1515.           OTHERWISE 
  1516.                DO
  1517.                   targetTopLevel = stemTopLevel.answer.origValue
  1518.                   targetTopLevel.displayValue = stemTopLevel.answer
  1519.                END
  1520.        END
  1521.    
  1522.        /* move keys to target TopLevel */
  1523.    
  1524.        IF answer <> "R" THEN       /* regular move */
  1525.        DO
  1526.           SAY global.iCyan || "Moving keys into TopLevel [" || global.iYellow || targetTopLevel.displayValue || global.iCyan || "] ..."
  1527.           DO i = 1 TO stemKey.0
  1528.              IF \all_keys THEN i = iKey
  1529.  
  1530.              /* move key in hand */
  1531.              PARSE VALUE call_move_keys(stemIni.iIni, stemTopLevel.iTopL.origValue, targetTopLevel,,
  1532.                                         stemKey.i.origValue, stemKey.i),
  1533.                          WITH TopSuccess keySuccess
  1534.              TopLevelCreated = TopLevelCreated | TopSuccess
  1535.              KeyMoved =        KeyMoved | keySuccess
  1536.    
  1537.              IF \all_keys THEN LEAVE
  1538.           END
  1539.        END
  1540.        ELSE                        /* rename single key */
  1541.        DO
  1542.           /* move key in hand */
  1543.           i = iKey
  1544.           PARSE VALUE call_move_keys(stemIni.iIni,,
  1545.                                      stemTopLevel.iTopl.origValue, stemTopLevel.iTopl.origValue,,
  1546.                                      stemKey.i.origValue, strings.displayValue, newKey),
  1547.                       WITH TopLevelCreated keySuccess
  1548.        END
  1549.    
  1550.        IF KeyMoved THEN    /* at least one key was moved, reread keys into stemKey. */
  1551.        DO
  1552.           CALL read_key iIni, iTopL
  1553.           IF global.KeySortState = "S" THEN        /* resort */
  1554.              CALL sort_generic "stemKey"
  1555.  
  1556.           RETURN TopLevelCreated
  1557.        END
  1558.        LEAVE
  1559.     END
  1560.  
  1561.     RETURN 0            /* no move took place, therefore no new TopLevel was created */
  1562.  
  1563.  
  1564. /*
  1565.    do the actual move-operation
  1566. */
  1567. CALL_MOVE_KEYS: PROCEDURE EXPOSE global.
  1568.     iniFile          = ARG(1)   /* OS/2-INI-file */
  1569.     sourceTopLevel   = ARG(2)   /* source */
  1570.     targetTopLevel   = ARG(3)   /* target */
  1571.     sourceKey        = ARG(4)   /* key */
  1572.     sourceKeyDisplay = ARG(5)   /* displayable string for key-name */
  1573.  
  1574.     TopLevelCreated = 0
  1575.  
  1576.     IF ARG() = 6 THEN   /* only given, if a single key-move within the same target (rename of a key) */
  1577.         targetKey = ARG(6)
  1578.     ELSE
  1579.     DO
  1580.         targetKey = sourceKey   /* move to a different place, but leave key-name unchanged */
  1581.         TopLevelCreated = 1     /* expect a succesful move into a new directory */
  1582.     END
  1583.  
  1584.     KeyMoved = 1                /* expect a successful move */
  1585.  
  1586.     /* present value of key */
  1587.     val1 = SysIni(iniFile, sourceTopLevel, sourceKey)
  1588.  
  1589.     /* value of key in target, if it exists */
  1590.     val2 = SysIni(iniFile, targetTopLevel, targetKey)
  1591.  
  1592.     IF val2 <> "ERROR:" THEN    /* key exists in target ! */
  1593.     DO
  1594.        CALL error_msg "Key:" || global.iCyan "[" || global.iYellow || sourceKeyDisplay || global.iCyan || "]" global.iRedWhite || "exists already, not moved.", "no wait"
  1595.        TopLevelCreated = 0
  1596.        KeyMoved = 0
  1597.     END
  1598.     ELSE
  1599.     DO
  1600.        /* create new key */
  1601.        CALL SysIni iniFile, targetTopLevel, targetKey, val1
  1602.        /* delete original key */
  1603.        CALL SysIni iniFile, sourceTopLevel, sourceKey, "DELETE:"
  1604.        SAY global.iCyan"Key: [" || global.iYellow || sourceKeyDisplay || global.iCyan || "] moved."
  1605.     END
  1606.  
  1607.     RETURN TopLevelCreated KeyMoved
  1608.  
  1609.  
  1610.  
  1611.  
  1612.  
  1613.  
  1614.  
  1615. /*
  1616.         read KEY-entries
  1617. */
  1618. READ_KEY: PROCEDURE EXPOSE stemIni. stemTopLevel. stemKey. global. strings.
  1619.     DROP stemKey.
  1620.     stemKey. = ""
  1621.  
  1622.     iIni     = ARG(1)
  1623.     iTopL    = ARG(2)
  1624.  
  1625.     ok = SysIni(stemIni.iIni, stemTopLevel.iTopL.origValue, 'ALL:', 'stemKey')
  1626.     IF ok = "ERROR:" THEN
  1627.     DO
  1628.        stemKey.0 = 0
  1629.     END
  1630.     ELSE
  1631.     DO i = 1 TO stemKey.0
  1632.        CALL check_value stemKey.i  /* determine and prepare value in hand */
  1633.        stemKey.i.origValue   = stemKey.i
  1634.        stemKey.i             = strings.displayValue
  1635.        stemKey.i.type        = strings.type
  1636.        stemKey.i.filterValue = strings.filterValue
  1637.     END
  1638.  
  1639.     CALL largest_generic("stemKey")
  1640.     RETURN 
  1641.  
  1642.  
  1643. /* 
  1644.         Display KEY-entries of chosen INI-file
  1645. */
  1646. SHOW_KEY: PROCEDURE EXPOSE global. stemIni. stemTopLevel. stemKey.
  1647.    iIni     = ARG(1)
  1648.    iTopL    = ARG(2)
  1649.    filename = stemIni.iIni
  1650.    TopLevel = stemTopLevel.iTopL
  1651.  
  1652.    CALL read_key iIni, iTopL
  1653.    global.KeySortState = "U"            /* unsorted */
  1654.    dirty   = 0                          /* everything o.k., no need to reread TopLevel */
  1655.  
  1656.    DO FOREVER
  1657.       IF stemKey.0 = 0 THEN RETURN "1"       /* no keys left, reread Top-Level entries */
  1658.  
  1659.       SAY
  1660.       SAY global.iRedWhite || CENTER("available keys", global.iColumns) || global.iCyan
  1661.       SAY
  1662.       SAY global.iCyan'INI-file:' global.iYellow filename
  1663.       SAY global.iCyan'TopLevel:' global.iYellow TopLevel
  1664.       SAY
  1665.       SAY global.iCyan'The following' global.iYellow||stemKey.0 global.iCyan'Key entries are available:'
  1666.       SAY
  1667.       CALL show_generic "stemKey"      /* show stem contents */
  1668.       SAY
  1669.  
  1670.  
  1671.       choices = "PSUQ"          /* define choices */
  1672.  
  1673.       tmp = global.enterString || stemKey.0 global.iCyan || 'to view Key-value,',
  1674.             global.iYellow || '0' || global.iCyan 'to return;'
  1675.  
  1676.       IF global.config.add.indKey THEN
  1677.       DO
  1678.          tmp = tmp global.iYellow || 'a' || global.iCyan || 'dd,'
  1679.          choices = choices || "A"
  1680.       END
  1681.  
  1682.       IF global.config.delete.indAllKeys THEN
  1683.       DO
  1684.          tmp = tmp global.iYellow || 'd' || global.iCyan || 'elete ALL,'
  1685.          choices = choices || "D"
  1686.       END
  1687.  
  1688.       IF global.config.move.indAllKeys THEN
  1689.       DO
  1690.          tmp = tmp global.iYellow || 'm' || global.iCyan || 'ove ALL,'
  1691.          choices = choices || "M"
  1692.       END
  1693.  
  1694.       IF global.config.copy.indAllKeys THEN
  1695.       DO
  1696.          tmp = tmp global.iYellow || 'c' || global.iCyan || 'opy ALL,'
  1697.          choices = choices || "C"
  1698.       END
  1699.  
  1700.       tmp = tmp global.iYellow || 's' || global.iCyan || 'ort,',
  1701.           global.iYellow || 'u' || global.iCyan || 'nsort,',
  1702.           global.iYellow || 'p' || global.iCyan || 'rint'
  1703.  
  1704.       SAY tmp
  1705.  
  1706.       /* define choices and upper numeric boundary and get answer from user */
  1707.       CALL CHAROUT , global.iYellow
  1708.       answer = get_answer(choices, stemKey.0)
  1709.       CALL CHAROUT , global.iCyan
  1710.       SAY
  1711.  
  1712.       SELECT
  1713.          WHEN answer = "" | answer = 0 | answer = "1B"x THEN LEAVE
  1714.  
  1715.          WHEN answer = "Q" THEN SIGNAL halt
  1716.  
  1717.          WHEN answer = 'P' THEN         /* print all Key-entries of TopLevel */
  1718.               DO
  1719.                  CALL print iIni, iTopL
  1720.                  IF global.KeySortState = "U" THEN      /* reread all key-entries */
  1721.                     CALL read_key iIni, iTopL
  1722.               END
  1723.    
  1724.          WHEN answer = 'S' THEN         /* sort key-entries */
  1725.               DO
  1726.                  CALL sort_generic "stemKey"
  1727.                  global.KeySortState = "S"
  1728.               END
  1729.     
  1730.          WHEN answer = 'U' THEN         /* unsort key-entries, i.e. reread them */
  1731.               DO
  1732.                  CALL read_key iIni, iTopL
  1733.                  global.KeySortState = "U"
  1734.               END
  1735.    
  1736.          WHEN answer = "D" THEN         /* delete all keys and TopLevel-entry */
  1737.               DO
  1738.                  CALL BEEP 2000, 250
  1739.                  CALL CHAROUT , global.iRedWhite || "Do you really wish to delete ALL KEYs ???" || global.noHint 
  1740.                  answer = get_answer("QYN")
  1741.                  CALL CHAROUT , global.iCyan
  1742.         
  1743.                  IF answer = "Q" THEN SIGNAL halt
  1744.         
  1745.                  IF answer = "Y" THEN
  1746.                  DO
  1747.                     SAY global.iCyan || "Deleting ALL keys from TopLevel [" || global.iYellow || stemTopLevel.iTopL || global.iCyan || "] ..."
  1748.                     val = SysIni(stemIni.iIni, stemTopLevel.iTopL.origValue, "DELETE:")
  1749.                     SAY global.iCyan"done."
  1750.         
  1751.                     RETURN "1"                          /* return to TopLevel-entries */
  1752.                  END
  1753.               END
  1754.    
  1755.          WHEN answer = "C" THEN         /* copy all key entries to another TopLevel */
  1756.               DO
  1757.                 dirty = dirty | copy_keys(iIni, iTopL, "1")
  1758.               END
  1759.  
  1760.          WHEN answer = "M" THEN         /* move all key entries to another TopLevel */
  1761.               DO
  1762.                 dirty = dirty | move_keys(iIni, iTopL, "1")
  1763.               END
  1764.  
  1765.  
  1766.          WHEN answer = "A" THEN         /* add a new key-entry */
  1767.               DO
  1768.                  newKey = create_new_key(stemIni.iIni, stemTopLevel.iTopL.origValue)
  1769.                  IF newKey = "" THEN ITERATE
  1770.         
  1771.                  CALL check_value newKey
  1772.                  newKey.displayValue = strings.displayValue
  1773.         
  1774.                  PARSE VALUE edit_value("A", "new value for Key:" global.iRedWhite || newKey.displayValue || global.iCyan, , , "Enter new Key-Value") WITH tmpState tmpResult
  1775.                  IF tmpState = "NOK" THEN ITERATE
  1776.                  newKeyValue = tmpResult
  1777.  
  1778.                  /* create new key */
  1779.                  val = SysIni(stemIni.iIni, stemTopLevel.iTopL.origValue, newKey, newKeyValue)
  1780.         
  1781.                  CALL read_key iIni, iTopL              /* reread keys */
  1782.         
  1783.                  IF global.KeySortState = "S" THEN
  1784.                     CALL sort_generic "stemKey"
  1785.               END
  1786.  
  1787.          OTHERWISE      /* display value of chosen key */
  1788.               dirty = dirty | show_keyvalue(iIni, iTopL, answer)        /* TopLevel created ? */
  1789.               SAY
  1790.       END  
  1791.       SAY
  1792.    END
  1793.    SAY global.iNormal
  1794.    RETURN dirty
  1795.  
  1796.  
  1797. /*
  1798.         display value and allow for editing
  1799. */
  1800. SHOW_KEYVALUE: PROCEDURE EXPOSE global. strings. stemIni. stemTopLevel. stemKey.
  1801.     iIni     = ARG(1)
  1802.     iTopL    = ARG(2)
  1803.     iKey     = ARG(3)
  1804.     dirty    = 0                /* change in key-names ? */
  1805.     TopLevelCreated = 0         /* was a TopLevel created using copy, move ? */
  1806.  
  1807.     filename = stemIni.iIni
  1808.     TopLevel = stemTopLevel.iTopL
  1809.     Key      = stemKey.iKey
  1810.  
  1811.     val = SysIni(stemIni.iIni, stemTopLevel.iTopL.origValue, stemKey.iKey.origValue)
  1812.  
  1813.     CALL check_value val
  1814.     iType = strings.type        /* type could be A, A0 or H */
  1815.  
  1816.     value2show = strings.displayValue
  1817.  
  1818.  
  1819.     DO FOREVER
  1820.        SAY
  1821.        SAY global.iRedWhite || CENTER("key-value", global.iColumns) || global.iCyan
  1822.        SAY
  1823.        SAY global.iCyan'INI-file:' global.iYellow || filename
  1824.        SAY global.iCyan'TopLevel:' global.iYellow || TopLevel
  1825.        SAY global.iCyan'     Key:' global.iYellow || Key global.iCyan
  1826.        SAY
  1827.    
  1828.    
  1829.        SAY "data type:" global.iYellow || global.dType.iType global.iCyan "(" ||,
  1830.            global.iYellow || global.dType.iType.long || global.iCyan || ")"
  1831.        SAY "    value:" global.iNormal
  1832.        SAY global.iCyan || "[" || global.iYellow || value2show || global.iCyan || "]"
  1833.        SAY
  1834.  
  1835.        choices = ""
  1836.  
  1837.        SAY global.iCyan || "Enter:"
  1838.        SAY
  1839.  
  1840.        IF iType = "H" THEN
  1841.        DO
  1842.           choices = choices || "FH"
  1843.           SAY "       " global.iYellow || "H" global.iCyan "to show value in hex-digits"
  1844.           SAY "       " global.iYellow || "F" global.iCyan "to show filtered value"
  1845.        END
  1846.  
  1847.        IF global.config.change.indKey THEN
  1848.        DO
  1849.           SAY "       " global.iYellow || "E" global.iCyan "to edit (change) key-value"
  1850.           choices = choices || "E"
  1851.        END
  1852.  
  1853.        IF global.config.delete.indKey THEN
  1854.        DO
  1855.           SAY "       " global.iYellow || "D" global.iCyan "to delete key"
  1856.           choices = choices || "D"
  1857.        END
  1858.  
  1859.        IF global.config.move.indKey THEN
  1860.        DO
  1861.           SAY "       " global.iYellow || "M" global.iCyan "to move/rename key"
  1862.           choices = choices || "M"
  1863.        END
  1864.  
  1865.        IF global.config.copy.indKey THEN
  1866.        DO
  1867.           SAY "       " global.iYellow || "C" global.iCyan "to print key"
  1868.           choices = choices || "C"
  1869.        END
  1870.  
  1871.        SAY "       " global.iYellow || "P" global.iCyan "to edit key-value"
  1872.        SAY "       " global.iCyan   || "   [Esc] to return"
  1873.        /* define choices and get answer from user */
  1874.        CALL CHAROUT , global.iYellow
  1875.        answer = get_answer(choices || "PQ")
  1876.        CALL CHAROUT , global.iCyan
  1877.  
  1878.        SELECT
  1879.           WHEN answer = "Q" THEN SIGNAL halt
  1880.  
  1881.           WHEN answer = "H" THEN value2show = strings.displayValue
  1882.  
  1883.           WHEN answer = 'P' THEN    /* print the Key-value */
  1884.                CALL print iIni, iTopL, iKey
  1885.  
  1886.           WHEN answer = "F" THEN value2show = strings.filterValue
  1887.  
  1888.  
  1889.  
  1890.  
  1891.          WHEN answer = "C" THEN         /* copy key to another TopLevel */
  1892.               DO
  1893.                 TopLevelCreated = TopLevelCreated | copy_keys(iIni, iTopL, "0", iKey)
  1894.               END
  1895.  
  1896.          WHEN answer = "M" THEN         /* move key to another TopLevel or rename it */
  1897.               DO
  1898.                 TopLevelCreated = TopLevelCreated | move_keys(iIni, iTopL, "0", iKey)
  1899.                 dirty = 1
  1900.                 LEAVE
  1901.               END
  1902.  
  1903.           WHEN answer = "D" THEN                        /* delete key */
  1904.                DO
  1905.                   CALL BEEP 2000, 250
  1906.                   CALL CHAROUT , global.iRedWhite || "Do you really wish to delete this KEY ?" || global.noHint 
  1907.                   answer = get_answer("QYN")
  1908.                   CALL CHAROUT , global.iCyan
  1909.  
  1910.                   IF answer = "Q" THEN SIGNAL halt
  1911.  
  1912.                   IF answer = "Y" THEN
  1913.                   DO
  1914.                      val = SysIni(stemIni.iIni, stemTopLevel.iTopL.origValue, stemKey.iKey.origValue, "DELETE:")
  1915.                      dirty = 1
  1916.                      LEAVE
  1917.                   END
  1918.                END
  1919.  
  1920.           WHEN answer = "E" THEN                        /* change key-value */
  1921.                DO
  1922.                   PARSE VALUE edit_value("E", val, , , "Enter new Key-Value") WITH tmpState tmpResult
  1923.                   IF tmpState = "OK" THEN
  1924.                   DO
  1925.                      val = SysIni(stemIni.iIni, stemTopLevel.iTopL.origValue, stemKey.iKey.origValue, tmpResult)
  1926.                      val = tmpResult
  1927.                   END
  1928.  
  1929.                   CALL check_value val
  1930.                   iType = strings.type        /* type could be A, A0 or H */
  1931.                   value2show = strings.displayValue
  1932.               
  1933.                   choice = ""
  1934.                END
  1935.  
  1936.           OTHERWISE LEAVE
  1937.        END  
  1938.    
  1939.        SAY
  1940.     END
  1941.  
  1942.     SAY
  1943.     IF dirty THEN               /* was a key added, renamed/moved, deleted ? */
  1944.     DO                          /* if so, reread keys */
  1945.        CALL read_key iIni, iTopL
  1946.        IF global.KeySortState = "S" THEN              /* resort keys */
  1947.           CALL sort_generic "stemKey"
  1948.     END
  1949.     RETURN TopLevelCreated
  1950.  
  1951.  
  1952. /* 
  1953.    check data-type of argument and set up a structure containing different representations
  1954.    of it
  1955. */
  1956. CHECK_VALUE: PROCEDURE EXPOSE global. strings.
  1957.    DROP strings.
  1958.    strings. = ""
  1959.  
  1960.    /* last character \0 ? */
  1961.  
  1962.    IF SUBSTR(ARG(1), LENGTH(ARG(1)), 1) = "00"x THEN    /* ASCIIZ ? */
  1963.    DO
  1964.       work = SUBSTR(ARG(1), 1, LENGTH(ARG(1)) - 1)
  1965.       asciiz = "0"
  1966.    END
  1967.    ELSE                                                 
  1968.    DO
  1969.       work = ARG(1)
  1970.       asciiz = ""
  1971.    END
  1972.  
  1973.    ascii = (VERIFY(work, global.iNonPrintable, "Match") = 0)    /* plain ASCII ? */
  1974.  
  1975.    IF ascii THEN                                        /* ASCII-type value in hand */
  1976.    DO
  1977.       IF asciiz = "0" THEN strings.type = "A0"
  1978.                       ELSE strings.type = "A"
  1979.       strings.displayValue = work
  1980.    END
  1981.    ELSE                                                 /* hexadecimal value in hand */
  1982.    DO
  1983.       strings.type = "H"
  1984.       strings.displayValue = "x'" || C2X(ARG(1)) || "'"
  1985.       strings.filterValue = TRANSLATE(ARG(1), global.iFilter, global.iNonPrintable)
  1986.    END
  1987.    RETURN
  1988.  
  1989.  
  1990.  
  1991. /*
  1992.    allow for adding or editing a value
  1993.    ARG(1) ... A to add, E to edit
  1994.    ARG(2) ... title
  1995.    ARG(3) ... optional, if given, then only ASCII-values allowed
  1996.    ARG(4) ... optional, if given, then only HEX- or ASCII-editing allowed (for TopLevels and
  1997.               keynames
  1998.    ARG(5) ... optional, if given, then the prompt for BOXEDIT
  1999. */
  2000. EDIT_VALUE: PROCEDURE EXPOSE global. strings.
  2001.    editType = ARG(1)    /* A add new, E edit existing */
  2002.    editName = ARG(2)    /* if adding new: TopLevel-entry or Key-entry 
  2003.                            if editing: value to be added */
  2004.    editDataType = ARG(3) /* optional, determines data-type "A", "A0", "H" */
  2005.  
  2006.  
  2007.    IF editType = "A" THEN
  2008.    DO
  2009.       DROP strings.
  2010.       strings. = ""
  2011.       tmpValue = ""
  2012.  
  2013.       IF ARG() = 3 THEN strings.type = editDataType
  2014.       ELSE
  2015.          choices = "12"
  2016.          SAY global.iCyan || "Defining:" global.iYellow || editName || global.iCyan
  2017.          SAY
  2018.          SAY "choose data type:" 
  2019.          SAY
  2020.          SAY "       " global.iYellow || "1" global.iCyan global.dtype.H.long
  2021.          SAY "       " global.iYellow || "2" global.iCyan global.dtype.A.long global.defaultHint
  2022.  
  2023.          IF ARG() < 4 THEN      /* ASCIIZ (A0) allowed ? */
  2024.          DO
  2025.            SAY "       " global.iYellow || "3" global.iCyan global.dtype.A0.long
  2026.            choices = choices || "3"
  2027.          END
  2028.  
  2029.          SAY "       " global.iCyan   || "   [Esc] to return"
  2030.          /* define choices and get answer from user */
  2031.          CALL CHAROUT , global.iYellow
  2032.          answer = get_answer("123Q")
  2033.          CALL CHAROUT , global.iCyan
  2034.    
  2035.          SELECT
  2036.             WHEN answer = "Q" THEN SIGNAL halt
  2037.             WHEN answer = "1" THEN strings.type = "H"
  2038.             WHEN answer = "2" | answer = "" THEN strings.type = "A"
  2039.             WHEN answer = "3" THEN strings.type = "A0"
  2040.    
  2041.             OTHERWISE RETURN "NOK"
  2042.          END  
  2043.       DO
  2044.       END
  2045.  
  2046.  
  2047.     END
  2048.     ELSE        /* editing mode */
  2049.     DO
  2050.        val = editName
  2051.        CALL CHECK_VALUE val
  2052.  
  2053.        IF strings.type = "A" | strings.type = "A0" THEN
  2054.        DO
  2055.            IF ARG() = 3 THEN answer = SUBSTR(editDataType, 1, 1)
  2056.            ELSE
  2057.            DO
  2058.               SAY global.iCyan || "choose data type for editing:"
  2059.               SAY
  2060.               SAY "       " global.iYellow || "H" global.iCyan global.dtype.H.long
  2061.               SAY "       " global.iYellow || "A" global.iCyan global.dtype.A.long global.defaultHint
  2062.               SAY "       " global.iCyan   || "   [Esc] to return"
  2063.    
  2064.               /* define choices and get answer from user */
  2065.               CALL CHAROUT , global.iYellow
  2066.               answer = get_answer("HAQ")
  2067.               CALL CHAROUT , global.iCyan
  2068.    
  2069.               IF answer = "Q" THEN SIGNAL halt    
  2070.    
  2071.               IF answer = "1B"x THEN RETURN "NOK"  /* Escape was pressed */
  2072.            END
  2073.                                                
  2074.            IF answer = "" | answer = "A" THEN   /* edit as ASCII */
  2075.            DO
  2076.               tmpValue = strings.displayValue
  2077.            END
  2078.            ELSE
  2079.            DO
  2080.               strings.type = "H"
  2081.               tmpValue = C2X(val)
  2082.            END
  2083.  
  2084.        END
  2085.        ELSE tmpValue = C2X(val)
  2086.     END
  2087.  
  2088.  
  2089.     tmpLength = LENGTH(tmpValue)
  2090.  
  2091.     neededRows = TRUNC(tmpLength / (global.iColumns - 2) + 0.9999) + 2
  2092.  
  2093.     IF neededRows > global.iRows THEN
  2094.     DO
  2095.        SAY
  2096.        CALL error_msg "screen-size not large enough to edit value !"
  2097.        val = "NOK"
  2098.     END
  2099.     ELSE  /* try to add four more empty lines */
  2100.     DO
  2101.        DO 4
  2102.           IF (neededRows + 1) < global.iRows THEN neededRows = neededRows + 1
  2103.                                              ELSE LEAVE
  2104.        END
  2105.        /* get present position */
  2106.        PARSE VALUE SysCurPos() WITH cursor_row cursor_col
  2107.  
  2108.        startingRow = cursor_row - neededRows 
  2109.  
  2110.        IF startingRow < 0 THEN startingRow = 0
  2111.  
  2112.        tmpType = ""       /* ASCII-edit for default */
  2113.        IF strings.type = "H" THEN tmptype = "H"
  2114.        editResult = boxedit((startingRow 0 (startingRow + neededRows - 1) (global.iColumns - 1)),,
  2115.                              tmpValue, tmpType, ARG(5))
  2116.        editResult = STRIP(editResult, "T")        /* remove trailing blanks */
  2117.  
  2118.        val = "NOK"
  2119.        IF editResult <> tmpValue THEN
  2120.        DO
  2121.           SELECT
  2122.              WHEN strings.type = "H" THEN val = "OK" X2C(editResult)
  2123.              WHEN strings.type = "A0" THEN val = "OK" editResult || "00"x
  2124.              OTHERWISE val = "OK" editResult
  2125.           END  
  2126.        END
  2127.     END
  2128.     RETURN val
  2129.  
  2130.  
  2131.  
  2132. /***********************************************************************************************/
  2133. /*
  2134.     print to file
  2135. */
  2136. PRINT: PROCEDURE EXPOSE global. strings. stemIni. stemTopLevel. stemKey.
  2137.     iIni  = ARG(1)      /* INI-file to be printed */
  2138.     iTopL = ARG(2)      /* TopLevel to be printed */
  2139.     iKey  = ARG(3)      /* Key to be printed */
  2140.  
  2141.     IF global.iBackupMode = "" THEN    /* prompt user */
  2142.     DO
  2143.        SAY
  2144.        SAY "Following settings are active:"
  2145.        SAY
  2146.        SAY global.iCyan || "Level of information to produce:" global.iYellow || VALUE("global.depthOfOutput." || global.config.showDepth)
  2147.        SAY global.iCyan || "Hexadecimal values shown as:    " global.iYellow || VALUE("global.hextypeOfOutput." || global.config.showHexAs)
  2148.        SAY global.iCyan || "Line length in characters:      " global.iYellow || global.config.showLineLength
  2149.        SAY
  2150.        CALL CHAROUT , global.iCyan || "Do you wish to change these settings ?" global.noHint
  2151.    
  2152.        /* define choices and get answer from user */
  2153.        CALL CHAROUT , global.iYellow
  2154.        answer = get_answer("YNQ")
  2155.        CALL CHAROUT , global.iCyan
  2156.    
  2157.        IF answer = "1B"x THEN RETURN 0
  2158.        ELSE IF answer = "Q" THEN SIGNAL halt
  2159.    
  2160.        IF answer = "Y" THEN                /* Yes, change the settings in effect */
  2161.        DO
  2162.          CALL settings_printout
  2163.        END
  2164.    
  2165.        answer = ""
  2166.        /* output file exists, shall we append to it ? */
  2167.        IF global.outFile <> "" THEN
  2168.        DO
  2169.           SAY
  2170.           SAY global.iCyan || "You printed already to file" global.iYellow || global.outFile || global.iCyan || "."
  2171.           SAY
  2172.           SAY global.iCyan || "Do you wish to append to it?" global.yesHint
  2173.           /* define choices and get answer from user */
  2174.           CALL CHAROUT , global.iYellow
  2175.           answer = get_answer("YNQ")
  2176.           CALL CHAROUT , global.iCyan
  2177.    
  2178.           IF answer = "1B"x THEN RETURN 0
  2179.           ELSE IF answer = "Q" THEN SIGNAL halt
  2180.       
  2181.        END
  2182.    
  2183.        IF answer = "N" | global.outFile = "" THEN  /* get file name to print to */
  2184.           IF \get_filename() THEN RETURN           /* user aborted print-operation ? */
  2185.     END
  2186.  
  2187.     /* o.k., now let us start producing the output ! */
  2188.  
  2189.     SELECT
  2190.        WHEN ARG() = 0 THEN      /* all INI-files to be printed */
  2191.             DO
  2192.                DO i = 1 TO stemIni.0
  2193.                   CALL output_filename i, "AI"          /* print file-name */
  2194.                                                         
  2195.                   CALL read_toplevel i                  /* read top-levels */
  2196.                   CALL sort_generic "stemTopLevel"      /* sort them */
  2197.                   DO j = 1 TO stemTopLevel.0
  2198.                      CALL output_topic j                /* print topic-name */
  2199.                      IF POS(global.config.showDepth, "KV") > 0 THEN             /* show more than TopLevel ? */
  2200.                      DO
  2201.                         CALL read_key i, j              /* read keys */
  2202.                         CALL sort_generic "stemKey"     /* sort them */
  2203.                         DO k = 1 TO stemKey.0
  2204.                            CALL output_key k            /* print key-name */
  2205.    
  2206.                            IF POS(global.config.showDepth, "V") > 0 THEN      /* show key-values too ? */
  2207.                            DO
  2208.                               /* get key-value */
  2209.                               val = SysIni(stemIni.i, stemTopLevel.j.origValue, stemKey.k.origValue)
  2210.                               CALL output_val val       /* print value */
  2211.                            END
  2212.                         END
  2213.                         CALL LINEOUT global.outFile, "" /* write empty line */
  2214.                      END
  2215.                   END
  2216.                CALL LINEOUT global.outFile, ""          /* write empty line */
  2217.                END
  2218.             END
  2219.  
  2220.        WHEN ARG() = 1 THEN      /* one INI-file, all TopLevels to be printed */
  2221.             DO
  2222.                i = iIni
  2223.                CALL output_filename i, "AT"             /* print file-name */
  2224.                CALL sort_generic "stemTopLevel"         /* sort them */
  2225.                                                        
  2226.                DO j = 1 TO stemTopLevel.0              
  2227.                   CALL output_topic j                   /* print topic-name */
  2228.                   IF POS(global.config.showDepth, "KV") > 0 THEN    /* show more than TopLevel ? */
  2229.                   DO
  2230.                      CALL read_key i, j                 /* read keys */
  2231.                      CALL sort_generic "stemKey"        /* sort them */
  2232.                      DO k = 1 TO stemKey.0
  2233.                         CALL output_key k               /* print key-name */
  2234.  
  2235.                         IF POS(global.config.showDepth, "V") > 0 THEN      /* show key-values too ? */
  2236.                         DO
  2237.                            /* get key-value */
  2238.                            val = SysIni(stemIni.i, stemTopLevel.j.origValue, stemKey.k.origValue)
  2239.                            CALL output_val val          /* print value */
  2240.                         END
  2241.                      END
  2242.                      CALL LINEOUT global.outFile, ""    /* write empty line */
  2243.                   END
  2244.                END
  2245.                CALL LINEOUT global.outFile, ""          /* write empty line */
  2246.             END
  2247.  
  2248.        WHEN ARG() = 2 THEN      /* one INI-file, one TopLevel, all keys to be printed */
  2249.             DO
  2250.                i = iIni
  2251.                j = iTopL
  2252.                CALL output_filename i, "AK"             /* print file-name */
  2253.                CALL output_topic j                      /* print topic-name */
  2254.                                                         
  2255.                CALL read_key i, j                       /* read keys */
  2256.                CALL sort_generic "stemKey"              /* sort them */
  2257.                                                         
  2258.                DO k = 1 TO stemKey.0                    
  2259.                   CALL output_key k                     /* print key-name */
  2260.  
  2261.                   IF POS(global.config.showDepth, "V") > 0 THEN      /* show key-values too ? */
  2262.                   DO
  2263.                      /* get key-value */
  2264.                      val = SysIni(stemIni.i, stemTopLevel.j.origValue, stemKey.k.origValue)
  2265.                      CALL output_val val                /* print value */
  2266.                   END
  2267.                END
  2268.                CALL LINEOUT global.outFile, ""          /* write empty line */
  2269.             END
  2270.  
  2271.        WHEN ARG() = 3 THEN      /* one INI-file, one TopLevel, one key and its value to be printed */
  2272.             DO
  2273.                i = iIni
  2274.                j = iTopL
  2275.                k = iKey
  2276.  
  2277.                CALL output_filename i, "K"              /* print file-name */
  2278.                CALL output_topic j                      /* print topic-name */
  2279.                CALL output_key k                        /* print key-name */
  2280.  
  2281.                /* get key-value */
  2282.                val = SysIni(stemIni.i, stemTopLevel.j.origValue, stemKey.k.origValue)
  2283.                CALL output_val val                      /* print value */
  2284.                CALL LINEOUT global.outFile, ""          /* write empty line */
  2285.             END
  2286.  
  2287.        OTHERWISE NOP
  2288.     END  
  2289.  
  2290.     SAY
  2291.     CALL STREAM global.outFile, "C", "CLOSE"            /* close output file */
  2292.  
  2293.     RETURN
  2294.  
  2295.  
  2296. /*
  2297.    write Filename into File, argument: index of INI-file to be processed
  2298. */
  2299. OUTPUT_FILENAME: PROCEDURE EXPOSE global. stemIni. stemTopLevel.
  2300.     range = ARG(2)      /* range of printout (all INIs, all TopLevels, all Keys, one Key) */
  2301.     /* show date/time of printout */
  2302.     tmp = LEFT("Date  [" || DATE("S") TIME() || "] ", global.config.showLineLength, "=")
  2303.     CALL LINEOUT global.outFile, tmp
  2304.  
  2305.     CALL LINEOUT global.outFile, ""
  2306.  
  2307.     /* show range of printout */
  2308.     tmp = LEFT("Range [" || VALUE("global.rangeOfPrintout." || range) || "] ", global.config.showLineLength, "=")
  2309.     CALL LINEOUT global.outFile, tmp
  2310.  
  2311.     /* show depth of information */
  2312.     tmp = LEFT("Depth [" || VALUE("global.depthOfOutput." || global.config.showDepth) || "] ", global.config.showLineLength, "=")
  2313.     CALL LINEOUT global.outFile, tmp
  2314.  
  2315.     CALL LINEOUT global.outFile, ""
  2316.  
  2317.     /* show filename, no matter how long it is */
  2318.     filename = "File  [" || VALUE("stemIni." || ARG(1))
  2319.     filler   = "      ["
  2320.  
  2321.     SAY filename || "]"
  2322.  
  2323.     tmp = ""
  2324.  
  2325.     /* filename can be arbitrarily long */
  2326.     DO WHILE filename <> ''     
  2327.        IF LENGTH(filename) >= global.config.showLineLength THEN
  2328.        DO
  2329.           tmp = SUBSTR(filename, 1, global.config.showLineLength - 1) || "]"
  2330.           filename = filler || SUBSTR(filename, global.config.showLineLength)
  2331.        END
  2332.        ELSE
  2333.        DO
  2334.           tmp = filename || "] "
  2335.           tmp = LEFT(tmp, global.config.showLineLength, "=")
  2336.           filename = ""
  2337.        END
  2338.  
  2339.        CALL LINEOUT global.outFile, tmp 
  2340.     END
  2341.  
  2342.     /* show # of TopLevel entries */
  2343.     tmp = LEFT("TopL# [" || stemTopLevel.0 "TopLevel(s)] ", global.config.showLineLength, "=")
  2344.     CALL LINEOUT global.outFile, tmp
  2345.  
  2346.  
  2347.     CALL LINEOUT global.outFile, ""     /* empty line */
  2348.     RETURN
  2349.  
  2350. /*
  2351.    write TopLevel entry
  2352. */
  2353. OUTPUT_TOPIC: PROCEDURE EXPOSE global. stemTopLevel.
  2354.     iInd = ARG(1)
  2355.  
  2356.     tmpDisplay = stemTopLevel.iInd
  2357.     tmpFiltered = ""
  2358.  
  2359.     SAY LEFT(global.format.forTop || "[" || tmpDisplay || "]", global.iColumns - 1)
  2360.  
  2361.     IF stemTopLevel.iInd.type = "H" THEN
  2362.     DO
  2363.        IF global.config.showHexAs = "H" | global.config.showHexAs = "B" THEN
  2364.           tmpDisplay = SUBSTR(tmpDISPLAY, 3, LENGTH(tmpDisplay) - 3)
  2365.        ELSE
  2366.           tmpDisplay = ""
  2367.  
  2368.        IF global.config.showHexAs = "F" | global.config.showHexAs = "B" THEN
  2369.            tmpFiltered = stemTopLevel.iInd.FilterValue
  2370.     END
  2371.  
  2372.     global.config.showDataLength = global.config.showLineLength - (global.format.forTop.Length + 7)   /* "[A0] [" ..."]" longest append */
  2373.     CALL print_go_do_it_finally_god_damn_it global.format.forTop, global.format.forTop.LeadIn, stemTopLevel.iInd.type, tmpDisplay, tmpFiltered
  2374.     RETURN
  2375.  
  2376.  
  2377. /*
  2378.    write Key entry
  2379. */
  2380. OUTPUT_KEY: PROCEDURE EXPOSE global. stemKey.
  2381.     iInd = ARG(1)
  2382.  
  2383.     tmpDisplay = stemKey.iInd
  2384.     tmpFiltered = ""
  2385.  
  2386.     SAY LEFT(global.format.forKey || "[" || tmpDisplay || "]", global.iColumns - 1)
  2387.  
  2388.     IF stemKey.iInd.type = "H" THEN
  2389.     DO
  2390.        IF global.config.showHexAs = "H" | global.config.showHexAs = "B" THEN
  2391.           tmpDisplay = SUBSTR(tmpDISPLAY, 3, LENGTH(tmpDisplay) - 3)
  2392.        ELSE
  2393.           tmpDisplay = ""
  2394.  
  2395.        IF global.config.showHexAs = "F" | global.config.showHexAs = "B" THEN
  2396.            tmpFiltered = stemKey.iInd.FilterValue
  2397.     END
  2398.  
  2399.     global.config.showDataLength = global.config.showLineLength - (global.format.forKey.Length + 7)   /* "[A0] [" ..."]" longest append */
  2400.     CALL print_go_do_it_finally_god_damn_it global.format.forKey, global.format.forKey.LeadIn, stemKey.iInd.type, tmpDisplay, tmpFiltered
  2401.     RETURN
  2402.  
  2403.  
  2404. /*
  2405.    write Key value
  2406. */
  2407. OUTPUT_VAL: PROCEDURE EXPOSE global.
  2408.     CALL check_value ARG(1)
  2409.  
  2410.     tmpDisplay = strings.DisplayValue
  2411.     tmpFiltered = ""
  2412.  
  2413.     IF strings.type = "H" THEN
  2414.     DO
  2415.        IF global.config.showHexAs = "H" | global.config.showHexAs = "B" THEN
  2416.           tmpDisplay = SUBSTR(tmpDISPLAY, 3, LENGTH(tmpDisplay) - 3)
  2417.        ELSE
  2418.           tmpDisplay = ""
  2419.  
  2420.        IF global.config.showHexAs = "F" | global.config.showHexAs = "B" THEN
  2421.            tmpFiltered = strings.FilterValue
  2422.     END
  2423.  
  2424.     global.config.showDataLength = global.config.showLineLength - (global.format.forVal.Length + 7)   /* "[A0] [" ..."]" longest append */
  2425.     CALL print_go_do_it_finally_god_damn_it global.format.forVal, global.format.forVal.LeadIn, strings.type, tmpDisplay, tmpFiltered
  2426.     RETURN
  2427.  
  2428.  
  2429.  
  2430. PRINT_GO_DO_IT_FINALLY_GOD_DAMN_IT: PROCEDURE EXPOSE global.
  2431.     title    = ARG(1)
  2432.     leadin   = ARG(2)
  2433.     type     = ARG(3)
  2434.     display  = ARG(4)
  2435.     filtered = ARG(5)     
  2436.  
  2437.     tmp1 = title
  2438.     type_name = LEFT(VALUE("global.dtype." || type), 4) || " ["
  2439.  
  2440.     DO WHILE display <> ""
  2441.        IF LENGTH(display) > global.config.showDataLength THEN
  2442.        DO
  2443.           tmp = SUBSTR(display, 1, global.config.showDataLength)
  2444.           display = SUBSTR(display, global.config.showDataLength + 1)
  2445.        END
  2446.        ELSE
  2447.        DO
  2448.           tmp = display
  2449.           display = ""
  2450.        END
  2451.  
  2452.        CALL LINEOUT global.outFile, tmp1 || type_name || tmp || "]"
  2453.        tmp1 = leadin
  2454.     END
  2455.  
  2456.     IF type = "H" & filtered <> "" THEN
  2457.     DO
  2458.        type_name = LEFT(VALUE("global.dtype." || "F"), 4)  || " ["   /* for ASCII-filtered strings */
  2459.    
  2460.        DO WHILE filtered <> ""
  2461.           IF LENGTH(filtered) > global.config.showDataLength THEN
  2462.           DO
  2463.              tmp = SUBSTR(filtered, 1, global.config.showDataLength)
  2464.              filtered = SUBSTR(filtered, global.config.showDataLength + 1)
  2465.           END
  2466.           ELSE
  2467.           DO
  2468.              tmp = filtered
  2469.              filtered = ""
  2470.           END
  2471.    
  2472.           CALL LINEOUT global.outFile, tmp1 || type_name || tmp || "]"
  2473.           tmp1 = leadin
  2474.        END
  2475.     END
  2476.  
  2477.     RETURN
  2478.  
  2479.  
  2480.  
  2481. /* ask user for the filename into which output should be printed */
  2482. GET_FILENAME: PROCEDURE EXPOSE global.
  2483.     IF global.outFile = "" THEN
  2484.        tmpResult = DIRECTORY() || "\"   /* supply current directory as default */
  2485.     ELSE
  2486.        tmpResult = global.outFile
  2487.  
  2488.     DO FOREVER
  2489.        SAY
  2490.        SAY "Enter file name:"
  2491.        SAY
  2492.        PARSE VALUE edit_value("E", tmpResult, "A", , "Enter new File-name") WITH tmpState tmpResult
  2493.  
  2494.        IF tmpState = "OK" THEN          /* check whether file exists already */
  2495.        DO
  2496.           IF STREAM(tmpResult, "C", "QUERY EXISTS") <> "" THEN
  2497.           DO
  2498.              CALL BEEP 2000, 250
  2499.              SAY
  2500.              SAY global.iYellow || tmpResult || global.iCyan "exists already !"
  2501.  
  2502.              SAY
  2503.              SAY "       " global.iYellow || "D" global.iCyan "delete existing file"
  2504.              SAY "       " global.iYellow || "A" global.iCyan "append to existing file"
  2505.              SAY "       " global.iCyan   || "   [Esc] to return"
  2506.           
  2507.              /* define choices and get answer from user */
  2508.              CALL CHAROUT , global.iYellow
  2509.              answer = get_answer("DAQ", , "NO-CR")   /* force an entry */
  2510.              CALL CHAROUT , global.iCyan
  2511.       
  2512.              SELECT
  2513.                 WHEN answer = "1B"x THEN RETURN 0     /* Escape was pressed */
  2514.                 WHEN answer = "Q" THEN SIGNAL halt
  2515.                 WHEN answer = "D" THEN                /* delete existing file */
  2516.                      DO
  2517.                         ADDRESS CMD "@DEL" tmpResult /* let OS/2 erase it */
  2518.                         IF RC <> 0 THEN
  2519.                         DO
  2520.                            SAY
  2521.                            CALL error_msg tmpResult || global.iCyan "could not be deleted, aborting..."
  2522.                            RETURN 0
  2523.                         END
  2524.                      END
  2525.       
  2526.                 OTHERWISE NOP
  2527.              END  
  2528.              LEAVE
  2529.           END
  2530.           ELSE       /* file does not exist yet, create it */
  2531.           DO
  2532.              IF STREAM(tmpResult, "C", "Open Write") <> "READY:" THEN        /* error while creating file */
  2533.              DO
  2534.                 SAY
  2535.                 CALL error_msg global.iYellow || tmpResult global.iRedWhite || "could not be created !"
  2536.  
  2537.                 CALL CHAROUT , "Try another filename ?" global.yesHint
  2538.                 answer = get_answer("YNQ")
  2539.                 CALL CHAROUT , global.iCyan
  2540.          
  2541.                 SELECT
  2542.                    WHEN answer = "1B"x THEN RETURN 0     /* Escape was pressed */
  2543.                    WHEN answer = "Q" THEN SIGNAL halt
  2544.                    WHEN answer = "Y" || answer = "" THEN ITERATE
  2545.                    OTHERWISE RETURN 0
  2546.                 END
  2547.              END
  2548.           END
  2549.        END
  2550.        ELSE RETURN 0
  2551.  
  2552.        LEAVE
  2553.     END
  2554.     global.outFile = tmpResult
  2555.  
  2556.     RETURN 1
  2557.  
  2558. /***********************************************************************************************/
  2559.  
  2560. /*
  2561.    display error message passed in ARG(1)
  2562.    if ARG(2) given, then do not prompt user for keyboard-input, return immediately
  2563. */
  2564. ERROR_MSG: PROCEDURE EXPOSE global.
  2565.     SAY global.iRedWhite || ARG(1)  global.iCyan
  2566.     IF ARG() = 1 THEN
  2567.     DO
  2568.        CALL BEEP 2000, 250
  2569.        SAY "press any key to continue..."
  2570.        tmp = SysGetKey("NOECHO")
  2571. /*
  2572.        IF TRANSLATE(tmp) = "Q" THEN SIGNAL halt         /* quit immediately */
  2573. */
  2574.        SAY
  2575.     END
  2576.     RETURN
  2577.  
  2578.  
  2579. HALT:
  2580.    IF global.outFile <> "" THEN         /* interrupted while writing to file */
  2581.    DO
  2582.       CALL STREAM global.outFile, "C", "CLOSE"  /* close file */
  2583.    END
  2584.  
  2585.    SAY 
  2586.    SAY global.iNormal || "User interrupted application."
  2587.    EXIT -1                              /* user interrupt       */
  2588.  
  2589.  
  2590. /* ********************** ********************** *********************** ****************** */
  2591.  
  2592. öööö
  2593.  
  2594. BACKUP_RESTORE_UPDATE: PROCEDURE EXPOSE global.
  2595.  
  2596. PARSE ARG WITH '/'switch filename
  2597.  
  2598. /* check  arguments */
  2599. switch = TRANSLATE(switch)
  2600. global.iBackupMode = "Quiet !"
  2601.  
  2602. /* check whether file exists */
  2603. IF filename = "" THEN sourceFile = ""
  2604.                  ELSE sourceFile = STREAM(filename, "C", "QUERY EXISTS")
  2605.  
  2606. /* debug */
  2607. say "**Debug: sourceFile >"sourceFile"<"
  2608. say "**Debug: filename   >"fileName"<"
  2609.  
  2610. IF sourceFile = "" THEN
  2611. DO
  2612.    SIGNAL usage
  2613. END
  2614.  
  2615. global.iBackupMode.iDrive = FILESPEC("drive", sourceFile)
  2616. global.iBackupMode.iPath  = FILESPEC("path",  sourceFile)
  2617.  
  2618. SELECT
  2619.    WHEN switch = "B" THEN       /* backup to an OS2-INI-file */
  2620.         DO
  2621.            SAY global.iCyan || "BACKUP-MODE: backup will be an OS/2-INI-file." || global.iNormal
  2622.            SAY
  2623.  
  2624.            global.bkpFileName = get_next_file(sourceFile)         /* get name of the new backup-file */
  2625.            CALL make_backup sourceFile, global.bkpFileName           /* backup the INI-file */
  2626.         END
  2627.  
  2628.    WHEN switch = "BT" THEN      /* backup to an ASCII-file */
  2629.         DO
  2630.            SAY global.iCyan || "BACKUP-MODE: backup will be an ASCII-file." || global.iNormal
  2631.            SAY
  2632.            CALL check_if_ini sourceFile
  2633.  
  2634.  
  2635.            /* backup-ASCII-file gets a file extension of "TXT", hence 10 backups from "TX0" thru "TX9" */
  2636.            tmpName  = FILESPEC("name",  sourceFile)
  2637.  
  2638.            pointPos = LASTPOS(".", tmpName)
  2639.            IF pointPos = 0 THEN tmpName = tmpName || ".TXT"
  2640.                            ELSE tmpName = SUBSTR(tmpName, 1, pointPos) || "txt"
  2641.  
  2642.            /* build name of the new backup-file */
  2643.            global.outFile = get_next_file(global.iBackupMode.iDrive ||,
  2644.                                           global.iBackupMode.iPath ||,
  2645.                                           tmpName)
  2646.  
  2647.            stemIni.0 = 1                        /* number of entries */
  2648.            stemIni.1 = sourceFile               /* assign OS/2-INI-file-name to be printed into an ASCII-file */
  2649.  
  2650.            IF global.config.showDepth <> "V" THEN       /* show everything ? */
  2651.               global.config.showDepth = "V"     /* set switch to show everything */
  2652.  
  2653.            IF global.config.showHexAs = "F" THEN        /* show filtered ASCII-string only ? */               
  2654.               global.config.showHexAs = "B"             /* show both, hexadecimal and filtered value */
  2655.  
  2656.            SAY
  2657.            SAY global.iCyan || "Source (OS/2-INI-file):" global.iYellow || sourceFile
  2658.            SAY global.iCyan || "Target (backup-file):  " global.iYellow || global.outFile || global.iNormal
  2659.            SAY
  2660.  
  2661.  
  2662.            CALL read_toplevel 1                 /* read & prepare TopLevel entries, do not sort them */
  2663.  
  2664.            CALL print 1                         /* call print-procedure, have all TopLevels printed */
  2665.            CALL STREAM global.outFile, "C", "CLOSE"     /* close output file */
  2666.         END
  2667.  
  2668.    WHEN switch = "R" | switch = "U" THEN        /* restore or update from an OS/2-INI-file */
  2669.         DO
  2670.            IF switch = "R" THEN tmp = "RESTORE"
  2671.                            ELSE tmp = "UPDATE"
  2672.  
  2673.            SAY global.iCyan || tmp || "-MODE: backup to read from will be an OS/2-INI-file." || global.iNormal
  2674.            SAY
  2675.  
  2676.            targetIni = getBkpData_Ini(sourceFile)       /* get target INI-name from INI-bkp */
  2677.            CALL ini_restore_from_ini sourceFile, targetIni, switch     /* restore/update original */
  2678.            CALL STREAM sourceFile, "C", "CLOSE"         /* close input file */
  2679.         END
  2680.  
  2681.    WHEN switch = "RT" | switch = "UT" THEN      /* restore or update from an ASCII-file */
  2682.         DO
  2683.            IF switch = "RT" THEN tmp = "RESTORE"
  2684.                             ELSE tmp = "UPDATE"
  2685.  
  2686.            SAY global.iCyan || tmp || "-MODE: backup to read from will be an ASCII-file." || global.iNormal
  2687.            SAY
  2688.  
  2689.            CALL ini_restore_from_txt sourceFile, switch /* use ASCII-file for restore */
  2690.            CALL STREAM sourceFile, "C", "CLOSE"         /* close input file */
  2691.         END
  2692.  
  2693.  
  2694.    OTHERWISE 
  2695.         DO
  2696.            SAY global.iYellow || "Invalid argument!" global.iYellow || switch || global.iNormal
  2697.            SIGNAL USAGE
  2698.         END
  2699. END  
  2700.  
  2701. EXIT 0          /* finished batch-mode */
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707. /*************************************************************************************/
  2708.  
  2709. /*
  2710.    restores/updates from an INI-file
  2711.    if restore, then delete TopLevels and Keys in original which are not found in the backup
  2712. */
  2713. INI_RESTORE_FROM_TXT: PROCEDURE EXPOSE global. 
  2714.     bkpIniFile  = ARG(1)
  2715.     switch      = ARG(2)
  2716.     done        = 0
  2717.     line        = ""
  2718.  
  2719.     /* get target filename */
  2720.     DO WHILE LINES(bkpIniFile) > 0
  2721.        IF line = "" & done THEN LEAVE
  2722.        line = LINEIN(bkpIniFile)
  2723.        PARSE VAR line key "[" value "]" rest
  2724.  
  2725.        IF SUBSTR(STRIP(key), 1, 1) = ";" THEN ITERATE   /* ignore comments */
  2726.  
  2727.        key = TRANSLATE(key)             /* translate key into uppercase */
  2728.  
  2729.        IF key = "FILE" THEN
  2730.        DO
  2731.           done = 1
  2732.           IF rest <> "" THEN            /* right square bracket part of filename ? */
  2733.           DO
  2734.              right_bracket = LASTPOS("]", rest)
  2735.              IF right_bracket > 0 THEN
  2736.              DO
  2737.                 value = value || "]"
  2738.                 IF right_bracket > 1 THEN
  2739.                    value = value || SUBSTR(rest, 1, right_bracket-1)
  2740.              END
  2741.  
  2742.           END
  2743.  
  2744.           targetIniFile = value
  2745.  
  2746.           /* now check, whether file spans multiple lines */
  2747.           DO WHILE LINES(bkpIniFile) > 0
  2748.              line = LINEIN(bkpIniFile)
  2749.                             /* comment-line ? */
  2750.              IF line = "" | SUBSTR(STRIP(line), 1, 1) = ";" THEN LEAVE          /* finished reading filename */
  2751.  
  2752.              PARSE VAR line key "[" value
  2753.              IF key <> "" THEN LEAVE            /* TopL# - key comes along */
  2754.  
  2755.              targetIniFile = targetIniFile || SUBSTR(value, 1, LASTPOS("]", value) - 1)
  2756.           END
  2757.           LEAVE
  2758.        END
  2759.     END 
  2760.  
  2761.  
  2762.     IF \done THEN
  2763.     DO
  2764.        CALL BEEP 2500, 250
  2765.        SAY global.iCyan || "ASCII-file" global.iYellow || bkpIniFile global.iRedWhite ||   "does not contain a vaild INI-backup !" || global.iNormal
  2766.        EXIT -3
  2767.     END
  2768.  
  2769.  
  2770.     /******************************/
  2771.     /* check validity of INI-file */
  2772.     century = SUBSTR(DATE("S"), 1, 2)    /* get century information */
  2773.  
  2774.     /* file to restore must be in the same directory as backup */
  2775.     tmpFile = global.iBackupMode.iDrive ||,
  2776.               global.iBackupMode.iPath ||,
  2777.               FILESPEC("name", targetIniFile)
  2778.  
  2779.     tmpResult = STREAM(tmpFile, "C", "QUERY EXISTS")
  2780.  
  2781.     IF tmpResult = "" THEN              /* does not exist in backup directory */
  2782.     DO
  2783.        CALL BEEP 2000, 250
  2784.        SAY global.iCyan || "Target-INI-file:" global.iYellow || tmpFile global.iCyan || "not found!" || global.iNormal
  2785.        SAY
  2786.  
  2787.        tmp = "Create it ?" global.yesHint
  2788.        global.answer = 1                              /* default to yes */
  2789.  
  2790.        IF \get_yes_no(tmp, "global.answer") THEN EXIT -1        /* user aborted backup */
  2791.  
  2792.        IF global.answer THEN origIniFile = tmpFile
  2793.                         ELSE EXIT -1                            /* user aborted backup */
  2794.     END
  2795.     ELSE
  2796.        origIniFile = tmpResult
  2797.    
  2798.     /* get date/time of target, i.e. INI-file */
  2799.     tmpDateTime = STREAM(origIniFile, "C", "QUERY DATETIME")
  2800.    
  2801.     IF tmpDateTime <> '' THEN
  2802.     DO
  2803.         /* make a sorted day from the American bound date-format  ! */
  2804.         PARSE VAR tmpDateTime month"-"day"-"year time
  2805.         tmpOrigDateTime = century || year || month || day time
  2806.     END
  2807.     ELSE
  2808.        tmpOrigDateTime = RIGHT("-", 8) RIGHT("-", 8)
  2809.    
  2810.     /* get date/time of backup */
  2811.     tmpDateTime = STREAM(bkpIniFile, "C", "QUERY DATETIME")
  2812.    
  2813.     IF tmpDateTime <> '' THEN
  2814.     DO
  2815.         /* make a sorted day from the American bound date-format  ! */
  2816.         PARSE VAR tmpDateTime month"-"day"-"year time
  2817.         tmpBkpDateTime = century || year || month || day time
  2818.     END
  2819.    
  2820.     SAY global.iCyan || "Backup:   (" || global.iYellow || tmpBkpDateTime  || global.iCyan || ")" global.iYellow || bkpIniFile
  2821.     SAY global.iCyan || "Original: (" || global.iYellow || tmpOrigDateTime || global.iCyan || ")" global.iYellow || origIniFile || global.iNormal
  2822.  
  2823.  
  2824.     /***********/
  2825.     /* restore */
  2826.  
  2827.     DROP stemTopLevel.
  2828.     stemTopLevel. = ""
  2829.     stemTopLevel.0 = 0          /* no entries into this array */
  2830.  
  2831.     DROP stemKey.
  2832.     stemKey. = ""
  2833.     stemKey.0 = 0               /* no entries into this array */
  2834.  
  2835.     DROP tmp.
  2836.     tmp. = ""
  2837.  
  2838.     ITop = 0                   
  2839.     iKey = 0
  2840.     iVal = 0
  2841.  
  2842.     DO WHILE LINES(bkpIniFile) > 0
  2843.        line = LINEIN(bkpIniFile)                /* read next line */
  2844.  
  2845.                       /* comment ? */
  2846.        IF line = "" | SUBSTR(STRIP(line), 1, 1) = ";" THEN ITERATE      /* iterate on empty line */
  2847.  
  2848.        PARSE VAR line key "[" type "]" "[" value "]" rest
  2849.  
  2850.        type = TRANSLATE(type)                   /* translate types into uppercase */
  2851.        IF type = "F" THEN ITERATE               /* hexadecimal representation with filtered ASCII-strings is ignored */
  2852.  
  2853.        key = TRANSLATE(key)                     /* translate keys into uppercase */
  2854.  
  2855.        IF SUBSTR(type, 1, 1) = "A" THEN         /* is value an ASCII-string ? */
  2856.           IF rest <> "" THEN                    /* right square bracket is part of ASCII-string ! */
  2857.           DO
  2858.              right_bracket = LASTPOS("]", rest)
  2859.              IF right_bracket > 0 THEN
  2860.              DO
  2861.                 value = value || "]"
  2862.                 IF right_bracket > 1 THEN
  2863.                    value = value || SUBSTR(rest, 1, right_bracket-1)
  2864.              END
  2865.  
  2866.           END
  2867.  
  2868.  
  2869.        SELECT
  2870.           WHEN key <> ""  THEN                  /* new Key */
  2871.                DO
  2872.                   SELECT
  2873.                      WHEN key = "TOP" THEN
  2874.                           DO
  2875.                              IF iVal THEN 
  2876.                              DO
  2877.                                 IF iTop THEN    /* same as previous TopLevel */
  2878.                                    CALL update_ini origIniFile   /* set value in hand */
  2879.                                 ELSE
  2880.                                    CALL update_ini origIniFile, "new Top"   /* set value in hand */
  2881.                              END
  2882.  
  2883.                              SAY global.iCyan || "Toplevel #" global.iYellow || stemTopLevel.0 + 1 || global.iNormal
  2884.  
  2885.                              IF stemKey.0 > 0 & switch = "RT" THEN      /* restore mode, delete all keys not in backup of present TopLevel */
  2886.                                    CALL delete_non_backedup_keys origIniFile, VALUE("stemTopLevel." || stemTopLevel.0)
  2887.  
  2888.                              DROP stemKey.
  2889.                              stemKey. = ""
  2890.                              stemKey.0 = 0               /* no entries into this array */
  2891.  
  2892.                              tmp.toppy               = value
  2893.                              tmp.toppy.typeIndicator = type
  2894.                              iTop = 0
  2895.                              iKey = 0
  2896.                              iVal = 0
  2897.                           END
  2898.  
  2899.                      WHEN key = "KEY" THEN
  2900.                           DO
  2901.                              IF iVal THEN 
  2902.                              DO
  2903.                                 IF iTop THEN    /* same as previous TopLevel */
  2904.                                    CALL update_ini origIniFile   /* set value in hand */
  2905.                                 ELSE
  2906.                                 DO
  2907.                                    CALL update_ini origIniFile, "new Top"   /* set value in hand */
  2908.                                    iTop = 1
  2909.                                 END
  2910.                              END
  2911.  
  2912.                              SAY global.iCyan || "             Key #" global.iYellow || stemKey.0 + 1 || global.iNormal
  2913.  
  2914.                              tmp.keyiy               = value
  2915.                              tmp.keyiy.typeIndicator = type
  2916.                              iKey = 1
  2917.                              iVal = 0
  2918.                           END
  2919.  
  2920.                      WHEN key = "VAL" THEN
  2921.                           DO
  2922.                              tmp.valuly               = value
  2923.                              tmp.valuly.typeIndicator = type
  2924.                              iVal = 1
  2925.                           END
  2926.                      OTHERWISE NOP
  2927.                   END 
  2928.                END
  2929.  
  2930.           OTHERWISE     /* add the next piece to the value */
  2931.                DO
  2932.                   SELECT
  2933.                      WHEN iVal THEN
  2934.                           tmp.valuly = tmp.valuly || value
  2935.  
  2936.                      WHEN iKey THEN
  2937.                           tmp.keyiy = tmp.keyiy || value
  2938.  
  2939.                      OTHERWISE 
  2940.                           tmp.toppy = tmp.toppy || value
  2941.                   END  
  2942.                END
  2943.        END  
  2944.     END
  2945.  
  2946.  
  2947.     IF iVal THEN 
  2948.     DO
  2949.        IF iTop THEN    /* same as previous TopLevel */
  2950.           CALL update_ini origIniFile   /* set value in hand */
  2951.        ELSE
  2952.           CALL update_ini origIniFile, "new Top"   /* set value in hand */
  2953.     END
  2954.  
  2955.     IF switch = "RT" THEN               /* restore mode, delete all keys not in backup */
  2956.     DO
  2957.        /* TopLevel in hand */
  2958.        CALL delete_non_backedup_keys origIniFile, VALUE("stemTopLevel." || stemTopLevel.0)
  2959.        CALL delete_non_backedup_toplevels origIniFile
  2960.     END
  2961.  
  2962.     RETURN
  2963.  
  2964.  
  2965.  
  2966. /*
  2967.    transform values, update stemTopLevel., stemKey., update target INI-file with new key
  2968.    if a second argument is given, then we have a new TopLevel being built, if there is an
  2969.    old one it has to be stored in the array
  2970. */
  2971. UPDATE_INI: PROCEDURE EXPOSE global. stemTopLevel. stemKey. tmp.
  2972.     origIniFile = ARG(1)
  2973.     iTop = stemTopLevel.0
  2974.  
  2975.     IF ARG() = 2 | iTop = 0 THEN        /* build a new TopLevel ? */
  2976.     DO
  2977.        iTop = iTop + 1
  2978.        SELECT
  2979.           WHEN tmp.toppy.typeIndicator = "H" THEN  /* hexadecimal value */
  2980.                stemTopLevel.iTop = X2C(tmp.toppy)
  2981.           WHEN tmp.toppy.typeIndicator = "A" THEN
  2982.                stemTopLevel.iTop = tmp.toppy
  2983.           WHEN tmp.toppy.typeIndicator = "A0" THEN
  2984.                stemTopLevel.iTop = tmp.toppy || "00"x
  2985.           OTHERWISE             /* illegal data-type */
  2986.                   RETURN
  2987.        END
  2988.        stemTopLevel.0 = iTop
  2989.     END
  2990.  
  2991.     iKey = stemKey.0
  2992.     iKey = iKey + 1
  2993.     stemKey.0 = iKey
  2994.  
  2995.     SELECT
  2996.        WHEN tmp.keyiy.typeIndicator = "H" THEN  /* hexadecimal value */
  2997.             stemKey.iKey = X2C(tmp.keyiy)
  2998.        WHEN tmp.keyiy.typeIndicator = "A" THEN
  2999.             stemKey.iKey = tmp.keyiy
  3000.        WHEN tmp.keyiy.typeIndicator = "A0" THEN
  3001.             stemKey.iKey = tmp.keyiy || "00"x
  3002.        OTHERWISE             /* illegal data-type */
  3003.                RETURN
  3004.     END
  3005.  
  3006.     SELECT
  3007.        WHEN tmp.valuly.typeIndicator = "H" THEN  /* hexadecimal value */
  3008.             value = X2C(tmp.valuly)
  3009.        WHEN tmp.valuly.typeIndicator = "A" THEN
  3010.             value = tmp.valuly
  3011.        WHEN tmp.valuly.typeIndicator = "A0" THEN
  3012.             value = tmp.valuly || "00"x
  3013.        OTHERWISE             /* illegal data-type */
  3014.                RETURN
  3015.     END
  3016.  
  3017.     CALL SysIni origIniFile, stemTopLevel.iTop, stemKey.iKey, value     /* set new value */
  3018.     RETURN
  3019.  
  3020.  
  3021.  
  3022.  
  3023. /*
  3024.    restores/updates from an INI-file
  3025.    if restore, then delete TopLevels and Keys in original which are not found in the backup
  3026. */
  3027. INI_RESTORE_FROM_INI: PROCEDURE EXPOSE global.
  3028.     sourceFile = ARG(1)         /* backup-INI-file */
  3029.     targetFile = ARG(2)         
  3030.     switch     = ARG(3)         /* if "R", then delete superfluous TopLevels and Keys in the original */
  3031.  
  3032.     CALL SysIni sourceFile, 'ALL:', 'stemTopLevel'
  3033.  
  3034.     DO i = 1 TO stemTopLevel.0          /* cycle thru all TopLevels */
  3035.        DROP stemKey.
  3036.        stemKey. = ""
  3037.        SAY global.iCyan || "Toplevel #" global.iYellow || i global.iCyan || "of" global.iYellow || stemTopLevel.0 || global.iNormal
  3038.  
  3039.        CALL SysIni sourceFile, stemTopLevel.i, 'ALL:', 'stemKey'
  3040.  
  3041.        DO j = 1 TO stemKey.0            /* cycle thru all Keys */
  3042.           SAY global.iCyan || "             Key #" global.iYellow || j global.iCyan || "of" global.iYellow || stemKey.0  || global.iNormal
  3043.           value = SysIni(sourceFile, stemTopLevel.i, stemKey.j)         /* get value */
  3044.           tmp =   SysIni(targetFile, stemTopLevel.i, stemKey.j, value)  /* set value */
  3045.        END 
  3046.  
  3047.        IF switch = "R" THEN             /* restore mode, delete all keys not in backup */
  3048.           CALL delete_non_backedup_keys targetFile, stemTopLevel.i
  3049.     END
  3050.  
  3051.     IF switch = "R" THEN             /* restore mode, delete all targets not in backup */
  3052.        CALL delete_non_backedup_toplevels targetFile
  3053.  
  3054.     RETURN
  3055.  
  3056.  
  3057.  
  3058.  
  3059.  
  3060.  
  3061. /*
  3062.    for restore-mode only: delete keys in target which are not in backup
  3063. */
  3064. DELETE_NON_BACKEDUP_KEYS: PROCEDURE EXPOSE stemKey. stemTargetKey. global.
  3065.    targetFile = ARG(1)
  3066.    TopLevel   = ARG(2)
  3067.  
  3068.    stemTargetKey. = ""
  3069.  
  3070.    CALL SysIni targetFile, TopLevel, "ALL:", "stemTargetKey"
  3071.    CALL sort_generic "stemKey", "EXACT"          /* sort backup-keys */
  3072.    CALL sort_generic "stemTargetKey", "EXACT"    /* sort target-keys */
  3073.  
  3074.    i = 1
  3075.    j = 1
  3076.    DO FOREVER                    /* delete keys, which cannot be found in the backup */
  3077.       SELECT
  3078.          WHEN stemKey.i << stemTargetKey.j THEN          /* delete superfluous keys */
  3079.               DO
  3080.                  IF i > stemKey.0 THEN
  3081.                  DO
  3082.                     DO k = j to stemTargetKey.0
  3083.                        CALL BEEP 2000, 100
  3084.                        SAY global.iCyan || "deleting key:" global.iYellow || stemTargetKey.k global.iNormal || global.iNormal
  3085.                        CALL SysIni targetFile, TopLevel, stemTargetKey.k, "DELETE:"
  3086.                     END
  3087.                     LEAVE
  3088.                  END
  3089.                  ELSE                   /* duplicate in bkp-keys, if so it comes from TXT-file */
  3090.                    i = i + 1
  3091.               END
  3092.  
  3093.          WHEN stemKey.i == stemTargetKey.j THEN          /* identical, o.k. */
  3094.               DO
  3095.                  i = i + 1
  3096.                  j = j + 1
  3097.                  IF j > stemTargetKey.0 THEN LEAVE       /* finished */
  3098.               END
  3099.  
  3100.          OTHERWISE /* stemKey.i >> stemTargetKey.j THEN  ... delete superfluous key */
  3101.               DO
  3102.                  CALL BEEP 2000, 100
  3103.                  SAY global.iCyan || "deleting key:" global.iYellow || stemTargetKey.j global.iNormal || global.iNormal
  3104.  
  3105.                  CALL SysIni targetFile, TopLevel, stemTargetKey.j, "DELETE:"
  3106.                  j = j + 1
  3107.               END
  3108.       END
  3109.    END
  3110.    RETURN
  3111.  
  3112.  
  3113. /*
  3114.    for restore-mode only: delete TopLevels in target which are not in backup
  3115. */
  3116. DELETE_NON_BACKEDUP_TOPLEVELS: PROCEDURE EXPOSE stemTopLevel. global.
  3117.    targetFile = ARG(1)
  3118.  
  3119.    stemTargetTopLevel. = ""
  3120.  
  3121.    CALL SysIni targetFile, "ALL:", "stemTargetTopLevel"
  3122.    CALL sort_generic "stemTopLevel", "EXACT"          /* sort backup-TopLevels */
  3123.    CALL sort_generic "stemTargetTopLevel", "EXACT"    /* sort target-TopLevels */
  3124.  
  3125.    i = 1
  3126.    j = 1
  3127.    DO FOREVER                    /* delete TopLevels, which cannot be found in the backup */
  3128.       SELECT
  3129.          WHEN stemTopLevel.i << stemTargetTopLevel.j THEN          /* delete superfluos TopLevels */
  3130.               DO
  3131.                  IF i > stemTopLevel.0 THEN
  3132.                  DO
  3133.                     DO k = j TO stemTargetTopLevel.0
  3134.                        CALL BEEP 2000, 100
  3135.                        SAY global.iCyan || "deleting topLevel:" global.iYellow || stemTargetTopLevel.k || global.iNormal || global.iNormal
  3136.                        CALL SysIni targetFile, stemTargetTopLevel.k, "DELETE:"
  3137.                     END
  3138.                     LEAVE
  3139.                  END
  3140.                  ELSE                   /* duplicate in bkp-toplevels, if so it comes from TXT-file */
  3141.                    i = i + 1
  3142.               END
  3143.  
  3144.          WHEN stemTopLevel.i == stemTargetTopLevel.j THEN          /* identical, o.k. */
  3145.               DO
  3146.                  i = i + 1
  3147.                  j = j + 1
  3148.                  IF j > stemTargetTopLevel.0 THEN LEAVE       /* finished */
  3149.               END
  3150.  
  3151.          OTHERWISE /* stemTopLevel.i >> stemTargetTopLevel.j THEN  ... delete superfluous key */
  3152.               DO
  3153.                  CALL BEEP 2000, 100
  3154.                  SAY global.iCyan || "deleting topLevel:" global.iYellow || stemTargetTopLevel.j global.iNormal || global.iNormal
  3155.                  CALL SysIni targetFile, stemTargetTopLevel.j, "DELETE:"
  3156.                  j = j + 1
  3157.               END
  3158.       END
  3159.    END
  3160.    RETURN
  3161.  
  3162.  
  3163.  
  3164.  
  3165.  
  3166.  
  3167. /*
  3168.    check whether backup-file is a valid OS/2-INI-file, containing entries
  3169. */
  3170. GETBKPDATA_INI: PROCEDURE EXPOSE global. bkpTopLevel.
  3171.    bkpIniFile = ARG(1)                  /* INI-file containing the backup-data */
  3172.    CALL check_if_ini bkpIniFile         /* check whether INI-file */
  3173.  
  3174.    century = SUBSTR(DATE("S"), 1, 2)    /* get century information */
  3175.    tmpDateTime = STREAM(bkpIniFile, "C", "QUERY DATETIME")
  3176.  
  3177.    /* make a sorted day from the American bound date-format  ! */
  3178.    PARSE VAR tmpDateTime month"-"day"-"year time
  3179.    tmpBkpDateTime = century || year || month || day time
  3180.  
  3181.    origIniFile = SysIni(bkpIniFile, global.config.showTopLevel, global.bkp.iOName)
  3182.  
  3183.    IF origIniFile <> "ERROR:" THEN      /* target must be in same directory as backup */
  3184.    DO
  3185.       origIniFile = global.iBackupMode.iDrive ||,
  3186.                     global.iBackupMode.iPath ||,
  3187.                     FILESPEC("name", origIniFile)
  3188.    END
  3189.  
  3190.    IF origIniFile = "ERROR:" THEN      /* backup was not produced by this program, maybe a copy */
  3191.    DO
  3192.       tmpFile  = FILESPEC("name", bkpIniFile)
  3193.       
  3194.       position = LASTPOS(".", tmpFile)                  /* get last dot in string */
  3195.       IF position < 1 THEN tmpTargetFile = tmpFile || ".INI"
  3196.                       ELSE tmpTargetFile = SUBSTR(tmpFile, 1, position) || "INI"
  3197.  
  3198.       origIniFile = global.iBackupMode.iDrive ||,
  3199.                     global.iBackupMode.iPath ||,
  3200.                     tmpTargetFile        /* put target INI in backup-directory */
  3201.    END
  3202.  
  3203.  
  3204.    tmpResult = STREAM(origIniFile, "C", "QUERY EXISTS") /* check whether INI-file exists */
  3205.  
  3206.    IF tmpResult = "" THEN                               /* not found */
  3207.    DO
  3208.       CALL BEEP 2000, 250
  3209.       SAY global.iCyan || "Target-INI-file:" global.iYellow || origIniFile global.iCyan || "not found!" || global.iNormal
  3210.       SAY
  3211.  
  3212.       tmp = "Create it ?" global.yesHint
  3213.       global.answer = 1                              /* default to yes */
  3214.  
  3215.       IF \get_yes_no(tmp, "global.answer") | \global.answer THEN EXIT -1      /* user aborted backup */
  3216.    END
  3217.    ELSE
  3218.       origIniFile = tmpResult
  3219.  
  3220.  
  3221.    tmpDateTime = STREAM(origIniFile, "C", "QUERY DATETIME")
  3222.  
  3223.    IF tmpDateTime <> '' THEN
  3224.    DO
  3225.        /* make a sorted day from the American bound date-format  ! */
  3226.        PARSE VAR tmpDateTime month"-"day"-"year time
  3227.        tmpOrigDateTime = century || year || month || day time
  3228.    END
  3229.    ELSE
  3230.       tmpOrigDateTime = RIGHT("-", 8) RIGHT("-", 8)
  3231.  
  3232.    SAY global.iCyan || "Backup:   (" || global.iYellow || tmpBkpDateTime  || global.iCyan || ")" global.iYellow || bkpIniFile
  3233.    SAY global.iCyan || "Original: (" || global.iYellow || tmpOrigDateTime || global.iCyan || ")" global.iYellow || origIniFile || global.iNormal
  3234.  
  3235.    RETURN origIniFile
  3236.  
  3237.  
  3238. /*
  3239.         check whether file in hand is an INI-file
  3240. */
  3241. CHECK_IF_INI: PROCEDURE EXPOSE bkpTopLevel. global.
  3242.     iniFile = ARG(1)
  3243.     /* not an OS/2-INI-file or empty ? */
  3244.     val = 0
  3245.  
  3246.     IF SysIni(iniFile, "ALL:", "bkpTopLevel") = "ERROR:" THEN val = -3
  3247.     ELSE
  3248.        IF bkpTopLevel.0 = 0 THEN val = -3
  3249.  
  3250.     IF val < 0 THEN              /* not an OS/2 INI-file */
  3251.     DO
  3252.        CALL BEEP 2000, 250
  3253.        SAY global.iYellow || iniFile || global.iRedWhite ||  ": not an OS/2-INI-file !" || global.iNormal
  3254.        EXIT val
  3255.     END
  3256.  
  3257.     RETURN 
  3258.  
  3259.  
  3260. /*
  3261.         produce an OS/2-INI-backup-file
  3262. */
  3263. MAKE_BACKUP: PROCEDURE EXPOSE global. bkpTopLevel.
  3264.    origIniFile = ARG(1)                 /* INI-file to be backed up */
  3265.    bkpIniFile = ARG(2)                  /* name of backup-INI-file */
  3266.  
  3267.    SAY
  3268.    SAY global.iCyan || "Source (OS/2-INI-file):" global.iYellow || origIniFile
  3269.    SAY global.iCyan || "Target (backup-file):  " global.iYellow || bkpIniFile || global.iNormal
  3270.    SAY
  3271.  
  3272.    /* not an OS/2-INI-file or empty ? */
  3273.    CALL check_if_ini origIniFile
  3274.  
  3275.    /* write information about backup-process and original file-name into INI-file */
  3276.    CALL SysIni bkpIniFile, global.config.showTopLevel, global.bkp.iOName, origIniFile
  3277.    CALL SysIni bkpIniFile, global.config.showTopLevel, global.bkp.iBName, bkpIniFile
  3278.    CALL SysIni bkpIniFile, global.config.showTopLevel, global.bkp.iDTimeStart, DATE("S") TIME()
  3279.    CALL SysIni bkpIniFile, global.config.showTopLevel, global.bkp.iTLentries, bkpTopLevel.0
  3280.  
  3281.    /* cycle thru TopLevel-entries */
  3282.    DO i = 1 TO bkpTopLevel.0               
  3283.       IF SysIni(origIniFile, bkpTopLevel.i, "ALL:", "keys") <> "ERROR:"        /* TopLevel not available anymore */
  3284.       THEN
  3285.       DO
  3286.           DO j = 1 TO keys.0            /* cycle thru Key-entries */
  3287.              val = SysIni(origIniFile, bkpTopLevel.i, keys.j)
  3288.              IF val <> "ERROR:" THEN                                            /* key not available anymore */
  3289.              DO
  3290.                 SAY global.iCyan || "    TopLevel #" global.iYellow || i global.iCyan || "of" global.iYellow || bkpTopLevel.0 global.iCyan || ", Key #" global.iYellow || j global.iCyan || "of" global.iYellow || keys.0 || global.iNormal
  3291.                 CALL SysIni bkpIniFile, bkpTopLevel.i, keys.j, val
  3292.              END
  3293.              ELSE
  3294.                 SAY global.iYellow || " ** error reading TopLevel #" global.iCyan || i || ", Key #" j || global.iNormal
  3295.           END
  3296.        END
  3297.        ELSE
  3298.           SAY global.iYellow || "*** error reading TopLevel #" global.iCyan || i || global.iNormal
  3299.        SAY
  3300.    END
  3301.  
  3302.    CALL SysIni bkpIniFile, global.config.showTopLevel, global.bkp.iDTimeEnd, DATE("S") TIME()
  3303.  
  3304.    SAY global.iCyan || "finished backup." || global.iNormal
  3305.    RETURN
  3306.    
  3307.  
  3308.  
  3309.  
  3310.  
  3311.  
  3312. /*
  3313.         Backup-files contain at the last character position a number ranging
  3314.         from 0 (oldest) to 9 (youngest backup)
  3315. */
  3316. GET_NEXT_FILE: PROCEDURE
  3317.      file = ARG(1)
  3318.      testname = SUBSTR(file, 1, LENGTH(file)-1)
  3319.  
  3320.      slot_found = -1
  3321.      DO i = 0 TO 9
  3322.         new_name = testname || i
  3323.         IF STREAM(new_name, "C", "QUERY EXISTS") <> new_name THEN 
  3324.         DO
  3325.            slot_found = i
  3326.            LEAVE
  3327.         END
  3328.      END
  3329.  
  3330.      IF slot_found = -1 THEN    /* no empty slot found, make room */
  3331.      DO                         /* erase oldest backup and rename the existing ones */
  3332.         CALL make_room testname
  3333.  
  3334.         ADDRESS CMD "@erase" '"' || testname || "0" || '"'         /* erase oldest file */
  3335.    
  3336.         DO i = 1 TO 9
  3337.            ADDRESS CMD "@ren" '"' || testname || i || '" "' || FILESPEC("name", testname || (i - 1)) || '"'
  3338.         END
  3339.  
  3340.         new_name = testname || "9"      /* new backup file */
  3341.      END
  3342.  
  3343.      RETURN new_name
  3344.  
  3345.  
  3346.  
  3347.  
  3348.  
  3349.  
  3350. USAGE:
  3351.    SAY "SHOWINI: allow to view, edit, print, backup, restore OS/2-INI-files"
  3352.    SAY "         (e.g. OS2.INI, OS2SYS.INI)"
  3353.    SAY
  3354.    SAY "showini                       ... allow to work interactively"
  3355.    SAY
  3356.    SAY "backing up: (backing up an OS/2-INI-file entirely)"
  3357.    SAY "==========="
  3358.    SAY "  showini /B  ini-file        ... Backup will be put in a newly created ini-file"
  3359.    SAY "  showini /BT ini-file        ... Backup will be put in a newly created Text-file"
  3360.    SAY
  3361.    SAY "restoring: (resets values according to backup & deletes keys which are not saved in backup)"
  3362.    SAY "=========="
  3363.    SAY "  showini /R  BKP-INI-file    ... Restore from a backup-ini-file"
  3364.    SAY "  showini /RT BKP-TEXT-file   ... Restore from a backup-Text-file"
  3365.    SAY
  3366.    SAY "updating: (just resets values according to backup)"
  3367.    SAY "========="
  3368.    SAY "  showini /U  BKP-INI-file    ... Update from a backup-ini-file"
  3369.    SAY "  showini /UT BKP-TEXT-file   ... Update from a backup-Text-file"
  3370.    EXIT -2              /* wrong switch or wrong file */
  3371.