OS2World OLD-STATIC-BACKUP Forum

OS/2 - SIGs => Rexx => Topic started by: jep on 2008.12.18, 22:49:43

Title: Update list of USB devices
Post by: jep on 2008.12.18, 22:49:43
Marked as: Normal
Hello,

here's some code to merge files with the latest available information about USB devices.

USBDock ( included with eComstation ) provide information about USB devices attached to the computer and in what order they appear. That information can be very important to know when you try out e.g. TAME/2 as it require that you specify the right number that the scanner is attached as (2 in the picture) as it may vary depending on where and how you add new USB-devices.

While this script is mainly useful in its current form to merge the USB Vendor/Device IDs list (http://"http://www.linux-usb.org/usb.ids") with the USBDock database, it can be extended to support more formats and serve as a template for you all on how to read files of different formats and output the data in another format.

The script use a few neat techniques that you may want to examine further, e.g.

(http://www.os2world.com/component/option,com_smf/Itemid,63/action,dlattach/topic,1379.0/attach,519/image/)

If you find a "new" device that USBDock doesn't know that much about, please take your time to send information and a report to usbdock@ecomstation.ru ("usbdock@ecomstation.ru"), it's easy and take just a moment to complete.


//Jan-Erik

/* UPdate DATabase tool for USBDock */

PARSE SOURCE . . prog
prog = FILESPEC( 'D', prog )||FILESPEC( 'P', prog )

call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
call SysLoadFuncs

file.in = ARG(1)
file.out = prog||'USBDock.dat'

DO WHILE STREAM( file.in, 'C', 'QUERY EXISTS' ) = ''
   SAY 'Please specify the name of the file with new information:'
   PARSE PULL file.in
END

/* This section has been commented out as it's not needed/used desirable to us it in this particular script */
/*IF STREAM( file.out, 'C', 'QUERY EXISTS' ) = '' THEN
DO
   SAY 'Please specify the name of the database file:'
   PARSE PULL file.out
END

IF STREAM( file.out, 'C', 'QUERY EXISTS' ) = '' THEN
DO
   SAY "Couldn't find the file "file.out", please check the path and name and try again!"
   RETURN -1
END*/

/*Change the height of VIO window to 10 characters */
'@mode 80,10'

/* Reset timer so we can use it if the processing take more than a few seconds  */
file.currTime = TIME( 'R' )

/* Prepare info about total size of file for later use if needed (progress bar) */
file.currSize = 0
file.totSize = STREAM( file.in, 'C', 'QUERY SIZE' )
IF STREAM( file.out, 'C', 'QUERY EXISTS' ) <> '' THEN
   file.totSize = file.totSize + STREAM( file.out, 'C', 'QUERY SIZE' )
CALL SysCLS

/* Default is to sort the whole stem from the beginning, unless we find the tag [USBDock] */
company.sort_from = 1
count = 0

/* Read the output file first, in case it contain data we want to keep */
CALL RxLoadFile 'out'
/* Then read the input file with new entries */
CALL RxLoadFile 'in'

/* If the USBDock.dat file exist, we don't want to overwrite it */
IF STREAM( file.out, 'C', 'QUERY EXISTS' ) <> '' THEN
DO
   /* ...so we rename it instead */
   '@REN '||file.out||' '||file.out||'.txt 2>>&1 1>>NUL'
   /* ...and sort the stem */
   CALL rxMerge 'Sorting entries...', 5
   CALL SysStemSort 'company.', 'A', 'I', company.sort_from,, 1, 14
END

/* Write the prepared stem with USB information to the file */
CALL RxWrite2File 'out'

/* Ensure that the progressbar show 100% at the finish, even on fast computers */
CALL RxProgress 1, 6
RETURN 0

RxLoadFile: PROCEDURE EXPOSE count file. company.
   source = ARG(1)
/* get the value for the stem that begin with "file." and end with the part specified by the input parameter */
   fileName = VALUE( 'file.'||source )
/* Determine what filetype we're reading, USBDock type, usb.ids filetype or some unknown */
   fileType = RxGetFileType( fileName )

/* If filetype as in usb.ids, then do the following */
   IF fileType = 1 THEN
   DO WHILE LINES( fileName ) > 0 THEN
      s = LINEIN( fileName )
      CALL rxShowMeter LENGTH( s ), 'Reading '||fileName||'...'
      PARSE VALUE s WITH deviceID deviceName
      IF POS( "#", s ) = 0 & LENGTH( STRIP( s ) ) > 0 THEN /* Ignore comment (#) and empty strings */
         IF LEFT( s, 1 ) <> D2C( 9 ) THEN /* Not TAB (ASCII Character No. 9 ) */
         DO
            IF isDevID( deviceID ) THEN /* Home made function to determine if its possibly a valid device ID string */
            DO
               count = count + 1
               company.count = deviceID'![]' /* Place the deviceID (company.id) string first on every row, as we will sort on that, "!" come early in the ASCII table */
               company.id = deviceID
               company.name = STRIP( SUBSTR( deviceName, 2 ) )
               count = count + 1
               company.count = deviceID'$'company.name /* Place the deviceID (company.id ) string first on every row, as we will sort on that, "$" come after "!" in the ASCII table */
            END
         END
         ELSE IF LEFT( s, 1 ) = D2C( 9 ) THEN
         DO
            deviceID = STRIP( STRIP( deviceID,, D2C( 9 ) ) )
            deviceName = STRIP( STRIP( deviceName,, D2C( 9 ) ) ) /* TAB and/or Space */
            IF isDevID( company.id ) & isDevID( deviceID ) THEN /* Both company.id and deviceID are valid */
            DO
               count = count + 1
               company.count = company.id||':'||deviceID||'='||company.name||' '||deviceName /* Sort on company.id, ":" Come after both "!" and "$" */
            END
         END
      company.0 = count
   END
   ELSE IF fileType = 2 THEN /* The filetype seem to indicate a USBDock file format */
   DO WHILE LINES( fileName ) > 0 THEN
      s = STRIP( LINEIN( fileName ) )
      CALL rxShowMeter LENGTH( s ), 'Reading '||fileName||'...'
      IF LEFT( s, 1 ) = '[' THEN /* '[' */
      DO
         IF TRANSLATE( s ) \= '[END OF FILE]' THEN
         DO
            count = count + 1
            PARSE VALUE s WITH '['deviceID']'.
            company.count = deviceID'![]' /* Place the deviceID (company.id) string first on every row, as we will sort on that, "!" come early in the ASCII table */
            IF TRANSLATE( deviceID ) = 'USBDOCK' THEN /* Don't sort the entries for [USBDock], skip over them */
               skip = 1
            ELSE skip = 0
         END
      END
      ELSE IF s <> '' THEN /* Not empty */
      DO 
         IF isDevID( deviceID ) | skip = 1 THEN
         DO
            count = count + 1
/* The string indicate a company */
            IF POS( 'company=', s ) = 1 THEN
            DO
               PARSE VALUE s WITH 'company='s
               s = deviceID'$'s /* Place the deviceID (company.id ) string first on every row, as we will sort on that, "$" come after "!" in the ASCII table */
            END
            company.count = s
            IF skip = 1 THEN company.sort_from = count + 1 /* Position where to start the sort relative to the tag [USBDock] */
         END
      END
      company.0 = count
   END
   CALL STREAM fileName, 'C', 'CLOSE'
RETURN 0

/* Test if the string is a "valid" device ID */
isDevID: PROCEDURE
RETURN ( DATATYPE( ARG(1), 'X' ) & POS( ' ', ARG(1) ) = 0 & LENGTH( STRIP( ARG(1) ) ) = 4 ) /* Check that it's a valid ID */

/* Write the stem to file */
RxWrite2File: PROCEDURE EXPOSE company. file.
   fileName = VALUE( 'file.'||ARG(1) )
   file.currSize = 0
   file.totSize = company.0
   CALL rxWorking 'Saving 'fileName'...',5
   CALL rxProgress 0, 6
   DO count = 1 TO company.0
      CALL rxShowMeter count
      PARSE VALUE company.count WITH next_id'='.
/* Compare with next stem to see if it's a duplicate, if so, skip over it */
      IF id = next_id THEN NOP
/* Otherwise, check to see if it's a tag that contain [] */
      ELSE IF RIGHT( company.count, 2 ) = '[]' THEN
      DO
/* Write an empty line before each section except the first */
         IF count > 1 THEN
            CALL LINEOUT fileName, ''
/* If so, strip it away */
         PARSE VALUE company.count WITH company.count'![]'.
/* And write to file with appropriate format */
         CALL LINEOUT fileName, '['||company.count||']'
      END
/* Check to see if it contain "$", indicating a company string */
      ELSE IF POS( '$', company.count ) > 0 THEN
      DO
/* If so, strip it away */
         PARSE VALUE company.count WITH .'$'company.count
/* And write to file with appropriate format */
         CALL LINEOUT fileName, 'company='||company.count
      END
      ELSE DO
/* Otherwise, just write it to file */
         CALL LINEOUT fileName, company.count
      END
      id = next_id
   END
/* end the file with an empty line */
   CALL LINEOUT fileName, ''
/* and the tag [end of file] specified by the USBDock file format */
   CALL LINEOUT fileName, '[end of file]'
   CALL STREAM fileName, 'C', 'CLOSE'
   DROP target.
   CALL rxShowMeter 0
RETURN 0
/* Extend/rewrite to support more or other file formats as well */
RxGetFileType: PROCEDURE
/* Read the first line from the file specified and then close it */
   retval = LINEIN( ARG(1) )
   CALL STREAM ARG(1), 'C', 'CLOSE'
/* Determine the file format from that */
   IF POS( '#', retval ) > 0 THEN /* usb.ids file format */
      retval = 1
   ELSE IF LEFT( retval, 1 ) = '[' THEN /* USBDock file format */
      retval = 2
   ELSE retval = 0 /* Unknown */
RETURN retval

rxShowMerge:
   IF file.currTime + 1 < TIME( 'E' ) THEN
   DO
      CALL rxWorking ARG(2), 5
      CALL rxMerge ARG(1), 6
      file.currTime = TIME( 'E' )
   END
RETURN 0

rxShowMeter:
   file.currSize = file.currSize + ARG(1)
   IF file.currTime + 1 < TIME( 'E' ) THEN
   DO
      CALL rxWorking ARG(2), 5
      CALL rxProgress file.currSize / file.totSize, 6
      file.currTime = TIME( 'E' )
   END
RETURN 0

rxProgress: PROCEDURE
   IF ARG(1) <= 1 THEN /* From 0 to 1 */
   DO
      temp = FORMAT( ARG(1) * 76,, 0 )
      PARSE VALUE SysCurPos( ARG(2), 0 ) WITH row col
      SAY RIGHT( COPIES( '█', temp )||COPIES( '░', 76 - temp )||RIGHT( MIN( FORMAT( ARG(1) * 100,,0 ), 100 ), 3 )||'%', 80 )
      CALL SysCurPos row, col
   END
RETURN 0

rxWorking: PROCEDURE EXPOSE _UNIQUE_COUNTER
   PARSE VALUE SysCurPos( ARG(2), 0 ) WITH row col
   IF _UNIQUE_COUNTER = 1 THEN
      SAY LEFT( '/' ARG(1), 80 )
   ELSE IF _UNIQUE_COUNTER = 2 THEN
      SAY LEFT( '-' ARG(1), 80 )
   ELSE IF _UNIQUE_COUNTER = 3 THEN
      SAY LEFT( '\' ARG(1), 80 )
   ELSE DO
      SAY LEFT( '|' ARG(1), 80 )
      _UNIQUE_COUNTER = 0
   END
   CALL SysCurPos row, col
   _UNIQUE_COUNTER = _UNIQUE_COUNTER + 1
RETURN

rxMerge: PROCEDURE
   IF ARG(1) <= 1 THEN /* From 0 to 1 */
   DO
      middle = FORMAT( ARG(1) * 76,, 0 )
      side = FORMAT( ( 1 - ARG(1) ) * 38,, 0 )
      PARSE VALUE SysCurPos( ARG(2), 0 ) WITH row col
      SAY CENTER( COPIES( '█', side )||COPIES( '░', middle )||COPIES( '█', side + 1 ), 76 )||RIGHT( MIN( FORMAT( ARG(1) * 100,,0 ), 100 ), 3 )||'%'
      CALL SysCurPos row, col
   END
RETURN 0