home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxpea11.zip / RxPutEA.CMD
OS/2 REXX Batch file  |  1994-08-30  |  16KB  |  657 lines

  1. /*
  2. Program:         RxPutEA
  3.  
  4. Date:            27-Aug-1994
  5.  
  6. Original Author: Craig Schneiderwent
  7.                  [CompuServe: 74631,165]
  8.                  [Internet: 74631.165@compuserve.com]
  9.  
  10. Purpose:         After I noticed that Golden CommPass will store file descriptions in
  11.                  the EAs for a downloaded file, I decided to make more use of the
  12.                  Standard Extended Attributes (SEAs) provided by OS/2.  This program
  13.                  provides a way to update some of the SEAs.
  14.                  By writing another program to call this one, I can update SEAs en masse.
  15.                  This allows me to do some record keeping within the OS/2 file system
  16.                  about files contained there.  This also saves me some time explaining
  17.                  what's in a particular ZIP stored on a shared network drive: I tell
  18.                  people to go to the 'File' pages of the settings notebook.
  19.                  
  20. Syntax:          Run without any parameters and the proper syntax will be shown.
  21.  
  22. Return Codes:    0 - Normal EOJ
  23.                  1 - Syntax error
  24.                  2 - Can't find target file
  25.                      Icon file not found
  26.                  3 - Invalid EA name
  27.                  7 - Internal logic error
  28.                  8 - EA READ error
  29.                  9 - EA WRITE error
  30.                      OPEN error on icon file
  31.                      READ error on icon file
  32.                      CLOSE error on icon file
  33.  
  34. Notes:           The .SUBJECT SEA is limited to 40 characters.  Values specified for
  35.                  this SEA which are greater than 40 characters in length will be
  36.                  truncated.
  37.  
  38.                  The .HISTORY and .KEYPHRASES SEAs are really supposed to be what the
  39.                  IBM Control Program Guide and Reference calls Multi-Valued Multi-Typed
  40.                  data.  These are relatively strange creatures, consisting of
  41.                  reversed-byte hex values in what I call the 'descriptor' area, followed
  42.                  by the type of data to be stored (I only allow ASCII in this program),
  43.                  followed by the length of the data to be stored, followed by a null
  44.                  byte ('00'x), followed by the data to be stored.
  45.  
  46.                  Setting the .ICON SEA seems to work, except the icon doesn't
  47.                  appear until you open the settings dialog for the affected file.
  48.                  You can only replace the .ICON SEA (-M has no effect).
  49.  
  50.                  For more information about the horrors of SEAs, consult the
  51.                  Control Program Reference which is part of the IBM Toolkit.
  52.  
  53. On the off-chance anyone cares: this program is public domain software.  Use it,
  54. abuse it, just don't charge for it.  Take a look at the code - who'd pay for it?
  55.  
  56. Given our litigious society...
  57.  
  58. DISCLAIMER
  59. Users of this program must accept this disclaimer of warranty:
  60.  
  61. "This program is supplied as is.  The original author disclaims all
  62. warranties, expressed or implied, including, without limitation,
  63. the warranties of merchantability and of fitness for any purpose.
  64. The original author assumes no liability for damages, direct or
  65. consequential, which may result from the use of this program."
  66.  
  67. */
  68.  
  69. Call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  70. Call SysLoadFuncs
  71.  
  72. myName = 'RxPutEA'
  73. version = '1.1'
  74. EAT_ASCII = 'FDFF'
  75. EAT_MVMT = 'DFFF'
  76. EAT_ICON = 'F9FF'
  77. CODEPAGE = '0000'
  78. ASCII = 1
  79. MVMT = 2
  80. ICON = 3
  81. eaType = 0
  82. nbOfEAs = 0
  83. nbOfEAsFirstByte = '00'
  84. nbOfEAsSecondByte = '00'
  85.  
  86. Call LoadSEAs
  87.  
  88. quietMode = 0
  89. modifyEA = 0
  90.  
  91. Select
  92.   When Words(Arg(1)) = 0 Then
  93.     Do
  94.       Call ShowSyntax
  95.       Call EndThisPlease 1
  96.     End
  97.   When (Translate(Word(Arg(1), 1) = '/H')) |,
  98.        (Translate(Word(Arg(1), 1) = '/?')) |,
  99.        (Translate(Word(Arg(1), 1) = '-H')) |,
  100.        (Translate(Word(Arg(1), 1) = 'HELP')) |,
  101.        (Translate(Word(Arg(1), 1) = '?')) Then
  102.     Do
  103.       Call ShowSyntax
  104.       Call EndThisPlease 0
  105.     End
  106.   When Words(Arg(1)) > 0 Then NOP
  107.   Otherwise
  108.     Do
  109.       Call ShowSyntax
  110.       Call EndThisPlease 0
  111.     End
  112. End
  113.  
  114. Call GetSwitches Arg(1)
  115.  
  116. /*
  117. Make sure the source file exists.
  118. */
  119. rc = CheckForFile( Word(Arg(1), 1) )
  120. If rc = 0 Then
  121.   fileName = fullPathName
  122. Else
  123.   Do
  124.     Say myName':' Word(Arg(1), 1) 'does not exist'
  125.     Call EndThisPlease 2
  126.   End
  127.  
  128. /*
  129. Make sure the EA Name is a Standard EA that we can deal with.
  130. */
  131. rc = EditEAName( Word(Arg(1), 2) )
  132. If rc = 0 Then
  133.   eaName = editedEAName
  134. Else
  135.   Do
  136.     Say myName':' Word(Arg(1), 2) 'is not an acceptable EA name'
  137.     Call ShowSyntax
  138.     Call EndThisPlease 3
  139.   End
  140.  
  141. Call GetCmdLineEAValue Arg(1)
  142.  
  143. If quietMode Then
  144.   NOP
  145. Else
  146.   Call ShowParms
  147.  
  148. If eaType = ICON Then
  149.   Do
  150.     Call DoSpecialIconStuff
  151.   End
  152. Else
  153.   NOP
  154.  
  155. If modifyEA Then
  156.   Do
  157.     Call MassageExistingEAValue
  158.   End
  159. Else
  160.   NOP
  161.  
  162. rc = WriteTheEA()
  163.  
  164. If rc = 0 Then
  165.   Call EndThisPlease 0
  166. Else
  167.   Call EndThisPlease 9
  168.  
  169.  
  170. Exit 0
  171.  
  172. /*
  173. Get the EA value entered on the command line.  It's delimited with single quotes, and
  174. any single quotes within the EA value are doubled.
  175. */
  176. GetCmdLineEAValue: Procedure Expose eaValue
  177.  
  178. eaValue = ''
  179. weAreDone = 0
  180. lookingForMatch = 0
  181. argLine = Arg(1)
  182. Parse Arg argLine . ' ' . ' ' restOfLine
  183.  
  184. /*
  185. Examine each byte.  We're done when we've encountered a closing single quote
  186. followed by a space.
  187. */
  188. Do i = 1 To Length(restOfLine)
  189.   aChar = Substr(restOfLine, i, 1)
  190.   If aChar = "'" Then
  191.     Do
  192.       If lookingForMatch Then
  193.         lookingForMatch = 0
  194.       Else
  195.         lookingForMatch = 1
  196.       If Length(restOfLine) > (i + 1) Then
  197.         If Substr(restOfLine, (i+1), 1) = ' ' Then
  198.           weAreDone = 1
  199.         Else
  200.           NOP
  201.       Else
  202.         weAreDone = 1
  203.     End
  204.   Else
  205.     NOP
  206.   If lookingForMatch Then
  207.     eaValue = eaValue || aChar
  208.   Else
  209.     NOP
  210.   If weAreDone Then Leave i
  211. End
  212.  
  213. eaValue = Strip(eaValue, , "'")
  214.  
  215. /*
  216. The .SUBJECT SEA has a limit of 40 characters.
  217. */
  218. If eaName = '.SUBJECT' & (Length(eaValue) > 40) Then
  219.   eaValue = Substr(eaValue, 1, 40)
  220. Else
  221.   NOP
  222.  
  223. Return
  224.  
  225. /*
  226. Add the appropriate 'descriptor' to the front of the EA value and
  227. write it out.
  228. */
  229. WriteTheEA:
  230.  
  231. Select
  232.   When eaType = ASCII Then
  233.     Do
  234.       eaInfo = X2C(EAT_ASCII),
  235.             || D2C( Length(eaValue) ),
  236.             || '00'x,
  237.             || eaValue
  238.     End
  239.   When eaType = MVMT Then
  240.     Do
  241.       If nbOfEAs < X2D('FF') Then
  242.         Do
  243.           nbOfEAsFirstByte = '00'
  244.           nbOfEAsSecondByte = nbOfEAs + 1
  245.           If nbOfEAsSecondByte < 10 Then
  246.             nbOfEAsSecondByte = '0' || nbOfEAsSecondByte
  247.           Else
  248.             NOP
  249.           nbOfEAsWord = nbOfEAsSecondByte || NbOfEAsFirstByte
  250.         End
  251.       Else
  252.         Do
  253.           nbOfEAsFirstByte = Substr( D2C( Length(eaValue) ), 1, 1)
  254.           nbOfEAsSecondByte = Substr( D2C( Length(eaValue) ), 2, 1)
  255.           nbOfEAsWord = nbOfEAsSecondByte || nbOfEAsFirstByte
  256.         End
  257.       If modifyEA & (nbOfEAs > 0) Then
  258.         Do
  259.           eaInfo = X2C(EAT_MVMT,
  260.                    || CODEPAGE,
  261.                    || nbOfEAsWord),
  262.                 || eaValue
  263.         End
  264.       Else
  265.         Do
  266.           eaInfo = X2C(EAT_MVMT,
  267.                    || CODEPAGE,
  268.                    || nbOfEAsWord,
  269.                    || EAT_ASCII),
  270.                 || D2C( Length(eaValue) ),
  271.                 || '00'x,
  272.                 || eaValue
  273.         End
  274.     End
  275.   When eaType = ICON Then
  276.     /*
  277.     The length of the icon data is a reversed-byte word.
  278.     */
  279.     Do
  280.       If Length(eaValue) < X2D('00FF') Then
  281.         Do
  282.           iconLengthFirstByte = X2C('00')
  283.           iconLengthSecondByte = D2C( Length(eaValue) )
  284.         End
  285.       Else
  286.         Do
  287.           iconLengthFirstByte = Substr( D2C( Length(eaValue) ), 1, 1)
  288.           iconLengthSecondByte = Substr( D2C( Length(eaValue) ), 2, 1)
  289.           iconLength = iconLengthSecondByte || iconLengthFirstByte
  290.         End
  291.       eaInfo = X2C(EAT_ICON),
  292.             || iconLength,
  293.             || eaValue
  294.     End
  295.   Otherwise
  296.     Do
  297.       Say myName 'Application error - EA Type not set'
  298.       Call EndThisPlease 7
  299.     End
  300. End
  301.  
  302. rc = SysPutEA(fileName, eaName, eaInfo)
  303.  
  304. If rc = 0 Then
  305.   NOP
  306. Else
  307.   Say myName': Error - SysPutEA return code =' rc
  308.  
  309. Return rc
  310.  
  311. /*
  312. Read the existing EA value and add the appropriate 'descriptor'
  313. information.
  314. */
  315. MassageExistingEAValue:
  316.  
  317. rc = GetExistingEAValue()
  318. If rc = 0 Then
  319.   Do
  320.     Select
  321.       When eaType = ASCII Then
  322.         Do
  323.           eaValue = existingEAValue,
  324.                  || ' ',
  325.                  || eaValue
  326.         End
  327.       When eaType = MVMT Then
  328.         Do
  329.           eaValue = existingEAValue,
  330.                  || X2C(EAT_ASCII),
  331.                  || D2C( Length(eaValue) ),
  332.                  || '00'x,
  333.                  || eaValue
  334.         End
  335.       When eaType = ICON Then
  336.         Do
  337.           /*
  338.           You can't add to an icon, only replace it.
  339.           */
  340.           NOP
  341.         End
  342.       Otherwise
  343.         Do
  344.           Say myName 'Application error - EA Type not set'
  345.           Call EndThisPlease 7
  346.         End
  347.     End
  348.   End
  349. Else
  350.   Call EndThisPlease 8
  351.  
  352. Return
  353.  
  354. /*
  355. Read the EA value and parse it.
  356. */
  357. GetExistingEAValue:
  358.  
  359. rc = ReadTheEA()
  360.  
  361. If rc = 0 Then
  362.   Select
  363.     When eaType = ASCII Then
  364.       Do
  365.         reversedExistingEAValueAndStuff = Reverse(existingEAValueAndStuff)
  366.         Parse Var reversedExistingEAValueAndStuff reversedExistingEAValue '00'x .
  367.         existingEAValue = Reverse(reversedExistingEAValue)
  368.       End
  369.     When eaType = MVMT Then
  370.       Do
  371.         /*
  372.         This is relatively bizarre, I know.  Values within the EA "descriptor"
  373.         are reversed.
  374.         */
  375.         nbOfEAsFirstByte = Substr( existingEAValueAndStuff, 6, 1 )
  376.         nbOfEAsSecondByte = Substr( existingEAValueAndStuff, 5, 1 )
  377.         nbOfEAs = C2D( nbOfEAsFirstByte || nbOfEAsSecondByte )
  378.         existingEAValue = Substr(existingEAValueAndStuff, 7)
  379.       End
  380.     When eaType = ICON Then
  381.       Do
  382.         /*
  383.         You can't add to an icon, only replace it.
  384.         */
  385.         NOP
  386.       End
  387.     Otherwise
  388.       Do
  389.         Say myName 'Application error - EA Type not set'
  390.         Call EndThisPlease 7
  391.       End
  392.   End
  393. Else
  394.   rc = 1
  395.  
  396. Return rc
  397.  
  398. ReadTheEA:
  399.  
  400. rc = SysGetEA(fileName, eaName, existingEAValueAndStuff)
  401.  
  402. If rc = 0 Then
  403.   NOP
  404. Else
  405.   Say myName': Error - SysGetEA return code =' rc
  406.  
  407. Return rc
  408.  
  409. /*
  410. Get any command line switches.
  411. */
  412. GetSwitches:
  413.  
  414. aLine = Reverse(Arg(1))
  415. Parse Var aLine reversedCmdLineSwitches "'" .
  416. cmdLineSwitches = Reverse(reversedCmdLineSwitches)
  417. i = 0
  418.  
  419. Do While i \= Words(cmdLineSwitches)
  420.   i = i + 1
  421.   Select
  422.     When Translate(Word(cmdLineSwitches, i)) = '-M' Then
  423.       Do
  424.         modifyEA = 1
  425.         If switchAt = 0 Then
  426.           switchAt = i
  427.         Else
  428.           If switchAt > i Then
  429.             switchAt = i
  430.           Else
  431.             NOP
  432.       End
  433.     When Translate(Word(cmdLineSwitches, i)) = '-Q' Then
  434.       Do
  435.         quietMode = 1
  436.         If switchAt = 0 Then
  437.           switchAt = i
  438.         Else
  439.           If switchAt > i Then
  440.             switchAt = i
  441.           Else
  442.             NOP
  443.       End
  444.     Otherwise NOP
  445.   End
  446. End
  447.  
  448. Return
  449.  
  450. /*
  451. Make sure we can deal with this SEA.
  452. */
  453. EditEAName: Procedure Expose editedEAName sea. seaEAType. eaType
  454.  
  455. rc = 1
  456.  
  457. Do i = 1 To sea.0
  458.   If Translate( Strip( Arg(1) ) ) = sea.i Then
  459.     Do
  460.       rc = 0
  461.       editedEAName = Translate( Strip( Arg(1) ) )
  462.       eaType = seaEAType.i
  463.       Leave i
  464.     End
  465.   Else
  466.     NOP
  467. End
  468.  
  469. Return rc
  470.  
  471. /*
  472. Make sure the specified file exists, and return its full path name
  473. */
  474. CheckForFile: Procedure Expose fullPathName
  475.  
  476. fullPathName = Stream(Arg(1), 'C', 'QUERY EXISTS')
  477. If fullPathName = '' Then
  478.   rc = 1
  479. Else
  480.   rc = 0
  481.  
  482. Return rc
  483.  
  484. /*
  485. The .ICON SEA is (big surprise) entirely different than the other SEAs
  486. handled by this program.  Rather than specifying the ea-value on the
  487. command line, the user specifies the file containing the icon data (a .ICO
  488. file) where they normally would specify the ea-value.
  489. */
  490. DoSpecialIconStuff:
  491.  
  492. /*
  493. Make sure the icon file exists.
  494. */
  495. rc = CheckForFile( eaValue )
  496. If rc = 0 Then
  497.   Do
  498.     iconFileName = fullPathName
  499.     rc = OpenFileForRead(iconFileName)
  500.     If rc = 0 Then
  501.       Do
  502.         Call GetFileSize(iconFileName)
  503.         Call ReadEntireFile iconFileName, fileLength
  504.         rc = CloseFile(iconFileName)
  505.         If rc = 0 Then
  506.           eaValue = iconFileContents
  507.         Else
  508.           Do
  509.             Say myName': CLOSE error on' iconFileName
  510.             Call EndThisPlease 9
  511.           End
  512.       End
  513.     Else
  514.       Do
  515.         Say myName': OPEN error on' iconFileName
  516.         Call EndThisPlease 9
  517.       End
  518.   End
  519. Else
  520.   Do
  521.     Say myName':' eaValue 'does not exist'
  522.     Call EndThisPlease 2
  523.   End
  524.  
  525. Return
  526.  
  527. /*
  528. Open the file specified in the parameter for read only.
  529. */
  530. OpenFileForRead: Procedure
  531.  
  532. aString = Stream(Arg(1), 'C', 'OPEN READ')
  533.  
  534. If aString = 'READY:' Then
  535.   rc = 0
  536. Else
  537.   rc = 1
  538.  
  539. Return rc
  540.  
  541. /*
  542. Get the size of the file specified in the parameter.
  543. */
  544. GetFileSize: Procedure Expose fileLength
  545.  
  546. fileLength = Stream(Arg(1), 'C', 'QUERY SIZE')
  547.  
  548. Return
  549.  
  550. /*
  551. Read the entire file specified in the parameter.
  552. */
  553. ReadEntireFile:
  554.  
  555. Call ON NOTREADY NAME ReadFileErr
  556.  
  557. iconFileContents = Charin( Arg(1), 1, Arg(2) )
  558.  
  559. CALL OFF NOTREADY
  560.  
  561. Return
  562.  
  563. /*
  564. Oops, an error occurred on read.
  565. */
  566. ReadFileErr:
  567.  
  568. Say myName '* File Read Error!'
  569.  
  570. Call EndThisPlease 9
  571.  
  572. Return
  573.  
  574. /*
  575. Close the file specified in the parameter.
  576. */
  577. CloseFile: Procedure Expose quietMode
  578.  
  579. aString = Stream(Arg(1), 'C', 'CLOSE')
  580.  
  581. If aString = 'READY:' Then
  582.   rc = 0
  583. Else
  584.   rc = 1
  585.  
  586. Return rc
  587.  
  588. LoadSEAs:
  589.  
  590. sea.0 = 5
  591. sea.1 = '.COMMENTS'
  592. sea.2 = '.HISTORY'
  593. sea.3 = '.SUBJECT'
  594. sea.4 = '.KEYPHRASES'
  595. sea.5 = '.ICON'
  596.  
  597. seaEAType.1 = ASCII
  598. seaEAType.2 = MVMT
  599. seaEAType.3 = ASCII
  600. seaEAType.4 = MVMT
  601. seaEAType.5 = ICON
  602.  
  603. Return
  604.  
  605. /*
  606. Just what it says...
  607. */
  608. ShowSyntax:
  609.  
  610. Say myName version 'Syntax:'
  611. Say Copies(' ', Length(myName)) myName "file-name ea-name 'ea-value' [-M] [-Q]"
  612. Say myName 'Adds/modifies a Standard Extended Attribute (SEA) for a file.'
  613. Say Copies(' ', Length(myName)) 'Parameters are separated with spaces.  The ea-value should be'
  614. Say Copies(' ', Length(myName)) 'enclosed in single quotes.  If the ea-value contains single'
  615. Say Copies(' ', Length(myName)) 'quotes, make each single quote into two single quotes.'
  616. Say Copies(' ', Length(myName)) 'The ea-value for an icon should refer to the icon file.'
  617. Say myName 'switches: (separate them with spaces please)'
  618. Say Copies(' ', Length(myName)) '-M   modify existing SEA'
  619. Say Copies(' ', Length(myName)) '-Q   quiet mode (suppress messages)'
  620. Say myName 'Accepted SEAs:'
  621. Do i = 1 To sea.0
  622.   Say Copies(' ', Length(myName)) sea.i
  623. End
  624.  
  625. Return
  626.  
  627. /*
  628. Show the parameters being used in this run.
  629. */
  630. ShowParms:
  631.  
  632. Say myName version ' ' Date() Time()
  633. Say '  Source File: ' fileName
  634. Say '  EA Name:     ' eaName
  635. If Length(eaValue) > 50 Then
  636.   Say '  EA Value:    ' Substr(eaValue, 1, 50) '[...]'
  637. Else
  638.   Say '  EA Value:    ' eaValue
  639. If modifyEA Then
  640.   Say '  Modify EA:    Yes'
  641. Else
  642.   Say '  Modify EA:    No'
  643.  
  644. Return
  645.  
  646. /*
  647. Just what it says...
  648. */
  649. EndThisPlease:
  650.  
  651. If quietMode Then
  652.   NOP
  653. Else
  654.   Say myName': return code =' Arg(1)
  655.  
  656. Exit Arg(1)
  657.