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.
- Change the size of the command line window
- How to pass stem variables between functions
- Determine file formats
- Read different file formats
- Create equivalent variables out of different file formats
- Create variables with additional data to handle "internal" sort order ( Such as "!", "$" and ":")
- How to skip over "duplicate" entries in the stem
- Provide timely feedback to the user even when used on slow machines and/or over the network
- An additional progress bar that split up
- Script structure, how to handle and solve cases like this
(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.
- Make a note about the Product Manufacturer and Product ID of the "Unknown device" as seen in USBDock
- Look in the folder "C:\ecs\SYSTEM\USBDock\" for a file with the name that resemble the id's mentioned above, such as "046dc044.log", attach it to the eMail.
- Surf the internet and find a high resolution image of the device you have, preferrably much larger than 128x128 pixels, with a white even background color and attach it as well to the eMail.
- Send your eMail with your new device so that others can see it as well
//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