DumpRecall
From Pickwiki
This works for us, based on keeping "reports" in a DIR type file named "RECALLS" in a particular structure. The program could be modified to do something similar given different file layouts, or even use PROC's (if you're into that kind of thing).
************************************************************************ * Program: DUMP.RECALL * Author : Ian [[McG]] * Date : 08/18/97 * Edited : $Id: DUMP.RECALL 17141 2013-10-04 14:54:18Z stiffd01 $ * Comment: Dump fields to an excel file ************************************************************************ * 04/01/1998 Ian Modify to handle 'D' type fields * 04/96/1998 Ian CD each dict item at the start of program * 04/24/1998 Ian Modify to handle @ID type fields (0 index) * 06/15/1998 Ian Do not use so many command line params - look in recall * 07/02/1998 Ian If there's a select, use it * 12/29/1998 Ian Convert " in data to ' * 03/11/1999 Ian Modify to dump in sylk or csv formats * 06/18/1999 Ian Do not call external routine for conversion - dump as we go * 07/08/1999 Ian Modified SUM calc to not include header row * 08/20/2001 Ian Do not parse output manually - use TO DELIM "filename" * Use perl Spreadsheet::[[WriteExcel]] to generate excel file * 08/22/2001 Ian Do totals at bottom of MR2 columns, optionally email file * 08/27/2001 Ian Do not use UDTEXECUTE for select statement * 09/17/2001 Ian Do a TRIM on recall to get rid of NULL atb names * Check for "silent" atbs with 0L width and \ heading * 01/08/2001 Ian If recall contains "SPREAD" commands, execute them * 01/30/2003 Ian If recall contains "CSV" dump as tab-delimited * 11/03/2004 Ian Add HTML excel dump * 01/17/2005 Ian Minor fix for change in format - comments after line 1 * 01/19/2005 Ian If email address = @LOGNAME, use current user's address * 02/02/2005 Ian Do not stop looping when select hit - need to exec SPREAD * A recall consists of one line, which is the "source" * followed by the lines of code that actually produce the * report. A tilda in line one represents a "hard" return * while a value mark indicates a "soft" return * e.g * 001: *GET.LIST L1~}SORT LS.MASTER KEY UATB.CUST.NAME.50}TOTAL UATB.OEC (IP\ * 002: EXECUTE \GET.LIST L1\ * 003: EXECUTE \SORT LS.MASTER KEY UATB.CUST.NAME.50 TOTAL UATB.OEC (IP\ * 004: END * T1=TIME() YYYY=OCONV(DATE(),"DY") MM= OCONV(DATE(),"DM") DD= OCONV(DATE(),"DD") TT= OCONV(TIME(),"MT") YMDT = YYYY:MM:DD:TT CONVERT ":" TO "" IN YMDT USER.NAME = @LOGNAME OPEN 'RECALLS' TO RECALLS ELSE STOP 201,'RECALLS' PROMPT '' HTML.FLAG=0 CSV.FLAG=1 DELIM.TYPE="TAB" HDR.FLAG=1 TAB=CHAR(9) S=@SENTENCE RECALL.NAME=FIELD(S, ' ', 2) IF RECALL.NAME = '' THEN PRINT @(-1):'ENTER RECALL NAME: ': INPUT RECALL.NAME IF RECALL.NAME = '' OR RECALL.NAME = '/' THEN STOP END READ RECALL FROM RECALLS, RECALL.NAME ELSE STOP 'CANNOT READ RECALLS ':RECALL.NAME * Decide if we're emailing or dumping to the shared drive P=FIELD(S,' ',3) EMAIL='' ; FILE='' IF INDEX(P,'@',1) # 0 THEN * Mail the file to someone IF P="@LOGNAME" THEN P=@LOGNAME EMAIL=P END ELSE FILE=P END FTP.TARGET="" IF FIELD(FILE,":",1)="FTP" THEN FTP.TARGET=FILE FILE=FIELD(FILE,":",5) END * See if there's a select or get-list statement GOSUB FIND.SELECT.LINE * Get rid of the select line and other stuff RECALL=RECALL<1> DEL RECALL<1,1> IF FILE = "" THEN FILE=RECALL.NAME:"_":YMDT:".TXT" END ELSE FILE=FILE:".TXT" END CONVERT ":" TO "" IN FILE * FILE='/samba_share/recall_dump/':FILE FN = FILE FILE='/samba_share/recall_dump/':ACCOUNT:'/':FN * * We assume that there is a directory in the shared drive * the same as the unix user name PC.FILE=@LOGNAME IF SELECT.LINE = '' THEN STOP 'MUST HAVE A SELECT LIST ' GOSUB PARSE.ATB.NAMES HEAD="" EXEC="LIST ":INFILE:" ID.SUP " FOR COL=1 TO NUM.FLDS FLD=FLD.LIST<1,COL> CONV=FLD.LIST<2,COL> COL.HDR=COL.HEAD.LINE<1,COL> IF INDEX(CONV,"MR2",1) THEN * Pass info to the perl script to say this is a numeric field COL.HDR="#":COL.HDR END HEAD:=COL.HDR:"~" IF CONV # '*' THEN IF INDEX(CONV,",",1) THEN SWAP "," WITH "" IN CONV EXEC:=\EVAL 'OCONV(\:FLD:\,"\:CONV:\")' \ END ELSE * a "*" indicates no CONV EXEC:=FLD:\ \ END NEXT COL NOITEMS.FLAG=0 *BEGIN CASE * CASE CSV.FLAG GOSUB DUMP.BASIC * CASE 1 * GOSUB DUMP.PERL *END CASE IF NOITEMS.FLAG THEN ERR.MESSAGE="No items selected in recall: ":RECALL.NAME IF EMAIL # '' THEN CALL TRIN.MAIL.SUB(EMAIL, USER.NAME, ERR.MESSAGE, RECALL.NAME, "") END ELSE PRINT ERR.MESSAGE END END ELSE * Success! Move over to NT server, or email BEGIN CASE CASE EMAIL # '' * Send the file as an attachment EXECUTE \TRIN.MAIL.FILE \:FILE:\ \:EMAIL:\ [[/A]]\ CASE FTP.TARGET # '' EXECUTE \TRIN.FTP.SEND \:FILE:\ \:FTP.TARGET CASE 1 * Move it to the shared drive EXECUTE \TRIN.SMB.MOVE \:FILE:\ \:PC.FILE END CASE END T=TIME()-T1 IF T < 60 THEN PRINT T:' seconds' END ELSE PRINT INT(T/60):' minute(s), ':MOD(T,60):' second(s)' END STOP PARSE.ATB.NAMES: CONVERT " " TO @VM IN RECALL CONVERT "~" TO "" IN RECALL RECALL=TRIM(RECALL) TOT.FLDS=DCOUNT(RECALL<1>,@VM) NUM.FLDS=0 FLD.LIST='' ; COL.HEAD.LINE='' INFILE='' FOR F=1 TO TOT.FLDS FLD.NAME=RECALL<1,F> IF FLD.NAME="CSV" THEN CSV.FLAG=1 IF FLD.NAME="TAB" THEN CSV.FLAG=1 ; DELIM.TYPE="TAB" IF FLD.NAME="HTML" THEN CSV.FLAG=1 ; DELIM.TYPE="HTML" IF FLD.NAME="NOHEAD" THEN HDR.FLAG=0 * Check this word to see if it's a file name, select, * get-list or dictionary atb IF INFILE='' THEN OPEN FLD.NAME TO DUMMY THEN INFILE=FLD.NAME OPEN INFILE TO INFILE.F ELSE STOP 201,INFILE OPEN 'DICT',INFILE TO @DICT ELSE STOP 201,'DICT ':INFILE CLOSE DUMMY END END ELSE * Add a field to field list, if it's in the dictionary * and it's not already in the list and it's type I or D LOCATE FLD.NAME IN FLD.LIST<1> SETTING POS ELSE READ DREC FROM @DICT, FLD.NAME THEN IF DREC<1>='I' OR DREC<1>='D' THEN GOSUB STORE.FIELD END END END NEXT F IF NUM.FLDS = 0 THEN PRINT ; PRINT 'NO ATB NAMES FOUND IN RECALL' STOP END RETURN STORE.FIELD: HED=DREC<4> WID=DREC<5> * If width=0 and header="\" then the ATB is suppressed IF (WID="0L" AND HED="\") OR (WID="0R" AND HED="\") THEN RETURN NUM.FLDS+=1 COL=NUM.FLDS TYP=DREC<1> ATB=DREC<2> CNV=DREC<3> IF CNV[1,1]='D' THEN CONVERT 'R' TO 'D' IN WID IF CNV='' THEN CNV='*' FLD.LIST<1,COL>=FLD.NAME FLD.LIST<2,COL>=CNV FLD.LIST<3,COL>=TYP FLD.LIST<4,COL>=ATB FLD.LIST<5,COL>=WID IF HED='' THEN HED=FLD.NAME CONVERT @VM TO "_" IN HED CONVERT " " TO "_" IN HED * This is the first line of the output file COL.HEAD.LINE<1,COL>=HED IF DREC<1> # 'D' THEN E=\CD \:INFILE:\ \:FLD.NAME EXECUTE E CAPTURING DUMMY END RETURN FIND.SELECT.LINE: SELECT.LINE='' PRE="EXECUTE \" ; LEN.PRE=LEN(PRE) * Skip the first "source" code line LINE.NUM=2 ; MAX.LINE=DCOUNT(RECALL,@AM) LOOP * Strip the line to it's actual code LINE=RECALL<LINE.NUM> IF LINE[1,1]='*' THEN LINE.NUM+=1 ; CONTINUE LINE=LINE[LEN.PRE+1, 999] LINE=FIELD(LINE,'\',1) * Is it a GET.LIST or SELECT? FIRST.WORD=FIELD(TRIM(LINE),' ',1) IF FIRST.WORD='SPREAD' THEN * Execute the spread command EXECUTE LINE END * Go with the first select line we find IF SELECT.LINE='' THEN IF FIRST.WORD='GET.LIST' OR FIRST.WORD='GET-LIST' OR FIRST.WORD='SELECT' OR FIRST.WORD='SSELECT' OR FIRST.WORD = 'sselect' THEN SELECT.LINE=LINE END END UNTIL LINE.NUM>MAX.LINE DO LINE.NUM += 1 REPEAT RETURN DUMP.PERL: * Use the "TO DELIM" unidata feature to dump the records the easy * (and fast) way EXEC:=\ to DELIM "~" \:FILE EXECUTE SELECT.LINE IF @SYSTEM.RETURN.CODE <= 0 THEN NOITEMS.FLAG=1 RETURN END UDTEXECUTE EXEC IF @LOGNAME = "stiffd01" THEN PRINT EXEC * Change the .TXT to null FILE= FILE[1,LEN(FILE)-4] * Now call the perl script to convert to TXT to XLS EXEC=\!/usr/local/bin/recall.pl "\:HEAD:\" \:FILE EXECUTE EXEC FILE=FILE:".xls" RETURN DUMP.BASIC: * We have a list of field names and a select, parse them the hard way * and write a tab-seperated file. This is slower but avoids limitations * on the number of columns (of unidata) and the perl module [[WriteExcel]] * Change the .TXT to .XLS FILE= FILE[1,LEN(FILE)-4]:".xls" EXECUTE "!>":FILE OPENSEQ FILE TO FVAR ELSE STOP 'CANNOT OPEN ':FILE IF DELIM.TYPE="HTML" THEN * Write the HTML header block - csv and tab don't need a header R=\<html xmlns:o="urn:schemas-microsoft-com:office:office"\ R:=\xmlns:x="urn:schemas-microsoft-com:office:excel"\ R:=\xmlns="http://www.w3.org/TR/REC-html40">\ GOSUB DO.WRITE R=\<head></head>\ GOSUB DO.WRITE R=\<body><table border=1>\ GOSUB DO.WRITE END * This is the same for CSV, TAB and HTML from here on out IF HDR.FLAG THEN * Write a header line REC.OUT='' FOR COL=1 TO NUM.FLDS FLD=COL.HEAD.LINE<1,COL> REC.OUT<1,COL>=FLD NEXT COL GOSUB WRITE.LINE END EXECUTE SELECT.LINE IF @SYSTEM.RETURN.CODE = 0 THEN NOITEMS.FLAG=1 RETURN END LOOP READNEXT @ID ELSE EXIT REC.OUT='' READ @RECORD FROM INFILE.F, @ID ELSE STOP 'CANNOT READ ':@ID FOR COL=1 TO NUM.FLDS FLD=FLD.LIST<1,COL> CONV=FLD.LIST<2,COL> * Should this have a flag? CONVERT "," TO "" IN CONV TYP=FLD.LIST<3,COL> ATB=FLD.LIST<4,COL> IF TYP="D" THEN IF ATB=0 THEN VALUE=@ID ELSE VALUE=@RECORD<ATB> END ELSE VALUE=CALCULATE(FLD) END IF CONV # '*' THEN * '*' Denotes no conversion code in field 3 VALUE=OCONV(VALUE,CONV) END REC.OUT<1,COL>=VALUE NEXT COL GOSUB WRITE.LINE REPEAT CLOSESEQ FVAR RETURN WRITE.LINE: * Take REC.OUT and parse BEGIN CASE CASE DELIM.TYPE="TAB" CONVERT @VM TO TAB IN REC.OUT R=REC.OUT ; GOSUB DO.WRITE CASE DELIM.TYPE="CSV" R='' FOR COL=1 TO NUM.FLDS R=R:\"\:REC.OUT<1,COL>:\",\ NEXT COL * Strip trailing comma R=R[1,LEN(R)-1] GOSUB DO.WRITE CASE DELIM.TYPE="HTML" * Turn @VM into <td>Field</td> R=" <tr>" ; GOSUB DO.WRITE R="" FOR COL=1 TO NUM.FLDS R=R:\ <td>\:REC.OUT<1,COL>:\</td>\ NEXT COL GOSUB DO.WRITE R=" </tr>" ; GOSUB DO.WRITE CASE 1 * Should never happen R=REC.OUT ; GOSUB DO.WRITE END CASE RETURN DO.WRITE: WRITESEQ R APPEND TO FVAR ELSE STOP 'CANNOT WRITE ':FILE RETURN