home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 4 Drivers / 04-Drivers.zip / s2kv201a.zip / RGCUBE.CMD < prev    next >
OS/2 REXX Batch file  |  2001-11-06  |  38KB  |  749 lines

  1. /*
  2.     ╔═══════════════════════════════════════════════════════════════════════╗
  3.     ║                    Config Update/Batch Editing                        ║
  4.     ║                                                                       ║
  5.     ║  Batch update of CONFIG.SYS-like files. CUBE modifies a Target ASCII  ║
  6.     ║  file, given a set of commands in a Procedure file.                   ║
  7.     ║                                                                       ║
  8.     ║  04/06/93: V2.6 - Add 'procedure read from QUEUE' (from Steve Farrell)║
  9.     ║  03/06/93: V2.5 - Add IF/IFNOT to xLINE cmds (generalize N. Marks req)║
  10.     ║                   Correct ADDSTRING BEFORE option  (Neil Marks)       ║
  11.     ║  07/04/93: V2.4 - Corrected ADDBOTTOM/ADDTOP in ADDSTRING (Per Hertz) ║
  12.     ║                   Address cmd + CHECK Option + new exit rtne          ║
  13.     ║  21/01/93: V2.3 - Added user defined string delimiter in CUBE cmds    ║
  14.     ║  21/12/92: V2.2 - Added conditionnal command processing (WHEN)        ║
  15.     ║  26/11/92: V2.1 - RS() for DL, DS (desinstallation case)              ║
  16.     ║                   New LINEID command (strip leading chars)            ║
  17.     ║                   ADDTOP,ADDBOTTOM for AS (W. Pachl requirement)      ║
  18.     ║                   Fix Whereis (Walter Pachl).                         ║
  19.     ║                   Exit with SaveFile return code (Walter Pachl)       ║
  20.     ║  18/11/92: V2.0 - Changes with environment variable substitution (RS) ║
  21.     ║                       (AS, RS, AL & AL now all have same RS() option) ║
  22.     ║                   Logging of all changes made to Target File          ║
  23.     ║                   Adapt/Include some of Walter Pachl's enhancements:  ║
  24.     ║                       Single CUBE command on command line             ║
  25.     ║                       Add'l string substitution at command line level ║
  26.     ║                       PAUSE option (debugging purposes)               ║
  27.     ║  05/11/92: V1.5 - AL with pre substitution                            ║
  28.     ║  03/11/92: V1.4 - AS with substitution ; fix RS recursion.            ║
  29.     ║  02/11/92: V1.3 - Bug fixes & cmds abbrev, thanks to Walter Pachl.    ║
  30.     ║                   Target Backup & lineid no more limited to col 1.    ║
  31.     ║  30/10/92: V1.2 - Added env variable substitution + version #         ║
  32.     ║  31/08/92: V1.1 - Bug fix                                             ║
  33.     ║  21/07/92: V1.0 - Initial revision                                    ║
  34.     ║  Didier LAFON - LAFON at CBEPROFS                                     ║
  35.     ╚═══════════════════════════════════════════════════════════════════════╝ */
  36.  
  37. '@echo off'
  38. version = '2.6'
  39. pf = 0
  40. if left(arg(1),1) = '{' then parse arg '{'PFile'}' TFile Bkup . '(' Opt
  41. else do
  42.   parse arg PFile TFile Bkup . '(' Opt
  43.   pf = 1
  44. end
  45. parse upper source source                          /* who am I ?              */
  46.  
  47. if pf then do
  48.   if PFile = '' then call Exit 0 'no procedure !'    /* no or missing PFile     */
  49.   if Pfile <> 'QUEUE' then if exists(PFile)='' then call Exit 0 PFile 'not found'
  50. end
  51. if TFile = ''  then call Exit 0 'no target !'      /* no or missing Tfile     */
  52. if exists(TFile)='' then call Exit 0 TFile 'not found'
  53.  
  54. pause=(wordpos('PAUSE',translate(Opt))>0)          /* Pause mode ?            */
  55. chkmd=(wordpos('CHECK',translate(Opt))>0)          /* Check mode ?            */
  56. ap = wordpos('MAKE',translate(Opt))                /* make  specified ?       */
  57. if ap>0 then Make=translate(word(Opt,ap+1))        /* ...when                 */
  58.         else Make = '*'                            /* default make = all      */
  59. MWhen='*'                                          /* Default when = all      */
  60. dlm = wordpos('DLM',translate(Opt))                /* New delimiter specified?*/
  61. if dlm>0 then _d_=left(word(Opt,dlm+1),1)          /*   yes use it            */
  62.          else _d_ = '"'                            /* else use default        */
  63. OnErr = 'STOP'                                     /* Default OnError setting */
  64. LStrip= ''                                         /* No lineid strip         */
  65. CaseM = 'I'                                        /* String compare default  */
  66. call get_cmdrs(Opt)
  67. NumberOfChanges = 0
  68.  
  69. say arg
  70. say 'CUBE' version 'applying' PFile 'to' TFile 'on' date() time()
  71. if Bkup <> "" then do
  72.    address cmd 'copy' Tfile Bkup '1>nul 2>nul'
  73.    if rc = 0 then say Tfile 'backup is:' Bkup
  74. end
  75.  
  76. Proc. = ''
  77. if pf then do
  78.    If PFile = 'QUEUE' then Do
  79.      i = 1
  80.      Do Queued()
  81.        Parse Pull procline
  82.        proc.i = proc.i || upkw(procline)
  83.        if right(Proc.i,1) = ','                       /*   continuation char ?   */
  84.          then proc.i=left(proc.i,length(proc.i)-1)' ' /*     yes: blank it out   */
  85.          else  i = i + 1                              /*     no: new Proc line   */
  86.      end
  87.      Proc.0 = i-1                                     /* Proc.0 = # of lines     */
  88.      if Proc.0 <= 0 then call Exit 0 PFile 'empty'
  89.   end
  90.   Else do
  91.      i = 1 ;                                          /* current Proc line: null */
  92.      do while lines(PFile)                            /* for all PFile's lines   */
  93.        Proc.i = Proc.i || upkw(linein(PFile))         /*   concat to Proc line   */
  94.        if right(Proc.i,1) = ','                       /*   continuation char ?   */
  95.          then proc.i=left(proc.i,length(proc.i)-1)' ' /*     yes: blank it out   */
  96.          else  i = i + 1                              /*     no: new Proc line   */
  97.      end
  98.      Proc.0 = i-1                                     /* Proc.0 = # of lines     */
  99.      call close PFile
  100.      if Proc.0 <= 0 then call Exit 0 PFile 'empty'
  101.   End
  102. end
  103. else do
  104.   Proc.0 = 1
  105.   Proc.1 = upkw(Pfile)
  106. end
  107.  
  108. i = 0
  109. do while lines(TFile)                              /* for all TFile's lines   */
  110.   i = i + 1                                        /*   get line in           */
  111.   Target.i = linein(TFile)                         /*   Target. stem          */
  112. end
  113. Target.0 = i                                       /* Target.0 = # of lines   */
  114. call close Tfile
  115.  
  116. /*  ╔═══════════════════════════════════════════════════════════════════════╗
  117.     ║The real thing: go thru procedure file, interpret/execute its commands ║
  118.     ║sequentially.                                                          ║
  119.     ╚═══════════════════════════════════════════════════════════════════════╝ */
  120.  
  121. p = 0                                              /* Proc lines index        */
  122. do while p <= Proc.0                               /* for all PFile's lines   */
  123.   p = p + 1                                        /*   index next line       */
  124.   if Proc.p = '' then iterate                      /*   ignore null lines     */
  125.   parse var Proc.p Verb Parms                      /*   Isolate command verb  */
  126.   say ''
  127.   say '>>>' Proc.p
  128.   Verb = translate(Verb)
  129.   Select                                           /*   Process verb          */
  130.     When left(Verb,1) = '*'   then iterate
  131.     When left(Verb,2) = '--'  then iterate
  132.                /* commands that always get executed  */
  133.     When Verb = 'WHEN'        then call APPLYWHEN
  134.     When Verb = 'ONERROR'     then call ONERROR
  135.     When Verb = 'CASE'        then call CASE
  136.     When Verb = 'LINEID'      then call SLINEID
  137.     When wordpos(Make,MWhen)=0 then iterate
  138.                /* commands executed when WHEN/MAKE match */
  139.     When Verb = 'REPLINE'     | verb = 'RL'  then call REPLINE
  140.     When Verb = 'ADDLINE'     | verb = 'AL'  then call ADDLINE
  141.     When Verb = 'ADDSTRING'   | verb = 'AS'  then call ADDSTRING
  142.     When Verb = 'DELSTRING'   | verb = 'DS'  then call DELSTRING
  143.     When Verb = 'REPSTRING'   | verb = 'RS'  then call REPSTRING
  144.     When Verb = 'COMMENTLINE' | verb = 'CL'  then call COMMENTL
  145.     When Verb = 'DELLINE'     | verb = 'DL'  then call DELLINE
  146.     Otherwise rc=OnErrorDo(p,"Don't know what to do")
  147.   end
  148.   if pause then Pull .
  149. end
  150. if chkmd = 0 then call exit 1 source 'ended.'      /* It's OVER !! and OK !!  */
  151. if chkmd = 1 then call exit 2 source 'ended.'      /*                         */
  152.  
  153. /* ╒═══════════════════════════════════════════════════════════════════════╕
  154.    │  Error report and action (based on Onerr setting, from ONERROR cmd)   ╞
  155.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  156. OnErrorDo:
  157.   parse arg line,msg
  158.   say PFile', line' line':' msg
  159.   if OnErr = 'STOP' then call Exit 0 source 'stopped.'
  160.                     else return 0
  161.  
  162. /* ╒═══════════════════════════════════════════════════════════════════════╕
  163.    │  Searches All or First or Last lines in Target starting with string   ╞
  164.    │  Returns the line number(s) found.                                    ╞
  165.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  166. Whereis: procedure expose Target. CaseM LStrip
  167.  parse arg string,direction,mode
  168.  if wordpos(direction,'F A')>0 then do; de=1; a=Target.0; par=1; end
  169.                                else do; de=Target.0; a=1; par=-1; end
  170.  stringlength=length(string); ret = ''
  171.  do i = de to a by par
  172.    If CaseM = 'S' then do; T = Target.i ; S = string ; end
  173.       else do; T = translate(Target.i) ; S = translate(string) ; end
  174.    If length(LStrip) = 1 then T = strip(T,'L',Lstrip)
  175.    if mode=1 then do
  176.      if left(T,stringlength)=S then do
  177.        ret = ret i
  178.        if direction \= 'A' then leave
  179.      end
  180.    end
  181.    else do
  182.      if pos(S,T) > 0 then do
  183.        ret = ret i
  184.        if direction \= 'A' then leave
  185.      end
  186.    end
  187.  end
  188.  return ret
  189.  
  190. /* ╒═══════════════════════════════════════════════════════════════════════╕
  191.    │  Searches All or First or Last lines in Target starting with string   ╞
  192.    │  Returns the line number(s) found.                                    ╞
  193.    │                                                                       ╞
  194.    │  Hack of Whereis by Ray Gwinn so we will not comment out lines that   ╞
  195.    │  are ALREADY comment lines.                                           ╞
  196.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  197. WhereisHack: procedure expose Target. CaseM LStrip
  198.  parse arg string,direction,mode,CommentString
  199.  if wordpos(direction,'F A')>0 then do; de=1; a=Target.0; par=1; end
  200.                                else do; de=Target.0; a=1; par=-1; end
  201.  stringlength=length(string); CommentStringlength=length(CommentString); ret = ''
  202.  do i = de to a by par
  203.    If CaseM = 'S' then do; T = Target.i ; S = string ; C = CommentString ; end
  204.       else do; T = translate(Target.i) ; S = translate(string) ; C = translate(CommentString) ; end
  205.    if left(T,CommentStringlength) \= C then do
  206.      If length(LStrip) = 1 then T = strip(T,'L',Lstrip)
  207.      if mode=1 then do
  208.        if left(T,stringlength)=S then do
  209.          ret = ret i
  210.          if direction \= 'A' then leave
  211.        end
  212.      end
  213.      else do
  214.        if pos(S,T) > 0 then do
  215.          ret = ret i
  216.          if direction \= 'A' then leave
  217.        end
  218.      end
  219.    end
  220.  end
  221.  return ret
  222.  
  223. /* ╒═══════════════════════════════════════════════════════════════════════╕
  224.    │  Update Target file from Target. stem. Remove '       ' lines ╞
  225.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  226. SaveFile:
  227.  address cmd 'erase' TFile
  228.  src = rc
  229.  if src = 0 then do
  230.    do i = 1 to Target.0
  231.      if Target.i = '       ' then iterate
  232.      rc=lineout(TFile,Target.i)
  233.    end
  234.    call close Tfile
  235.  end
  236.  return src
  237.  
  238. /* ╒═══════════════════════════════════════════════════════════════════════╕
  239.    │  Insert a line in Target file (stem) after line number i.             ╞
  240.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  241. Insert: procedure  expose Target. NumberOfChanges
  242.  parse arg i string
  243.  if i = Target.0 then k = Target.0 + 1
  244.  else do
  245.    do j = Target.0 to i+1 by -1
  246.      k = j + 1
  247.      Target.k = Target.j
  248.    end
  249.    k = i + 1
  250.  end
  251.  Target.k = string
  252.  Target.0 = Target.0 + 1
  253.  say 'Inserted line' k ': "'Target.k'"'
  254.  NumberOfChanges = NumberOfChanges + 1
  255.  return
  256.  
  257. /* ╒═══════════════════════════════════════════════════════════════════════╕
  258.    │  returns a procedure command line  with all strings uppercased, except╞
  259.    │  doubled-quoted strings.                                              ╞
  260.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  261. upkw: procedure expose vn. vv. _d_
  262.   parse arg sentence
  263.   sentence = strip(sentence)
  264.   phrase = ""
  265.   do forever
  266.     if sentence = '' then leave
  267.     if left(word(sentence,1),1) = _d_ then do
  268.        parse var sentence (_d_) y (_d_) sentence
  269.        phrase = phrase _d_ || y || _d_
  270.     end
  271.     else do
  272.        parse var sentence y sentence
  273.        phrase = phrase translate(y)
  274.     end
  275.   end
  276.   return phrase
  277.  
  278. /* ╒═══════════════════════════════════════════════════════════════════════╕
  279.    │  apply command line-specified substitutions within a string           ╞
  280.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  281. Cmdrs: procedure expose vn. vv.
  282.  parse arg y
  283.  do i = 1 to vn.0
  284.    out = ''
  285.    do forever
  286.      if pos(vn.i,y) > 0 then do
  287.         parse var y x (vn.i) y
  288.         out = out || x || vv.i
  289.      end
  290.      else leave
  291.    end
  292.  y = out || y
  293.  end
  294.  return y
  295.  
  296. /* ╒═══════════════════════════════════════════════════════════════════════╕
  297.    │  apply env. variables substitutions to STRING if req. in OPTION.      ╞
  298.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  299. Envrs: procedure
  300.   Parse arg String,Option
  301.   out = ''
  302.   parse var Option x 'RS('c')' .
  303.   if length(c) = 1 then do
  304.      do forever
  305.         parse var String x (c) name (c) String
  306.         if name = "" then leave
  307.         out = out || x || value(name,,'OS2ENVIRONMENT')
  308.      end
  309.      String = out || x
  310.   end
  311.   return String
  312.  
  313. /* ╒═══════════════════════════════════════════════════════════════════════╕
  314.    │ All that must be done to quit and more: say msg, save Target file if  ╞
  315.    │ necessary (type=1).                                                   ╞
  316.    ╘═══════════════════════════════════════════════════════════════════════╛  */
  317. Exit:
  318.  parse arg type msg
  319.  src=0
  320.  Select
  321.    When type=1 then do
  322.         src = SaveFile()
  323.         if src <> 0 then msg = msg 'Error writing' TFile
  324.                     else msg = msg NumberOfChanges 'changes applied'
  325.         end
  326.    When type=2 then do
  327.         src = NumberOfChanges
  328.         msg = msg NumberOfChanges 'changes applied'
  329.         end
  330.    Otherwise nop
  331.  End
  332.  say msg
  333.  Exit src
  334.  
  335. /*      ┌─────────────────────────────────────────────────────────┐
  336.         │ ONERROR [CONTINUE] [STOP] : what to do on syntax errors │
  337.         └─────────────────────────────────────────────────────────┘           */
  338. ONERROR:
  339.  if wordpos(translate(Parms),'CONTINUE STOP')>0 then OnErr = translate(Parms)
  340.     else rc=OnErrorDo(p,'On Error what ?')
  341.  return
  342.  
  343. /*      ┌─────────────────────────────────────────────────────────┐
  344.         │ WHEN     ... wordlist of when codes ...                 │
  345.         └─────────────────────────────────────────────────────────┘           */
  346. APPLYWHEN:
  347.  MWhen = strip(translate(Parms),'B')
  348.  if MWhen = '*' then MWhen = Make
  349.  return
  350.  
  351. /*      ┌─────────────────────────────────────────────────────────┐
  352.         │ CASE [SENSITIVE] [IGNORE] : string compare mode         │
  353.         └─────────────────────────────────────────────────────────┘           */
  354. CASE:
  355.  if wordpos(translate(Parms),'SENSITIVE IGNORE')>0 then CaseM = translate(left(Parms,1))
  356.     else rc=OnErrorDo(p,'Case what ?')
  357.  return
  358.  
  359. /*      ┌─────────────────────────────────────────────────────────┐
  360.         │ LINEID [NOSTRIP] [STRIP "x"]                            │
  361.         └─────────────────────────────────────────────────────────┘           */
  362. SLINEID:
  363.  Select
  364.    When word(translate(Parms),1) = 'NOSTRIP' then Lstrip = ""
  365.    When word(translate(Parms),1) = 'STRIP' then do
  366.       Parse var Parms 'STRIP' (_d_) ww (_d_)
  367.       if length(ww) <> 1 then rc=OnErrorDo(p,'Strip leading what ?')
  368.                          else Lstrip = ww
  369.       end
  370.    Otherwise rc=OnErrorDo(p,'Lineid what ?')
  371.  end
  372.  return
  373.  
  374. /*      ┌─────────────────────────────────────────────────────────┐
  375.         │ REPLINE lineid WITH replacement [( options]             │
  376.         └─────────────────────────────────────────────────────────┘           */
  377. REPLINE:
  378.   parse var Parms (_d_) Lineid (_d_)  'WITH' (_d_) With (_d_)  '(' Opt
  379.   if Lineid = '' then do                           /* No line identifier      */
  380.     rc=OnErrorDo(p,'Replace what line ?')
  381.     return
  382.   end
  383.   if With = '' then do                             /* No replacement string   */
  384.     rc=OnErrorDo(p,'Replace line with ?')          /*   process error         */
  385.     return                                         /*   ignore command        */
  386.   end
  387.   With = Cmdrs(With)                               /* cmd substitution        */
  388.   With = Envrs(With,Opt)                           /* env substitution if req */
  389.   dir = Searchdir(opt)                             /* What target lines ?     */
  390.   mod = Lidmod(opt)                                /* floating line id ?      */
  391.   select                                           /* What if no target lines?*/
  392.     when wordpos('ADDTOP',Opt)>0 then after=0      /* add after line 0        */
  393.     when wordpos('ADDBOTTOM',Opt)>0 then after=Target.0 /* add after last line     */
  394.     when wordpos('DONTADD',Opt)>0 then after=-1    /* don't add               */
  395.     otherwise after=-1                             /* don't add is the default*/
  396.   end
  397.   if ififnot() then return                         /* Process only when       */
  398.   where = Whereis(Lineid,dir,mod)                  /* Get target lines numbers*/
  399.   if where \= '' then do                           /* if target(s) found      */
  400.     do until where = ''                            /*   process all targets   */
  401.       parse var where w where                      /*     1 at a time         */
  402.       was = Target.w                               /* save old value for log  */
  403.       Target.w = With                              /*     target = replacmnt. */
  404.       call logrep w,was,Target.w                   /*     log action          */
  405.       if dir \= 'A' then leave                     /*     quit if not ALL     */
  406.     end
  407.   end
  408.   else if after>-1 then call insert after With     /* if no target, try add   */
  409.   return
  410.  
  411. /*      ┌───────────────────────────────────────────────────────────┐
  412.         │ ADDLINE     line  [( options]                             │
  413.         └───────────────────────────────────────────────────────────┘         */
  414. ADDLINE:
  415.   parse var Parms (_d_) Line (_d_)  '(' Opt
  416.   if Line = '' then do                             /* No line identifier      */
  417.     rc=OnErrorDo(p,'Add what line ?')              /*    process error        */
  418.     return                                         /*    ignore command       */
  419.   end
  420.   select                                           /* When to add ?           */
  421.     when wordpos('IFNEW',Opt)>0 then always=0      /*   if not already there  */
  422.     when wordpos('ALWAYS',Opt)>0 then always=1     /*   even if already there */
  423.     otherwise always=0                             /*   IFNEW is the default  */
  424.   end
  425.   Line = Cmdrs(Line)                               /* cmd substitution        */
  426.   Line = envrs(Line,Opt)                           /* env substitution if req */
  427.   mod = Lidmod(opt)                                /* floating line id ?      */
  428.   exist = Whereis(Line,'F',mod)                    /* If this line exists and */
  429.   if exist \= '' & always = 0 then return          /* IFNEW , don't add !     */
  430.   if ififnot() then return
  431.  
  432.   select                                           /* Where to add ?          */
  433.     when wordpos('AFTER',Opt)>0 then do;           /* 1) After a given line   */
  434.       parse var Opt 'AFTER' (_d_) astr (_d_)  .    /*    line identifier ?    */
  435.       if astr = '' then after = Target.0           /*    no id = add bottom   */
  436.       else after = Whereis(astr,'F',mod)           /*    else get # of 1st    */
  437.       parse var after after .                      /*    line with this id.   */
  438.       if after='' then do                          /*    no match found       */
  439.         if wordpos('ONLY',Opt)>0 then after=-1     /*      if ONLY, don't add */
  440.            else after=Target.0                     /*      else add bottom    */
  441.       end
  442.     end
  443.     when wordpos('BEFORE',Opt)>0 then do;          /* 2) Before a given line  */
  444.       parse var Opt 'BEFORE' (_d_) bstr (_d_)  .   /*    line identifier ?    */
  445.       if bstr = '' then after = 0                  /*    no id = add top      */
  446.       else after = Whereis(bstr,'F',mod)           /*    else get # of 1st    */
  447.       parse var after after .                      /*    line with this id.   */
  448.       if after ='' then do                         /*    no match found       */
  449.         if wordpos('ONLY',Opt)>0 then after=-1     /*      if ONLY don't add  */
  450.            else after=0                            /*      else add top       */
  451.       end
  452.       else after=max(0,after-1)                    /*    match found          */
  453.     end
  454.     otherwise after=Target.0                       /* 3) default = add bottom */
  455.   end
  456.   if after \= -1 then call insert after Line       /* add the line            */
  457.   return
  458.  
  459. /*      ┌───────────────────────────────────────────────────────────┐
  460.         │ ADDSTRING string IN lineid [(Options]                     │
  461.         └───────────────────────────────────────────────────────────┘         */
  462. ADDSTRING:
  463.   parse var Parms (_d_) With (_d_)  'IN' (_d_) Lineid (_d_)   '(' Opt
  464.   if Lineid = '' then do                           /* No line identifier      */
  465.     rc=OnErrorDo(p,'Add string where ?')           /*    process error        */
  466.     return                                         /*    ignore command       */
  467.   end
  468.   if With = '' then do                             /* No string to add        */
  469.     rc=OnErrorDo(p,'Add what string ?')            /*    process error        */
  470.     return                                         /*    ignore command       */
  471.   end
  472.   With = Cmdrs(With)                               /* cmd substitution        */
  473.   With = Envrs(With,Opt)                           /* env substitution if req */
  474.   dir=Searchdir(opt)                               /* Which target line ?     */
  475.   mod=Lidmod(opt)                                  /* floating line id ?      */
  476.   where = Whereis(Lineid,dir,mod)                  /* Select target(s)        */
  477.   if where \= '' then do                           /*   if target found       */
  478.     do until where = ''                            /*     process target(s)   */
  479.       parse var where w where                      /*     1 at a time         */
  480.       if CaseM = 'S' then do
  481.          Tar= Target.w; Wi = With; end             /*     string compare mode */
  482.       else do
  483.          Tar = translate(Target.w); Wi=translate(With); end  /*     string compare mode */
  484.       if pos(Wi,Tar) > 0 & ,                       /* String already there &  */
  485.          wordpos('ALWAYS',Opt) = 0 then leave      /* ALWAYS not specified.   */
  486.  
  487.       select                                       /* Where to add ?          */
  488.         when wordpos('AFTER',Opt)>0 then do        /* 1) After a given string */
  489.           astr=''                                  /*    defaulted to null    */
  490.           parse var Opt 'AFTER' (_d_) astr (_d_)  .  /*    what is this string  */
  491.           If CaseM = 'I' then astr=translate(astr)
  492.           was = Target.w                           /*    save for logging     */
  493.           if astr = '' | pos(astr,Tar)=0           /* if no string or no match*/
  494.              then Target.w = Target.w || With      /*    add at end of target */
  495.           else do
  496.              parse var Tar xx (astr) rest          /* insert string after     */
  497.              Target.w = xx || astr || With || rest /*   specified string      */
  498.           end
  499.           call logrep w,was,Target.w               /*   log action            */
  500.         end
  501.         when wordpos('BEFORE',Opt)>0 then do       /* 2) Before a given string*/
  502.           bstr=''                                  /*    defaulted to null    */
  503.           parse var Opt 'BEFORE' (_d_) bstr (_d_)  . /*    what is this string  */
  504.           If CaseM = 'I' then bstr=translate(bstr)
  505.           was = Target.w                           /*    save for logging     */
  506.           if bstr = '' | pos(bstr,Tar)=0           /* if no string or no match*/
  507.           then do                                  /* add at beginning        */
  508.             If CaseM = 'I' then Lid=translate(Lineid)
  509.             Parse var Tar (Lid) rest               /* but after identifier    */
  510.             Target.w = Lineid || With || rest      /*                         */
  511.           end
  512.           else do
  513.              parse var Tar xx (bstr) rest          /* insert string before    */
  514.              Target.w = xx || With || bstr || rest /*   specified string      */
  515.           end
  516.           call logrep w,was,Target.w               /*   log action            */
  517.         end
  518.         otherwise nop
  519.       end
  520.       if dir \= 'A' then leave                     /* leave if not ALL targets*/
  521.     end
  522.   end
  523.   else do                                          /* no target : add line ?  */
  524.     if wordpos('ADDTOP',Opt)>0 then call insert 0 Lineid || With
  525.     if wordpos('ADDBOTTOM',Opt)>0 then call insert Target.0 Lineid || With
  526.   end
  527.   return
  528.  
  529. /*      ┌───────────────────────────────────────────────────────────┐
  530.         │ DELSTRING string [IN lineid] [(Options]                   │
  531.         └───────────────────────────────────────────────────────────┘           */
  532. DELSTRING:
  533.   parse var Parms (_d_) What (_d_)  'IN' (_d_) Lineid (_d_)  '(' Opt
  534.   if Lineid = '' then parse var Parms (_d_) What (_d_)  '(' Opt
  535.   if What = '' then do                             /* No string to del        */
  536.     rc=OnErrorDo(p,'Delete what string ?')         /*    process error        */
  537.     return                                         /*    ignore command       */
  538.   end
  539.   What = Cmdrs(What)                               /* cmd substitution        */
  540.   What = envrs(What,Opt)                           /* env substitution if req */
  541.   dir=Searchdir(opt)                               /* Which target line ?     */
  542.   mod=Lidmod(opt)                                  /* floating line id ?      */
  543.   where = Whereis(Lineid,dir,mod)                  /* Select target(s)        */
  544.   if where \= '' then do                           /*   if target found       */
  545.     do until where = ''                            /*     process target(s)   */
  546.       parse var where w where                      /*     1 at a time         */
  547.       do forever                                   /* for all occurences      */
  548.         if CaseM = 'S' then do
  549.            Tar = Target.w; Wh=What; end            /*     string compare mode */
  550.         else do
  551.            Tar = translate(Target.w); Wh=translate(What); end  /*     string compare mode */
  552.         if pos(Wh,Tar) > 0 then do                 /*     String is there     */
  553.            was = Target.w                          /*     save for logging    */
  554.            parse var Tar xx (Wh) rest              /*     isolate string      */
  555.            Target.w = xx || rest                   /*     delete string       */
  556.            call logrep w,was,Target.w              /*     log action          */
  557.         end
  558.         else leave
  559.       end
  560.       if dir \= 'A' then leave                     /* leave if not ALL targets*/
  561.     end
  562.   end
  563.   return
  564.  
  565. /*      ┌───────────────────────────────────────────────────────────┐
  566.         │ REPSTRING ostring [WITH nstring] [IN lineid] [(Options]   │
  567.         └───────────────────────────────────────────────────────────┘           */
  568. REPSTRING:
  569.   parse var Parms (_d_) Ostr (_d_)  'WITH' (_d_) With (_d_)  'IN' (_d_) Lineid (_d_)  '(' Opt
  570.   if Ostr = '' then do                             /* No old string specif.   */
  571.     rc=OnErrorDo(p,'Replace what string ?')        /*    process error        */
  572.     return                                         /*    ignore command       */
  573.   end
  574.   if With = '' then parse var Parms (_d_) Ostr (_d_)  'IN' (_d_) Lineid (_d_)  '(' Opt
  575.   if Lineid = '' then parse var Parms (_d_) Ostr (_d_)  '(' Opt
  576.   if With = '' then With = Ostr                    /* No rep string specif.   */
  577.   With = Cmdrs(With)                               /* cmd substitution        */
  578.   With = envrs(With,Opt)                           /* env substitution if req.*/
  579.   dir=Searchdir(opt)                               /* Which target line ?     */
  580.   mod=Lidmod(opt)                                  /* floating line id ?      */
  581.   where = Whereis(Lineid,dir,mod)                  /* Select target(s)        */
  582.   do while where \= ''                             /*   if target found       */
  583.       parse var where w where                      /*     1 at a time         */
  584.       was = Target.w
  585.       newtar = ''
  586.       do forever                                   /* for all occurences      */
  587.         if CaseM = 'S' then do
  588.            Tar = Target.w; Os=Ostr; end            /*     string compare mode */
  589.         else do
  590.            Tar = translate(Target.w); Os=translate(Ostr); end  /*     string compare mode */
  591.         if pos(Os,Tar) > 0 then do                 /*     String is there     */
  592.            parse var Tar xx (Os) rest              /*     isolate string      */
  593.            newtar = newtar || xx || With           /*     replace occurrence  */
  594.            Target.w = rest                         /*     next                */
  595.         end
  596.         else leave
  597.       end
  598.       Target.w = newtar || target.w
  599.       call logrep w,was,Target.w                   /* log action              */
  600.       if dir \= 'A' then leave                     /* leave if not ALL targets*/
  601.   end
  602.   return
  603.  
  604. /*      ┌─────────────────────────────────────────────────────────┐
  605.         │ COMMENTLINE lineid WITH type [(options ]                │
  606.         └─────────────────────────────────────────────────────────┘           */
  607. COMMENTL:
  608.   parse var Parms (_d_) Lineid (_d_)  'WITH' (_d_) cmnt (_d_)  '(' Opt
  609.   if Lineid = '' then do                           /* No identifier           */
  610.     rc=OnErrorDo(p,'Comment what ?')               /*    process error        */
  611.     return                                         /*    ignore command       */
  612.   end
  613.   if cmnt = '' then do                             /* No comment string       */
  614.     rc=OnErrorDo(p,'Comment how ?')                /*    process error        */
  615.     return                                         /*    ignore command       */
  616.   end
  617.   dir=Searchdir(opt)                               /* Which target lines ?    */
  618.   mod=Lidmod(opt)                                  /* floating line id ?      */
  619.   if ififnot() then return
  620.  
  621. /* The following line altered by RG so as not to comment a commented line */
  622. /*where= whereis(Lineid,dir,mod)*/
  623.   where= WhereisHack(Lineid,dir,mod,cmnt)          /* get target lines #s     */
  624.   if where \= '' then do                           /* if match(es) found      */
  625.     do until where = ''                            /*   process target(s)     */
  626.       parse var where w where                      /*   1 at a time           */
  627.       was = Target.w                               /*  save for logging       */
  628.       Target.w = cmnt Target.w                     /*   comment target        */
  629.       call logrep w,was,Target.w                   /*   log action            */
  630.       if dir \= 'A' then leave                     /* leave if not ALL targets*/
  631.     end
  632.   end
  633.   return
  634.  
  635. /*      ┌─────────────────────────────────────────────────────────┐
  636.         │ DELLINE lineid [(options ]                              │
  637.         └─────────────────────────────────────────────────────────┘           */
  638. DELLINE:
  639.   parse var Parms (_d_) Lineid (_d_)   '(' Opt
  640.   if Lineid = '' then do                           /* No identifier           */
  641.     rc=OnErrorDo(p,'Delete what line ?')           /*    process error        */
  642.     return                                         /*    ignore command       */
  643.   end
  644.   Lineid = Cmdrs(Lineid)                           /* cmd substitution        */
  645.   Lineid = envrs(Lineid,Opt)                       /* env substitution if req */
  646.   dir=Searchdir(opt)                               /* Which target line(s) ?  */
  647.   mod=Lidmod(opt)                                  /* floating line id ?      */
  648.   if ififnot() then return
  649.   where= whereis(Lineid,dir,mod)                   /* Get target lin(s) #s    */
  650.   if where \= '' then do                           /* if match(es) found      */
  651.     do until where = ''                            /*    process all targets  */
  652.       parse var where w where                      /*    one at a time        */
  653.       say 'Deleted line' w
  654.       say '  was:' Target.w
  655.       NumberOfChanges = NumberOfChanges + 1
  656.       Target.w = '       '                 /*    mark for delete      */
  657.       if dir \= 'A' then leave                     /* leave if not ALL targets*/
  658.     end
  659.   end
  660.   return
  661.  
  662. /*      ┌─────────────────────────────────────────────────────────┐
  663.         │ SEARCHDIR: Direction for line search in Target File     │
  664.         └─────────────────────────────────────────────────────────┘           */
  665. Searchdir: procedure
  666.   select                                           /* What target lines ?     */
  667.     when wordpos('LAST',arg(1))>0 then dir='L'     /* set reverse search      */
  668.     when wordpos('FIRST',arg(1))>0 then dir='F'    /* set forward search      */
  669.     otherwise dir='A'                              /* default is all lines    */
  670.   end
  671.   return dir
  672.  
  673. /*      ┌─────────────────────────────────────────────────────────┐
  674.         │ LIDMOD: Identify line at 1st col or anywhere in line    │
  675.         └─────────────────────────────────────────────────────────┘           */
  676. Lidmod: procedure
  677.   if wordpos('*ID',arg(1))>0 then return(0)
  678.                              else return(1)
  679.  
  680.  
  681. /*      ┌─────────────────────────────────────────────────────────┐
  682.         │ Stream functions (close & exists)                       │
  683.         └─────────────────────────────────────────────────────────┘           */
  684. close:
  685.   return stream(arg(1),'C','CLOSE')
  686.  
  687. exists:
  688.   return stream(arg(1),'C','QUERY EXISTS')
  689.  
  690. /*      ┌─────────────────────────────────────────────────────────┐
  691.         │ get substitution variables and their values in cmdline. │
  692.         │ ( RS(#aaa#=aaa #bbb#=bbb)                               │
  693.         │Output: vn.i = number and names of subst. variables      │
  694.         │        vv.i = values of these variables                 │
  695.         │Adapted from Walter Pachl's                              │
  696.         └─────────────────────────────────────────────────────────┘           */
  697. get_cmdrs: procedure expose vn. vv.
  698.   parse arg Opt
  699.   vn.0 = 0
  700.   p = pos('RS(',translate(Opt))
  701.   if p > 0 then do
  702.     rs = substr(Opt,p+3)
  703.     Parse var rs rs ')'
  704.     Do i=1 By 1 While rs<>''
  705.       rs=strip(rs,'L')
  706.       Parse Var rs vn '=' vv rs
  707.       if left(vn,1) = right(vn,1) then do
  708.         vn.i = vn
  709.         vv.i = vv
  710.       end
  711.       else call Exit 0 'Invalid substitution variables ('vn vv')'
  712.     End
  713.     vn.0=i-1
  714.   end
  715.   Return
  716.  
  717. /*      ┌─────────────────────────────────────────────────────────┐
  718.         │ Log a change in a target line                           │
  719.         └─────────────────────────────────────────────────────────┘           */
  720. logrep: procedure expose NumberOfChanges
  721. parse arg ln,old,new
  722. if old<>new then do
  723.   say 'Changed line' ln
  724.   say '  old: "'old'"'
  725.   say '  new: "'new'"'
  726.   NumberOfChanges = NumberOfChanges + 1
  727. end
  728.  
  729. return
  730.  
  731. /*      ┌─────────────────────────────────────────────────────────┐
  732.         │ Process IF/IFNOT logic for Lines commands               │
  733.         │    returns 1 if IF/IFNOT condition is false !!          │
  734.         │    returns 0 otherwise                                  │
  735.         └─────────────────────────────────────────────────────────┘           */
  736. ififnot:
  737. if wordpos('IFNOT',Opt)>0 Then Do                /* Process only when       */
  738.   parse var Opt 'IFNOT' (_d_) istr (_d_) .       /* another line doesn't    */
  739.   iexist = Whereis(istr,'F',mod)                 /* exists                  */
  740.   if iexist \= '' then return(1)                 /*                         */
  741. end                                              /*                         */
  742. if wordpos('IF',Opt)>0 Then Do                   /* Process only when       */
  743.   parse var Opt 'IF' (_d_) istr (_d_) .          /* another line exists     */
  744.   iexist = Whereis(istr,'F',mod)                 /*                         */
  745.   if iexist  = '' then return(1)                 /*                         */
  746. end                                              /*                         */
  747. return(0)
  748.  
  749.