REM *** M2CBCONV *** REM M2CBCONV MAY BE USED TO CONVERT RANDOM DATA FILES FROM MICROSOFT REM FORMAT TO A FORMAT WHICH CAN BE READ BY CBASIC COMPILER PROGRAMS REM GENERATED BY M2CBASIC. SEE THE APPROPRIATE APPENDIX FOR MORE INFO. REM THIS MODULE CALLS EXTERNAL FUNCTIONS CONTAINED IN M2CBLIB.BAS REM SEE CONVERT.FILE ROUTINES FOR LIST OF EXTERNAL FUNCTIONS CALLED. STRING IN.NAME, OUT.NAME, FIELD.TYPE(1), CMND INTEGER REC.LEN, MAX.FIELDS, CUR.FIELDS, FIELD.LEN(1) REM *************** PARSE.CMND.LINE ROUTINES ***************** DEF TOKEN STRING TOKEN, TOK, CH REM REMOVE NOISE FROM COMMAND CH = LEFT$(CMND,1) WHILE LEN(CMND) > 0 AND (CH = " " OR CH = "," OR CH = "=") CMND = RIGHT$(CMND,LEN(CMND)-1) CH = LEFT$(CMND,1) WEND REM RETRIEVE TOKEN AND REMOVE FROM COMMAND TOK = "" CH = LEFT$(CMND,1) WHILE LEN(CMND) > 0 AND CH <> " " AND CH <> "," AND CH <> "=" TOK = TOK + CH CMND = RIGHT$(CMND,LEN(CMND)-1) CH = LEFT$(CMND,1) WEND TOKEN = TOK RETURN FEND DEF CHECK.NUM(TOK) REM CHECKS THAT TOKEN PASSED IS NUMERIC - RETURNS ITS NUMERIC VALUE STRING TOK INTEGER CHECK.NUM OK = -1 FOR I = 1 TO LEN(TOK) IF MATCH(MID$(TOK,I,1),"0123456789",1) = 0 \ THEN OK = 0 NEXT I IF OK AND LEN(TOK) > 0 \ THEN CHECK.NUM = INT%(VAL(TOK)) \ ELSE PRINT """";TOK;""" FOUND WHEN NUMERIC EXPECTED" :\ STOP RETURN FEND DEF SET.FIELD.ARRAYS(FL,FT) REM THIS FUNCTION SETS THE ARRAYS FIELD.LEN(*), FIELD.TYPE(*) REM FIELDS CONTAINING MULTIPLE NUMERIC ITEMS ARE SPLIT INTO REM INDIVIDUAL ARRAY ENTRIES. ANY PROBLEMS CAUSE PROGRAM TO STOP STRING FT INTEGER FL, MULT, I, J MULT = 0 IF FT = "C" THEN MULT = 1 \ MULT SET TO LENGTH OF SINGLE ITEM FOR NUM. ELSE IF FT = "S" THEN MULT = 4 \ ELSE IF FT = "D" THEN MULT = 8 \ ELSE IF FT = "I" THEN MULT = 2 IF MULT = 0 \ THEN PRINT "ILLEGAL FIELD TYPE FOUND -> ";FT :\ STOP IF MOD(FL, MULT) <> 0 \ THEN PRINT "FIELD TYPE INCONSISTANT WITH FIELD WIDTH ";FT;" ";FL :\ STOP IF MULT > 1 \ :REM I.E. NUMERIC ITEM THEN I = FL / MULT : FL = MULT \ ELSE I = 1 FOR J = 1 TO I CUR.FIELDS = CUR.FIELDS + 1 IF CUR.FIELDS > MAX.FIELDS \ THEN PRINT "MAXIMUM FIELDS EXCEEDED - INCRESE MAX.FIELDS" :\ STOP FIELD.LEN(CUR.FIELDS) = FL FIELD.TYPE(CUR.FIELDS) = FT NEXT J FEND DEF PARSE.CMND.LINE STRING KEYWD, FT INTEGER FL, I CMND = COMMAND$ IN.NAME = TOKEN IF IN.NAME = "" \ THEN PRINT "NO INPUT FILE SPECIFIED" : STOP KEYWD = TOKEN IF KEYWD = "OUTPUT" \ THEN OUT.NAME = TOKEN :\ KEYWD = TOKEN \ ELSE OUT.NAME = "" IF KEYWD = "RECL" \ THEN REC.LEN = CHECK.NUM(TOKEN) :\ KEYWD = TOKEN \ ELSE REC.LEN = 128 CUR.FIELDS = 0 WHILE LEN(CMND) > 0 FL = CHECK.NUM(KEYWD) :REM FIELD LENGTH FT = TOKEN :REM FIELD TYPE CALL SET.FIELD.ARRAYS(FL,FT) KEYWD = TOKEN WEND IF CUR.FIELDS = 0 \ THEN CUR.FIELDS = 1 :\ FIELD.LEN(1) = REC.LEN :\ FIELD.TYPE(1) = "C" REM CHECK THAT LENGTH OF FIELDS SPECIFIED = RECORD LENGTH FL = 0 FOR I = 1 TO CUR.FIELDS FL = FL + FIELD.LEN(I) NEXT I IF FL <> REC.LEN \ THEN PRINT "RECORD LENGTH NOT EQUAL TO SUM OF FIELD LENGTHS" :\ PRINT "RECORD LENGTH -> ";REC.LEN;" SUM OF FIELDS -> ";FL :\ STOP FEND REM ************ OPEN.FILES ROUTINES ************** DEF JUGGLE.NAMES REM RENAME INPUT FILE TO .BAK INTEGER I STRING TEMP.NAME, EXT I = MATCH(".",IN.NAME,1) IF I > 0 \ THEN EXT = RIGHT$(IN.NAME,LEN(IN.NAME)-I) \ ELSE EXT = "" IF EXT = "BAK" \ THEN PRINT "CANNOT RENAME FILE WITH "".BAK"" EXTENSION" :\ STOP IF EXT = "" \ THEN TEMP.NAME = IN.NAME + ".BAK" \ ELSE TEMP.NAME = LEFT$(IN.NAME,I) + "BAK" OUT.NAME = IN.NAME IN.NAME = TEMP.NAME REM RENAME INPUT FILE TO .BAK IF SIZE(IN.NAME) > 0 \ THEN OPEN IN.NAME AS 1 :\ DELETE 1 I = RENAME (IN.NAME,OUT.NAME) RETURN FEND DEF OPEN.FILES IF SIZE(IN.NAME) = 0 \ THEN PRINT IN.NAME;" CANNOT BE FOUND" :\ STOP IF IN.NAME = OUT.NAME \ THEN OUT.NAME = "" IF OUT.NAME = "" \ THEN CALL JUGGLE.NAMES IF END #1 THEN OPEN.IN.PROB IF END #2 THEN OPEN.OUT.PROB OPEN IN.NAME AS 1 CREATE OUT.NAME RECL REC.LEN+8 AS 2 RETURN :REM *** EXIT *** OPEN.IN.PROB: \ PRINT IN.NAME;" COULD NOT BE OPENED FOR INPUT" STOP OPEN.OUT.PROB: \ PRINT OUT.NAME;" COULD NOT BE OPENED FOR OUTPUT" STOP FEND REM ************ CONVERT.FILE ROUTINES ************** REM **** EXTERNAL FUNCTIONS RESIDING IN M2CBLIB.BAS DEF MCVS(SPNUM$) EXTERNAL REM STRING CONTAINING MICROSOFT SINGLE -> REAL STRING SPNUM$ REAL MCVS FEND DEF MCVD(DPNUM$) EXTERNAL REM STRING CONTAINING MICROSOFT DOUBLE -> REAL STRING DPNUM$ REAL MCVD FEND DEF MKS$(X) EXTERNAL REM REAL -> STRING CONTAINING CB80 SINGLE STRING MKS$ REAL X FEND DEF MKD$(X) EXTERNAL REM REAL -> STRING CONTAINING CB80 DOUBLE STRING MKD$ REAL X FEND DEF APNDCH (BUF$) EXTERNAL REM APPEND FLAGS - SEE M2CBLIB.BAS FOR EXPLANATION STRING BUF$, APNDCH FEND DEF CONV.SINGLE(SPNUM$) REM CONVERTS A 4 BYTE STRING CONTAINING A SINGLE PRECISION NUMBER REM IN MICROSOFT FORMAT TO A 4 BYTE STRING CONTAINING THE NUMBER REM IN TRUNCATED CB80 FORMAT STRING SPNUM$, CONV.SINGLE REAL X X = MCVS(SPNUM$) CONV.SINGLE = MKS$(X) RETURN FEND DEF CONV.DOUBLE(DPNUM$) REM CONVERTS A 8 BYTE STRING CONTAINING A DOUBLE PRECISION NUMBER REM IN MICROSOFT FORMAT TO AN 8 BYTE STRING CONTAINING THE NUMBER REM IN CB80 FORMAT STRING DPNUM$, CONV.DOUBLE REAL X X = MCVD(DPNUM$) CONV.DOUBLE = MKD$(X) RETURN FEND DEF CONVERT.FILE STRING BUF, FIELD, FT, NF INTEGER I, J, REC.CNT IF END #1 THEN EOF.ON.INPUT IF END #2 THEN WRITE.PROBLEMS PRINT: PRINT "CONVERSION BEGINS "; REC.CNT = 0 WHILE -1 :REM END OF FILE TERMINATES LOOP BUF = "" FOR I = 1 TO CUR.FIELDS FIELD = "" FOR J = 1 TO FIELD.LEN(I) FIELD = FIELD + CHR$(GET(1)) NEXT J FT = FIELD.TYPE(I) IF FT = "C" OR FT = "I" THEN NF = FIELD \ ELSE IF FT = "S" THEN NF = CONV.SINGLE(FIELD) \ ELSE IF FT = "D" THEN NF = CONV.DOUBLE(FIELD) BUF = BUF + NF NEXT I BUF = APNDCH(BUF) :REM ADD FLAGS PRINT #2; BUF REC.CNT = REC.CNT + 1 IF MOD(REC.CNT,50) = 0 \ THEN PRINT REC.CNT; WEND EOF.ON.INPUT: \ PRINT: PRINT REC.CNT;" RECORDS CONVERTED" CLOSE 1,2 RETURN WRITE.PROBLEMS: \ PRINT : PRINT "PROBLEM OCCURRED WHILE WRITING NEW FILE" PRINT "CONVERSION ABORTED AFTER ";REC.CNT;" RECORDS" CLOSE 1,2 RETURN FEND REM ***** MAIN LINE ***** MAX.FIELDS = 100 DIM FIELD.LEN(MAX.FIELDS), FIELD.TYPE(MAX.FIELDS) CALL PARSE.CMND.LINE CALL OPEN.FILES CALL CONVERT.FILE