David:
here is a READ csv routine (when I'm not using QM)
SUBROUTINE READCSV.SUB(CODE,STRING,ARRAY,CONTINUED)
!
* 10-10-12 smt readcsv.sub
!
* CODE = (TAB or CSV)
* STRING
= line from csv file to be converted to a dynamic array and stored in array
* ARRAY = dynamic array to be built or continued
* CONTINUED = set to 1 if linefeed was within last quoted field and array needs to be contiuned on next line
* Initially set to zero in calling program when starting a CSV file but then maintained by this
* subroutine for the duration of the csv file.
*
IF ASSIGNED(CONTINUED) THEN CONTINUED = 0
IF ASSIGNED(ARRAY) THEN ARRAY =
''
*
NEW = ''
QUOTED = 0
COMMA.ON = 0
QUOTE.ON = CONTINUED
*
IF CONTINUED THEN
CONTINUED = 0
AM$ = COUNT(ARRAY,@AM)
END ELSE
AM$ = 0
ARRAY = ''
END
*
LNE = STRING
LNG = LEN(LNE)
*
BEGIN CASE
CASE CODE = "TAB"
CONVERT CHAR(9) TO @AM IN LNE
AM$ += 1
ARRAY<AM$> := LNE
CASE CODE = "CSV"
GOSUB 100
CASE 1
CRT \Invalid code. CODE = '\:CODE:\'\
ARRAY = ''
END CASE
RETURN
*
100 * CSV
*
ESC.STR = ''
ESC.STR<1> = '\\,\", \r, \n, \t,\r\n'
ESC.STR<2> = ' \, ",253,253,252, 253'
CONVERT ", " TO @VM IN ESC.STR
*
LOOP
X1 = LNE[1,1]
X2 = LNE[1,2]
X4 = LNE[1,4]
UNTIL X1 = '' DO
BG = 2
*
*** setup check for excaped characters
*
LOCATE(X4,ESC.STR,1;VM$) THEN
ESC.ON = 5
CHR = ESC.STR<2,VM$>
END ELSE
LOCATE(X2,ESC.STR,1;VM$) THEN
ESC.ON = 3
CHR = ESC.STR<2,VM$>
END ELSE
ESC.ON = 0
END
END
*
BEGIN CASE
*
*** skip trailing spaces while waiting for comma
*
CASE COMMA.ON AND X1 # ","
IF X1 # " " THEN
CRT \Invalid format, discarding. X1 = '\:X1:\'\
END
*
*** excaped characters only valid within quoted fields
*
CASE ESC.ON AND QUOTE.ON
IF CHR MATCH "1N0N" THEN
NEW := CHAR(CHR) ;* new line or tab within quoted field
END ELSE
NEW := CHR
END
BG = ESC.ON ;* 3 or 5
*
*** check quote usage
*
CASE X1 = \"\
IF QUOTE.ON THEN
IF X2 = \""\ THEN
NEW := X1
BG = 3
END ELSE
QUOTE.ON = 0
COMMA.ON = 1
END
END ELSE
QUOTE.ON = 1
QUOTED = 1
IF TRIM(NEW) # '' THEN
CRT \Invalid format, discarding. NEW = '\:NEW:\'\
END
NEW = ''
END
*
*** check comma usage
*
CASE X1 = ","
IF QUOTE.ON THEN
NEW := X1
END ELSE
GOSUB 200 ;* add to array
END
*
*** all the rest
*
CASE 1
NEW := X1
END CASE
*
*** trim off what was used
*
LNE = LNE[BG,LNG]
REPEAT
*
*** is this field continued?
*
IF QUOTE.ON THEN
CONTINUED = 1
LOCATE("\n",ESC.STR,1;VM$) THEN
CHR =
ESC.STR<2,VM$>
END ELSE
CHR = 253
END
IF CHR MATCH "1N0N" THEN
NEW := CHAR(CHR) ;* new line or tab within quoted field
END ELSE
NEW := CHR
END
END
*
GOSUB 200 ;* add to array
*
RETURN
*
200 * add to array
*
*** if not quoted then trim leading and trailing spaces
*
IF NOT(QUOTED) THEN
NEW = TRIMF(NEW) ;* trim leading spaces
NEW = TRIMB(NEW) ;* trim trailing spaces
END
*
*** update array
*
AM$ +=
1
ARRAY<AM$> := NEW
*
*** init variables for next field
*
NEW = ''
QUOTED = 0
COMMA.ON = 0
QUOTE.ON = 0
*
RETURN
*
END
here is a
subroutine to WRITE csv (when I'm not using QM)
SUBROUTINE WRITECSV.SUB(DO.EXCEL,DYNREC,MAXAMC,RESX)
!
* 10-10-12 smt take dynamic array and convert CSV (comma separated values)
* please reference document RFC 4180
*
*
*** to make it simple and more obvious, I will enclose
EACH field in '"' (double quotes)
*
* do NOT remove a '-' when it's the 1st char if the 2nd char is a number
* this makes 'negative' numbers positive
!
* modifications:
!
RESX = ''
FOR II = 1 TO MAXAMC
IF II > 1 THEN RESX:= ","
VAL$ = DYNREC<II>
!
*** remove chars that Excel uses in formulas
!
IF DO.EXCEL THEN
CHR$ = VAL$[1,1]
BEGIN CASE
CASE CHR$ = "-"
IF NOT(NUM(VAL$[2,1])) THEN
VAL$ = VAL$[2,999]
END
CASE CHR$ = "="
VAL$ = VAL$[2,999]
CASE CHR$ = "+"
VAL$ = VAL$[2,999]
CASE CHR$ = "/"
VAL$ = VAL$[2,999]
CASE CHR$ = "*"
VAL$ = VAL$[2,999]
END CASE
END
IF INDEX(VAL$,\"\,1) THEN
VAL$ = SWAP(VAL$,\"\,\""\)
END
RESX:= \"\:VAL$:\"\
NEXT II
!
20000 * end of program
!
RETURN
END
hope this helps
good luck,
Steve Trimble
Computerized Data Mgmt Inc
2705 Justin Matthews Dr
N Little Rock, AR 72116
(501) 615-8674 09:00am - 6:00pm CST