// Flat-CSV - Delimit fields in a "flat", fixed-length-record, data file // as specified by the data-description file "Fields.txt". // Also, quote-and-comma-delimit fields. Also, strip leading // and/or trailing spaces. Also, when selected, translate simple // EBCDIC text to ASCII. // Implements {EDIT, Convert, Flat to CSV...}. // // Originally by: Thomas C. Burt, Greenview Data, Inc. // Last change: 01-Mar-2005 // Last change: 23-Nov-2008 Ch. Ziemski: Help-Button added. Preliminary. // // Requires: VEDIT 6.10 or later. // // From VEDIT: Select {EDIT, Convert, Flat to CSV...}. // // Description: Loads (or creates a sample) data description file "Fields.Txt" // which it uses to insert a delimiter/string between fields in // either a "flat" (fixed-length) or a terminated-record source // data file. A terminated-record file may have a variable length // final field. // // The source data file is saved to disk before the conversion and // remains unaltered, thereafter. The output filename is given the // extension ".CSV". // // At startup, this macro loads the data description file // "Fields.Txt", searching for it in the source file's // directory, the current default directory, or the Vedit // UserMacro, Macro or Home directories. If "Fields.Txt" is // not found, it is created as an empty file. If the data // description file is empty, this macro then copies the // sample file (MACROS)\fields.smp into it. It extracts the // delimiter/string and presents it to the user in the opening // dialog box, using a comma if no delimiter is defined. The user // can elect to edit "Fields.Txt" before starting the conversion. // Fields may be marked for deletion with an 'x'. No delimiter is // output for this case. See the documentation on "Fields.Txt", // below. // // Additionally, the user may optionally choose to have simple // EBCDIC text translated to ASCII. // // From OS: vpw -w -s0 [-y | -q] [-n] -x flat-CSV.vdm flat_filename [-t record_length] [-a flat_output_name] [lname] // // Invocation: -A specifies the name of the output file, including optional drive and path. // When not specified, "filename.csv" will be used. // // -N with no parameter uses "fname.TXT" as its record description file. // Alternatively, to always use "fname.TXT", edit this macro to // set numeric variable #64 = 1; see below. // // -T specifies the fixed record length for unterminated data records. // Not needed when records are terminated nor when the record length // is specified in the data_description file. // // -Y Save the results and exit; otherwise, display the beginning of the // processed output file. // // -Q Run in "quiet" mode as an icon on the task bar. // // lname: provide an explicit pathname for the data description file to // be used in place of the default file "Fields.Txt". // // Description: Loads any data description file [default is "Fields.txt"] which it // uses to insert separators into the source data file, deleting any // specified fields and saving the results into the specified output file. // If either the "-y" or "-q" options are specified, exits when finished; // otherwise, displays the output file from its beginning. // // Creates the file "flat_filename.CSV" or the filename specified after // the "-a" parameter. The source file remains unaltered. // May be run under WildFile.VDM or WildFWiz.VDM. // ///////////////////////////////////////////////////////////////////////////////////////////// // // Fields.txt - Data description file for inserting field delimiters into a fixed-length file. // Also, fields may be deleted; no delimiter is output in this case. Also // handles files with terminated records; in which case, the final field in any // record can be variable length. // // This description file may contain statements, field // specifications, embedded comments, comment lines and blank lines. // Fields are specified by their beginning column. The field may be // preceded by a code letter; currently the only codes are 'x', // which deletes the field, and 'i' or nothing to "ignore" the field; // i.e., copy it to the output file. // // Note: when a field is deleted, the field delimiter is omitted as well. // // syntax: [name=value][[whitespace]//comment] // or // [[code]col1,[code]col2,...,[code]colm][[whitespace]//comment] // [[code]coln,[code]coln+1,...,[code]colx][[whitespace]//comment] // etc. // // name list: // r[[ecord[_]]l[ength]][,output record type] // r or rl or record_length // // optional record terminators output // or // delim[iter] // or // trim Trim leading and/or trailing spaces // or // EBCDIC Source is simple EBCDIC text; output is ASCII // // Name statement details: // // Delimiter = char Any ASCII char not included in the data file // or // tab the ASCII letters 't', 'a', 'b' // or // qcd the ASCII letters 'q', 'c', 'd' to quote and comma delimit fields // or // 'exression' e.g., '0x9' - the ASCII code for horizontal tab // or // "string" Quotes are necessary // // Note: comma is the default delimiter. // // Record_Length = expression[,rtype] // expression is any valid numeric // rl= expression recognized by Vedit's // r= numeric expression evaluator. Not // needed for terminated records; may // include the terminators if specified, // but this is not required. This value // is overridden by any "-t record_length" // invocation parameter. Optionally, the // standard file-type codes may be appended // to cause record terminators to be appended // on output (0=, 1=). // // Trim = 0|1|2|3 0=No trimming (default); 1=Trim leading spaces; // 2=trim trailing spaces; 3=trim both leading & // trailing spaces. // // EBCDIC = 0 | 1 0 = no translation; text is presumed to be ASCII // this is the default; // 1 = source is simple (no packed fields!) EBCDIC text but // output is ASCII. // // Field specifications: Fields are defined by their initial column, // starting with column 1. These fields may be // preceded by an optional code letter. // Currently, the only code letters are 'x' to // delete the field and 'i' or nothing to // "ignore" the field; i.e., copy it as is // to the output file. // // Example: 1,5,15,x20,101,104,115 // Delete columns 20-100 while // inserting delimiters after columns 4, // 14, 19, 103 and 114 // ///////////////////////////////////////////////////////////////////////////////////////////// // // Register Usage: // T-Regs // 0-9 Scratch regs; saved and restored // 0 Used for output filename into/out-from DI1() // 1 Used for separator string into/out-from DI1() // 20-30 Saved and restored // 101 Dialog submacro // 102 Unexpected-Error-Break-Out-Trapping submacro // // // NumRegs // #0-#3 User responses to DI1() // #10 ID of T-Reg containing data output pathname (21) // #11 ID of T-Reg containing data output path only (22) // #12 ID of T-Reg containing data source pathname (23) // #13 ID of data description file "source-path\sdata.TXT" (24) // #14 ID of data description filename "sdata.TXT" (25) // #15 T-Reg for saving starting current directory (26) // #16 T-Reg for source data output path (27) // #17 T-Reg for data description file output pathname (28) // #18 T-Reg for source data input pathname (29) // #20 T-Reg containing delimiting char/string (default=',') (20) // #23 Field counter // #24 Maximum # fields to be stored into NumRegs // #25 Total # fields // #26 Action for final field in a record {keep,delete} = {i,x} // #31-#39 Statistics // #41 Status of FileSelector Window at startup // #42 Save original Zoom value // #43 Message Window (Window for data buffer in command mode) // #44 1=trim leading spaces; 2=trim trailing spaces; 3=both // #45 EBCDIC flag; 0 -> ASCII // #63 Macro "stage" index // #64 Flag variable (hex values) // 01 to use "fname.TXT" instead of FIELDS.TXT // 10 for Quoted-and-Comma-Delimited output fields // 40 when explicit data layout file "lname" // #66 Save WILDFILE's Locked-in-Macro ID // #67 Input record type (0,1,2,3,5,6), where 6=fixed length record // #87 is the input record size or 0 // #68 Output record type; #88 = output record size or 0 // #69 Zeroed 1st time in; set to 1 on exit; for running under WildFile // #75 Buffer number for translated output - the "standard" output buffer. // #78 Record counter for progress display // #85 Current field type (i or nothing, x) // #87 Input record size or zero (see #67) // #88 Output record size or zero (see #68) // #90 Source data file's buffer ID // #91 Wildfile-pass counter // #92 Buffer ID of/for the data description file. // #99 Flag - 0x57495C44 ("WILD") when macro is running // #100 Filename position marker // #103 T-Reg this macro is running in // #105 Save/restore Visual_Macro() value // #106 Temp // #130-#229 First 100 field widths // // Preserves NumRegs[0-59] and [70-99] except that #99 is cleared // when this macro is running from the default T-Reg[100||122]. // ////////////////////////////////////////////////////////////////////////////// // // // Execution starts here. // // // ////////////////////////////////////////////////////////////////////////////// #63 = 0 // Macro "stage" index for T-Reg[102] // (Unexpected-Break-Out Trapping submacro) #103 = Macro_Num // #103 = T-Reg # this macro is in if (#103==100||#103==122){#99=0} // Clear WildFile flag when running in // T-Reg[ 100 || 122 ] #106 = 100 // #106 = Max # fields to be stored into NumRegs // Caveat Programmer! if (#99==0x57495C44) { // When WILDFILE is running... if (!#91){ // #91 is zeroed (once only) by Wildfile #69 = 0 // 1st time in } #91++ // Update Wildfile pass counter // (May be useful for debugging...) } else { #69 = 0 } // // Check version #, first time in. // if (#69==0) { #100 = 610 if (Version_Num<#100) { Reg_Push(0,1) Reg_Set(1,"Field delimiting macro requires VEDIT version ") #1 = #100/100 #2 = Remainder ITOA(#1,1,LEFT+NOCR+APPEND) Reg_Set(1,".",APPEND) ITOA(#2,1,LEFT+NOCR+APPEND) Reg_Set(1," or later.",APPEND) Alert() Dialog_Input_1(0,`"Error","|@(1)"`) Reg_Pop(0,1) if (Is_Quiet) { XALL(1) } else { Break_Out(EXTRA) } } } // // START - Save NumRegs[0,10]. // Set necessary config values, saving setting in NumRegs. // Save NumRegs[0-59] and [70-99]. :START: #63 = 1 Num_Push(0,10) #0 = Config(U_AUTO_CFG,0) // Turn off auto-save-config #1 = Config(F_AUTO_SAVE,0) // Turn off auto-save-changes every x minutes #2 = Config(F_OVER_MODE,0) // Allow insert/delete even for fixed-records #3 = Config(F_F_TYPE) #4 = Config(F_REC_HEAD) #5 = Config(E_EXP_TAB) // Tabs complicate COBOL processing #6 = Config(E_RETAB_BK) #7 = Config(E_RETAB_FILL) #8 = Config(S_E_MORE,0) #9 = Config(D_DSP_WRAP,0) #66 = Reg_Lock_Macro // Save WILDFILE's locked-in-macro ID Num_Push(0,59) // Save numeric regs used herein Num_Push(70,99) // Except for #60-#69 Reg_Push(0,9) Reg_Push(20,30) //////////////////////////////////////////////////////////////////////////////// // // Copy submacros into T-Regs[]. // // // T-Reg[62] - Progress Display. // // First time, display estimated processing time. // Also display persistent "Converted records: " // Every time, display count and percentage of records processed. // Reg_Set(62,` if (#78==#31){call(63)} WH(#33) NT(#78,NOCR) // count #37=FSize-CP if (#37>1000000){#34=100-(#37/(#36/100))} else{if (#36==0){#34=100} else{#34=100-((100*#37)/#36)} } Message(" (") NT(#34,LEFT+NOCR) // percentage Message("%)") `) // [62] Progress Display // // T-Reg[63] - Progress Display (Initial Message). // // Display estimated processing time. // Also display persistent "Converted records: " // Empties itself on exit. // Reg_Set(63,` #35=TT WH(1) Message("Estimated processing time is ") #34=((#35-#32)*((#36/(#36-FSize+CP)))+500)/1000 NT(#34,LEFT+NOCR) Message(" seconds\n") Message("Converted records: ") #33=WH RE(MN,EXTRA) `) // [63] Progress Display (Initial Message) // // T-Reg[102] - Unexpected error breakout trap. // Restore Vedit's original state, then // terminate. // Reg_Set(102,` Reg_Lock_Macro(CLEAR) //Disable further error trapping // // Discard data description buffer. // Buf_Switch(#92,NOMSG) Buf_Quit(OK|NOMSG) // // Release and reload source data file. // Buf_Switch(#90,NOMSG) File_Quit(OK) File_Open(@(#18),OK+NOMSG) // // Save output file; display it from BoF. // Buf_Switch(#75,NOMSG) //Switch to the main output file File_Save(BEGIN+NOMSG) //Save output file; goto BoF (quickly) // // Remove any Help window. // if (Win_Status('h')>=0){ Win_Delete('h') //Remove any Help window } // // Reshow the FileSelector Window. // if (#41) { //If the FileSelector Window was hidden Do_Visual("\ME\VI") //Reshow it now } // Ch_Dir(@(#15)) //Restore original "current" directory Reg_Empty(101) //Empty dialog submacro Reg_Pop(20,30) //Restore T-Regs Reg_Pop(0,9) Num_Pop(70,99) //Restore numeric regs Num_Pop(0,59) Config(U_AUTO_CFG,#0) //Restore user's config values Config(F_AUTO_SAVE,#1) Config(F_OVER_MODE,#2) // no Config(F_F_TYPE,#3) // no Config(F_REC_HEAD,#4) Config(E_EXP_TAB,#5) Config(E_RETAB_BK,#6) Config(E_RETAB_FILL,#7&0xff) Config(S_E_MORE,#8) Config(D_DSP_WRAP,#9) if (#99==0x57495C44) { //If WILDFILE macro running Config(F_F_TYPE,#4) Config(F_REC_HEAD,#5) } Num_Pop(0,10) //Restore remaining user numregs Reg_Lock_Macro(#66) //Restore caller's lock, perhaps #69 = 1 //WILDFILE flag for next time in if (Is_Quiet || Is_Option(y)){ Buf_Switch(#92,NOMSG) Buf_Quit(OK|NOMSG) XALL(1) } else { if (#105){ vm(SET) } Reg_Empty(Macro_Num,EXTRA) } `) // [102] Unexpected Error Breakout /////////////////////////////////////////////////////////////////////////////////// // // Save some state values. // Hide any FileSelector Window. // #63 = 2 #41 = 0 // Haven't changed status of FileSelector Window yet #42 = Zoom_Status // #42 = window zoom status if (IsFileSelector) { // When FileSelector Window is visible... #41 = 1 // Remember this fact... Do_Visual("\ME\VI") // And then toggle the window into hidden mode } // // Set default delimiter to comma (',') in T-Reg[#20]. // #20 = 20 Reg_Set(#20,',') // Default field delimiter #105 = vm; vm(CLEAR) Reg_Lock_Macro(102) //////////////////////////////////////////////////////////////////////////////// // // Sign-on and File Handling. // // Set #90 = source data file's buffer ID. Normally, the current edit buffer // is considered to be the source data file. It will be closed and // reopened in read-only mode. // // Set #92 = buffer ID of/for the data layout file. // Presume any file in buffer[2] is the data layout file if // this macro is being run from the command line: e.g., // vpw -x delimit dname fname.txt // // Set #75 = buffer number for translated output; referred to herein as // the standard output buffer. // // To initiate data conversion manually, the layout file must be named // FIELDS.TXT and exist in the current or VEDIT HOME directory. // In which case, after loading the data file, the user can initiate // processing via {EDIT, Convert, Flat to CSV...}. // // Likewise, the layout file must be named FIELDS.TXT to run under // WILDFILE.VDM. // #43 = Win_Num //#43 = message window #100 = 0 // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);#100=1;update() ? #90 = #75 = Buf_Num //#90 = current buffer # #92 = 0 //#92 = layout buffer ID; not yet set #64 = 0 //Set = 1 to always use fname.TXT //instead of FIELDS.TXT when no explicit //filename parameter "lname" if (#100) {Win_Switch(#43)} Win_Zoom() //Max sized window Win_Clear() if (#100){ ws($) } // // Make the data file's output directory the current default directory. // #15 = 26 // T-Reg[] to hold current default directory #16 = 27 // T-Reg[] to hold source data file's output path #17 = 28 // T-Reg[] to hold description file's output pathname #18 = 29 // T-Reg[] to hold source data input pathname Reg_Set(#15,Cur_Dir) // Save current directory Reg_Set(#16,Path_Only) // Get source data file's output path Reg_Set(#18,Input_File) if (Is_Open_Write) { Ch_Dir(Path_Only) } // // For autoexecution (-x), presume anything in buffer #2 is the layout file. // // if ( -x && !Wildfile && 2nd buffer ) #100 = 0 // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);#100=1;update() ? if ( Is_Auto_Execution && #99!=0x57495C44 && Buf_Status(2) >= 0 ) { #92 = 2 // #92 = data layout buffer #64 = #64 | 0x40 // Flag data description file already loaded } #63 = 3 ////////////////////////////////////////////////////////////////////////// // // Edit Mode only: // // Create/modify data description file "Fields.Txt" when in edit mode; // Insert "Fields.Smp" into newly-created/empty "Fields.Txt"; then, // run/cancel the rest of this macro. // Unless canceled, set #92 = buffer ID of "Fields.Txt". // #100=0 // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);#100=1;update() ? if (! Is_Auto_Execution && ! Is_Redirect_Input ) { // // Loading "Fields.Txt", wherever it might be. // #0 = 1 // Flag that "Fields.txt" loaded // // Invocation "current" directory. // if (File_Exist("|@(#15)\Fields.Txt")){ File_Open("|@(#15)\Fields.Txt",OK+NOMSG) // // Source data file's output directory. // } else { if (File_Exist("|@(#16)\Fields.Txt")){ File_Open("|@(#16)\Fields.Txt",OK+NOMSG) // // Vedit User Macros Directory. // } else { if (File_Exist("|(UserMacro)\Fields.Txt")){ File_Open("|(UserMacro)\Fields.Txt",OK+NOMSG) // // Vedit Macros Directory. // } else { if (File_Exist("|(Macro)\Fields.Txt")){ File_Open("|(Macro)\Fields.Txt",OK+NOMSG) // // Vedit Home Directory. // } else { if (File_Exist("|(Home)\Fields.Txt")){ File_Open("|(Home)\Fields.Txt",OK+NOMSG) // // "Fields.Txt" does not exist. // } else { #0 = 0 // Flag that "Fields.Txt" not found }}}}} // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);update() ? // // Reset flag #0 if an empty file was loaded. // if (#0==1) { Reg_Set(#17,PATH_NAME) #0 = File_Size > 0 } // // If empty or nonexistent "Fields.Txt", // insert "Fields.Smp" into data description file. // (Just look in the standard directories for this file). // if (!#0) { #1 = Reg_Free Reg_Load(#1,"Fields.Smp",EXTRA) // // For nonexistent "Fields.Txt"... // if (File_Check("Fields.Txt")<0) { // // For normal editing, create Fields.Txt // in the source data file's output directory. // if (! Is_Auto_Execution ) { File_Open("|@(#16)\Fields.Txt",OK+NOMSG) // // For auto-execution, create Fields.Txt // in the invocation default directory. // } else { File_Open("|@(#15)\Fields.Txt",OK+NOMSG) } } // // Copy sample "Fields.Smp" into "Fields.Txt". // Reg_Set(#17,Path_Name) Reg_Ins(#1) Reg_Empty(#1) } //////////////////////////////////////////////////////////////// // // // Initializing the Dialog I // // // // Edit the dialog command, below, to set the default button // // to "[Describe]" for non-existent/empty "Fields.Txt" or // // to "[Run]", otherwise. // // // //////////////////////////////////////////////////////////////// #92 = Buf_Num Buf_Switch(#90) Update() // // Creating default output filename in T-Reg[0]. // Reg_Set(0,pathonly) Reg_Set(0,`\`,APPEND) Reg_Set(0,fileonly,APPEND) Reg_Set(0,`.csv`,APPEND) // Reg_Set(101,~#106 = DI1(0,^`Flat to CSV`, `This function converts a "Flat" data file into a CSV file by inserting user-specified separators (delimiters) between fields. If needed, Carriage-Return/Line-Feed can be added to the end of each record. The beginning columns for the fields and various options are specified by the file "Fields.txt" which must first be created and can later be modified by the [Describe] button. The converted file will be saved under a new name:`, `??&Output:`, `Specify the desired delimiters and other options below. These options will also be enabled in the "Fields.txt" file.`, `??&Separator(s):`, `.g.l() &User specified separator`, `()&Quote && Comma Delimit`, `() &Tab delimit`, `.g.h.r[]Trim &leading spaces`, `[]Tri&m trailing spaces`, `[]&EBCDIC to ASCII`, `[&Describe]`, `[&Run]`, `[&Help]`, `[&Cancel]`^, SET+APP+CENTER,0,0) ~) if (Buf_Switch(Buf_Free(EXTRA),EXTRA|NOMSG) = 0x09 #0 = 3 } else { if (match("qcd")==0){ Reg_Set(1,"qcd") // The Letters 'q' 'c' 'd' to Quote & Comma Delimit #0 = 2 } else { if (cc==''') { #0 = Cur_Pos Char(1) if (Search_Block("//",Cur_Pos,EoL_Pos,NOERR)){ #1 = Cur_Pos } else { #1 = EoL_Pos } Goto_Pos(#0+1) if (Search_Block("'",Cur_Pos,#1,ADVANCE|NOERR)){ Reg_Copy_Block(1,#0,Cur_Pos) } else { Reg_Set(1,"'") } #0 = 1 } else { if (cc=='"') { #0 = Cur_Pos Char(1) if (Search_Block("//",Cur_Pos,EoL_Pos,NOERR)){ #1 = Cur_Pos } else { #1 = EoL_Pos } Goto_Pos(#0+1) if (Search_Block('"',Cur_Pos,#1,ADVANCE|NOERR)){ Reg_Copy_Block(1,#0,Cur_Pos) } else { Reg_Set(1,'"') } #0 = 1 } else { if (cc=='/'&&cc(1)!='/'){ Reg_Set(1,'/') #0 = 1 } else { if (match('|s|[|w]|{//,|>}')==0){ #0 = 1 Reg_Copy_Block(1,Cur_Pos,Cur_Pos+1) }}}}}} } // // Set initial state for stripping {leading,trailing} whitespace. // #44 = 0 if (Search("|>1 // Trailing whitespace checkbox // // Set EBCDIC flag, perhaps. // #45 = 0 // Not EBCDIC if (Search("|,[Describe],[Run],[Help],[Cancel]} // // [Help]. // if (#106==3){ Help("Converting") // That help page needs another click on a link, but it's the best entry I found. } else { break } } // // [Cancel] or . // if (#106==0 || #106==4 ){ Buf_Switch(#92,NOMSG) Buf_Quit(OK|NOMSG) Buf_Switch(#90,NOMSG) Win_Switch(#43) Win_Zoom(#42) Goto DONE } // // [Run] or [Describe]. // Buf_Switch(#92,NOMSG) // // Process any "trim spaces" options. // #44 = (#1 | (#2<<1)) & 3 // #44 = Trim options #1 = 0 if (Search("|> 1 Type_Space(#0) Message('*********************************************************\n');TS(#0) Message('* FLAT-CSV.VDM 03/01/2005 *\n');TS(#0) Message('* Insert field delimiters into "flat" data file. *\n');TS(#0) Message('*********************************************************\n');TN() // // If no file open, prompt for filename and open it. // Reg_Set(3,"file to convert") if (!File_Size) { repeat(ALL) { Reg_Set(3,"Enter name of ",INSERT) Reg_Set(3,": ",APPEND) Type_Newline() Reg_Type(3) Get_Input(#10,"",NOCR) if (File_Exist(@(#10))) { Break } Alert() Message("\nFile not found; please try again or to cancel.\n") } File_Open("|@(#10)",NOEVENT) #90 = Buf_Num } }} // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);update() ? if ( File_Size == 0 ) { Goto DONE } // // For Auto-Execution, set Current Directory to source data file's input directory. // #63 = 7 Buf_Switch(#90,NOMSG) Reg_Push(0,1) Reg_Set(0,INPUT_FILE) Buf_Switch(Buf_Free(EXTRA),NOMSG) Reg_Ins(0) EOF() Replace("|{\,:}","",REVERSE) if(Match_Item==2){ Ins_Text(":\") } Del_Line() Reg_Copy(1,0) if ( Is_Auto_Execution ) { Ch_Dir(@(1)) } Reg_Pop(0,1) Buf_Quit(OK|NOMSG) Buf_Switch(#90,NOMSG) // // Set T-Reg[#10] = data output pathname: // path\fname.csv (normally) or // user selected name from DI1() or // "-a" parameter for Auto-Execution ("-x"). if ( Is_Auto_Execution ) { // // Auto_Execution && "-a" // if ( Is_SaveAs ) { Reg_Set(#10,PATH_NAME) //T-Reg[#10] = user-specified output pathname // // Auto_Execution Default: Input_Path\File_Name.CSV // } else { Reg_Set(#10,PATH_ONLY) // = path Reg_Set(#10,"\",APPEND) // = path\ Reg_Set(#10,FILE_ONLY,APPEND) // = path\fname Reg_Set(#10,".CSV",APPEND) // = path\fname.CSV } } else { // // Interactive name from Dialog_Input_1() // Reg_Set(#10,@0) } // // Set T-Reg[#11] = output_path\. // #0 = Buf_Num #11 = 22 Buf_Switch(Buf_Free(EXTRA),NOMSG) Reg_Ins(#10) //buf[] = full_path_name (output) Search("\",BEGIN+ALL+ADVANCE+NOERR) //Skip over pathname Reg_Copy(#11,0) //T-Reg[#11] = output_path\ Buf_Quit(OK) Buf_Switch(#0,NOMSG) // // Delete default error file from the output directory. // Set T-Reg[18] with its full pathname. // // Reg_Set(#18,@(#11)) **** #18 reused already ***** // Reg_Set(#18,`Fields.err`,APPEND) // File_Delete( @(#18), OK + NOERR ) // // Check for missing/empty data file. // if ( FSize == 0 ) { Reg_Empty(1) Out_Reg(1,APPEND) Message("\n***** Missing or empty data file ") Reg_Type(0) Message("\n") Out_Reg(CLEAR) // Call("ERRMSG") if (Is_Quiet) { XALL(1) } else { if (#99==0x57495C44) { break_out } else { break_out(EXTRA) }} } // // Determine tentative input EOL type or record size. // Set #67 = input EOL-type: {0,1,2,3,4,6} and // #87 = input record size or 0. // // Note: 0-4 are config/menu values for Vedit's terminated "file-type". // 6 = fixed-length record. // #67 = Config(F_F_TYPE) #87 = 0 if ( #67 > 6 ) { #87 = #67 #67 = 6 // Fixed length records } // // Set T-Reg[#12] = source_data_pathname. // #12 = 23 Out_Reg(#12) Name_Read(EXTRA+NOMSG+NOCR) Out_Reg(CLEAR) // // Open the output buffer. // Set #75 = buffer ID. // Configure preliminary record-type/size. // // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);#100=1;update() ? Buf_Switch(Buf_Free) File_Open_Write(@(#10),OVERWRITE+OK+NOMSG) #75 = Buf_Num Config(F_OVER_MODE,0,ALL) if ( #67 != 6 ) { Config(F_F_TYPE,#67,LOCAL) } else { if ( #87 > 7 ) { Config(F_F_TYPE,#87,LOCAL) } else { Config(F_F_TYPE,7,LOCAL) Config(F_CUST_REC_SIZE,#87,LOCAL) }} // // Close the source data file. // Reopen in Read-only mode. // Set #90 = buffer ID. // Buf_Switch(#90) if (Is_Altered){ File_Close(NOMSG) } else { Buf_Empty(OK) } File_Open("|@(#12)",BROWSE+OVERWRITE+OK+NOMSG) #90 = Buf_Num if ( #67 != 6 ) { Config(F_F_TYPE,#67,LOCAL) } else { if ( #87 > 7 ) { Config(F_F_TYPE,#87,LOCAL) } else { Config(F_F_TYPE,7,LOCAL) Config(F_CUST_REC_SIZE,#87,LOCAL) }} // // Set T-Reg[#13] = "source_data_path\fname.TXT". // Set T-Reg[#14] = "fname.TXT". // #13 = 24 #14 = 25 Buf_Switch(Buf_Free(EXTRA),NOMSG) //Switch to temp buffer Reg_Ins(#12) //buf[] = source_data_full_pathname Replace(".|M|>","",REVERSE+NOERR) //Delete any existing extent Ins_Text(".TXT") //Append ".TXT" Reg_Copy_Block(#13,0,File_Size) //T-Reg[#13] = "path\fname.TXT" // Search("\",BEGIN+ALL+ADVANCE+NOERR) //Skip over pathname Reg_Copy_Block(#14,CP,EOL_Pos) //T-Reg[#14] = "fname.TXT" Buf_Quit(OK) //Discard temporary buffer // // Open data layout file for editing. // Unless already loaded, determine name: Fields.TXT or fname.TXT; // then load it from the current directory if possible; // else from the VEDIT Home Directory; // quit if no such file. // Enter: T-Reg[#13] = "source_data_path\fname.TXT". // T-Reg[#14] = "fname.TXT". // #63 = 8 if (#92>0) { Buf_Switch(#92,NOMSG) // Switch to data layout buffer } if (#64&0x40) { // If explicit data layout file Reg_Set(#13,INPUT_FILE) // Full pathname Out_Reg(#14) Name_Read(NOMSG) // Filename only (for consistency) Out_Reg(CLEAR) } else { // No explicit layout file if (!(#64&1)) { // If !( -N 1 ) i.e., not fname.txt Reg_Set(#13,"Fields.txt") // full pathname (current directory) Reg_Set(#14,"Fields.txt") // for VEDIT home directory } if (File_Exist(@(#13))) { //If local layout file, load it File_Open("|@(#13)",OVERWRITE+OK+NOMSG) // but do not create backup file } else { if (File_Exist("|(HOME)\|@(#14)")) { File_Open("|(HOME)\|@(#14)",OVERWRITE+OK+NOMSG) } else { Reg_Empty(1) Out_Reg(1,APPEND) if (Is_Quiet) { Message("\n***** No data layout file.") } Message(`\nCannot find `); Reg_Type(#13) Message(` in current nor VEDIT's "home" directory.`) Out_Reg(CLEAR) // Call("ERRMSG") if (Is_Quiet) { XALL(1) } else { Type_Newline(1) Buf_Quit(OK) Buf_Switch(#90,NOMSG) GetKey("Press any key to view data file...") // Call("CloseErr") Break_Out(EXTRA) } }} } #92 = Buf_Num #63 = 9 // // Remove junk (0x1a, e.g.) at end of layout file. // End_Of_File(); bol; if ( match("|[|w]|k") == 0 ) { db(cp,eolpos) } // // Ensure layout file is newline-terminated. // End_Of_File() Ins_Newline(1) //Ensure final newline line(-10,NOERR) //Back up a bit r("|<|L","",ALL+NOERR) //Strip empty lines BOF() ////////////////////////////////////////////////////////////////////////// // // // Preprocessing the data layout file // // // ////////////////////////////////////////////////////////////////////////// // // Strip comments, leading whitespace and blank lines. // Replace("|<|w","",BEGIN+ALL+NOERR) //Remove leading whitespace Replace("|<|[|W]//|Y|L","",BEGIN+ALL+NOERR) //Strip comment lines Replace("|[|W]//|Y|>","",BEGIN+ALL+NOERR) //Strip inline comments Replace("|<|L","",BEGIN+ALL+NOERR) //Remove blank lines Replace("^{[a-z]+[\s\t]+.*,[\s\t]*[0-9]+}[\s\t]+{[^\s\t].*}$","\1 \2",REGEXP+BEGIN+ALL+NOERR) // // Ascertain record-type/size and optional output filetype code. // Delete lines of type 'code letter=' after processing. // Perform error checking; break out if bad input. // Convert to "field_length" format; // Copy 1st 100 fields into Num_Regs[130-229]. // ////////////////////////////////////////////////////////////// // // // 'Code=' Preprocessing // // // ////////////////////////////////////////////////////////////// // // // Current Codes // // // // r=input_length/_type[,output_type] // // Delim=char or tab or 'expression' or "string" // // Trim={0,1,2,3} for {no,leading,trailing,both} // // EBCDIC={0,1} to translate from EBCDIC to ASCII // // // // Note: all 'code=' statements must precede the // // field list. // // // ////////////////////////////////////////////////////////////// // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);update() ? #63 = 10 #44 = 0 // No "trim" instruction, yet #45 = 0 // Not translating from EBCDIC to ASCII, normally Begin_Of_File() while(!At_EOF) { match("|a",all+advance) if (match("|[|w]=|[|w]",advance)!=0) { break } #2=Cur_Pos // // r=n... // BoL() if (Match("r|s")==0){ Goto_Pos(#2) #67=#68=Num_Eval(ADVANCE) // #67 = input record type {0,1,2,3,6} // #68 = default output record type #0 = #67 if (#67>7) { #87 = #67 // #87 = input record size Buf_Switch(#90) #68 = #67 = 6 // #67 = fixed length input records // assume fixed output records } if (#0>=0){ Buf_Switch(#90) // Switch to the source buffer Config(F_F_TYPE,#0,LOCAL) // Set its file-type Buf_Switch(#92) // Switch back to the data description file } // // r=...,out_type // if (match("|[|W],",advance)==0){ #0 = #68 = Num_Eval() // #68 = {0,1,2,3} = output record type if (#68 > 7 ) { #88 = #68 #68 = 6 } if (#0>=0){ Buf_Switch(#75) // Switch to the output buffer Config(F_F_TYPE,#0,LOCAL) // Set its file-type Buf_Switch(#92) // Switch back to the data description file } } Goto DELLN } // // Delim=char // if (Match("Delim")==0){ Goto_Pos(#2) if (EoLPos==Cur_Pos+1){ rcb(#20,Cur_Pos,Cur_Pos+1) Goto DELLN } // // Delim=tab // if (Match("tab")==0){ Ins_Char(9) RCB(#20,Cur_Pos-1,Cur_Pos) Goto DELLN } // // Delim=qcd // if (Match("qcd|s")==0){ #64 |= 0x10 RCB(#20,Cur_Pos,Cur_Pos+3) Goto DELLN } // // Delim='expression', were 0 <= eval(expression) < 256 (enforced; no error) // Match("|[|w]",ADVANCE) if ( Cur_Char == ''' ) { c #2 = Cur_Pos if(!Search_Block("'|>",Cur_Pos,EoL_Pos,noerr)){ Goto BADLAY } Del_Char(1) Goto_Pos(#2) #0 = ( 0xFF & Num_Eval() ) ITOA(#0,#20,LEFT+NOCR) Goto DELLN } // // Delim="string" // if ( Match('"') != 0 ) { Goto BADLAY } c #2 = Cur_Pos if (!Search_Block('"|>',Cur_Pos,EoL_Pos,noerr)) { Goto BADLAY } rcb(#20,#2,Cur_Pos) Goto DELLN } // // EBCDIC={0,1} // if (Match("EBCDIC")==0){ Goto_Pos(#2) #45 = Num_Eval() Goto DELLN } // // Trim=1|2|3. // if (Match("Trim")==0){ Goto_Pos(#2) #44 = Num_Eval() // Goto DELLN } // // DELLN - Delete "code=" line from buffer. // Continue at top of loop. // :DELLN: BOL() Del_Line(1) continue } // 'code=' processing ////////////////////////////////////////////////////////////// // // // Field Preprocessing // // // ////////////////////////////////////////////////////////////// // // // Fields consist of optional 'code ' & beginning column // // and are separated by commas and/or newlines. // // The field lengths are computed; the first 100 are // // stored into variables #130-#229; negative values are // // stored for fields that are to be deleted. The remain- // // fields are converted into the string f101,f102,,,fn // // where each f-i is an integer; again, fields that are // // being deleted are listed as negative values. // // // // Current Codes // // // // nothing or i "ignore"; i.e., copy to output; then // // append the delimiter/string // // x Delete (excise); no delimiter/string // // // ////////////////////////////////////////////////////////////// // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);update() ? Begin_Of_Line() #0 = 130 #2 = 0 // Last field beginning column #3 = 0 // Last field action {1,-1} = {keep, delete} #4 = 0 // Current field beginning column #5 = 0 // Current field action #6 = 0 // Field counter #24 = 100 // # Field descriptions to be processed into N-Regs #63 = 11 while(!At_EoF) { Match("|X",ADVANCE) #5 = 1 if (Match("|{x,i}",ADVANCE)==0){ if (Match_Item==1){ #5 = -1 } Match("|[|w]|[|s]",ADVANCE) } #4 = Num_Eval(ADVANCE) if (#6++>0){ #@0 = #3 * (#4 - #2) #0++ } #2 = #4 #3 = #5 Match("|[|X]|[|S]",ADVANCE) if (#6>#24){Break} } // Field Processing Loop Del_Block(0,Cur_Pos) #25 = #6 // // Just convert to field sizes and tidy up (standardize) // the remaining fields. // if (#3==1){ #3 = 'i' } else { #3 = 'x' } While(!At_EoF){ #0=cp Match("|X",ADVANCE) #5 = 'i' if (Match("|{x,i}",advance)==0){ if (Match_Item==1){ #5 = 'x' } Match("|[|w]|[|s]",ADVANCE) } #4 = Num_Eval(ADVANCE) if (Match("|[|X]|[|S]",ADVANCE)!=0){ Goto BADLAY } Del_Block(#0,cp) Ins_Char(#3) Num_Ins(#4-#2,LEFT+NOCR) Ins_Char(',') #25++ #2 = #4 #3 = #5 } // // Handle final field. // if (#25>#24){dc(-1)} // Trim final comma from description list #26 = #3 // Save action of final field {i,x} /////////////////////////////////////////////////////////////// // // // Statistics Initialization // // // // Set #76 = (approx) record size. // // #77 = (approx) # records in the file. // // #31 = # records per reporting cycle {100 or 10 or 1} // // // /////////////////////////////////////////////////////////////// #63 = 12 Buf_Switch(#90,NOMSG) //Switch to source data file BoF() if (#67>5){ //If fixed-length records... #76 = #87 //Default record size } else { //Else file should have newlines... #0 = Cur_Pos Line(100,NOERR) //Advance a few lines #76 = (Cur_Pos - #0)/100 //Approx line size Goto_Pos(#0) //Restore pos } #77 = (File_Size-#0) / #76 //#77 = # of records in file #31 = 100 if (#77 < 500){ #31 = 10 } if (#77 < 50){ #31 = 1 } // // Show life by displaying "Processing first xxx data records..." message. // // if (!Is_Quiet) { Win_Hor(1) Message("Input file: ") // Display input drive:\path\name Reg_Type(#18,0) Win_EOL() Type_Newline() Buf_Switch(#75,NOMSG) Name_Write(EXTRA) // Ditto for output file Buf_Switch(#90,NOMSG) if (false){ if (Reg_Size(#65+18)){ ***** error ***** Message("Error file: ") // Ditto for error error file Reg_Type(#65+18,0) ***** error ***** Win_EOL() Type_Newline() } } // if (FALSE) Message("Processing first ") Num_Type(#31,LEFT+NOCR) Message(" data records... ") } // // More statistics. // #36 = File_Size #39 = Reg_Free // Do nothing for record #0 ////////////////////////////////////////////////////////////////////////////// // // Main Processing loop. // #77 = #75 //Initially, output buffer = standard output buffer #78 = 0 //Record counter #32 = Time_Tick #63 = 13 // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);update() ? BS(#90,NOMSG) while(!AtEOF){ // For each record // // Show progress message every 100 or 10 or 1 iterations. // if (!IsQuiet&&!(#78%#31)){ call(#39) // T-Reg(#39) is empty, initially #39=62 // Next time it'll have the right stuff } #78++ // Increment record # // // Copy current record into the output buffer. // #1=cp // At start of data to be moved l(1,noerr) #2=cp // At start of next line c(-nc) // At end of data to be moved rcb(0,#1,cp) // Copy current line into T-Reg[0] gp(#2) // Move to start of next line bs(#77,NOMSG) ri(0,BEGIN) /////////////////////////////////////////////////////////////// // // // Translate from EBCDIC to ASCII, perhaps. // // // /////////////////////////////////////////////////////////////// if (#45) { Translate_Block(CP,EoBPos,REVERSE) } ////////////////////////////////////////////////////////////////////////// // // Field processing loop, 1st 100 fields // #2 = min(#24,#25-1) // // Just delimit fields. // if ((#64&0x10)==0){ for (#23=0;#23<#2;#23++){ #0=130+#23 #0=#@0 if (#0<0){ // For negative field size dc(-#0) // Simply delete the field } else { // Otherwise... if (#44&1){ if (match(" ",ALL|ADVANCE)==0){ #1=min(#0,Chars_Matched) Char(-Chars_Matched) dc(#1) #0-=#1 } } c(#0) // Advance past the field... if (#44&2){ while(cc(-1)==' '&�--){ dc(-1) } } ri(#20) // and insert the delimiter/string } } // // Quote and Comma Delimit. // } else { for (#23=0;#23<#2;#23++){ #0=130+#23 #0=#@0 if (#0<0){ // For negative field size dc(-#0) // Simply delete the field } else { // Otherwise... if (!At_BoL){ Ins_Char(',') // Append comma separator } Ins_Char('"') // Append starting quote if (#44&1){ if (match(" ",ALL|ADVANCE)==0){ #1=min(#0,Chars_Matched) Char(-Chars_Matched) dc(#1) #0-=#1 } } c(#0) // Advance past the field... if (#44&2){ while(cc(-1)==' '&�--){ dc(-1) } } Ins_Char('"') // Append ending quote } } } // // Process remaining fields one at a time. // bs(#92,NOMSG) // Switch to Fields.Txt file BoF // // Just Delimit. // if ((#64&0x10)==0){ While(!AtEoF){ // For each field #3=cc // #3 = code letter {i,x} c // Advance past it #4=NE(ADVANCE) // #4 = field size c // Advance past field delimiter bs(#77,NOMSG) // Switch to data output file if (#3=='x'){ // For 'x' fields... dc(#4) // Simply delete the field } else { // Otherwise... if (#44&1){ if (match(" ",ALL|ADVANCE)==0){ #1=min(#4,Chars_Matched) Char(-Chars_Matched) dc(#1) #4-=#1 } } c(#4) // Advance past the field... if (#44&2){ while(cc(-1)==' '&--){ dc(-1) } } ri(#20) // and insert the delimiter/string } bs(#92,NOMSG) // Switch to Fields.Txt file } // (!At_EOF) // // Quote & Comma Delimit. // } else { While(!AtEoF){ // For each field #3=cc // #3 = code letter {i,x} c // Advance past it #4=NE(ADVANCE) // #4 = field size c // Advance past field delimiter bs(#77,NOMSG) // Switch to data output file if (#3=='x'){ // For 'x' fields... dc(#4) // Simply delete the field } else { // Otherwise... Ins_Text(',"') // Append comma and starting quote if (#44&1){ if (match(" ",ALL|ADVANCE)==0){ #1=min(#4,Chars_Matched) Char(-Chars_Matched) dc(#1) #4-=#1 } } c(#4) // Advance past the field... if (#44&2){ while(cc(-1)==' '&--){ dc(-1) } } Ins_Char('"') // Append ending quote } bs(#92,NOMSG) // Switch to Fields.Txt file } // (!At_EOF) } ////////////////////////////////////////////////////////////////////// // // // End of record processing. // // // ////////////////////////////////////////////////////////////////////// BS(#77,NOMSG) if (#26<0){ // If the final field is to be deleted dc(ALL) // Delete to end of the line if ((#64&0x10)==0){ // When not qcd... dc(-RSize(#20)) // Delete preceding delimiter/string as well } } else { // Else... if (#64&0x10){ // If qcd... Ins_Text(',"') } if (#44&1){ if (match(" ",ALL|ADVANCE)==0){ dc(-cmat) } } #0=Cur_Pos EoF() // Go to the end of the line if (#44&2){ #4=Cur_Pos-#0 while(cc(-1)==' '&--){ dc(-1) } } if (#64&0x10){ // If qcd... Ins_Char('"') // Append final quote } } // // Append NewLines, if so specified. // if (#68<6){ IN(1) } // // Switch back to the source data buffer. // BS(#90,NOMSG) } // Main processing loop #63 = 14 // "Stage" index ///////////////////////////////////////////////////////////////////////////// // // Set true to view final statistics. // if ( FALSE ) { if (!Is_Quiet) { Win_Hor(1) Message("Converted records: ") Num_Type(#78,NOCR) Message(" (") Num_Type(100,LEFT+NOCR) Message("%)") Win_EOL() Message("\nActual elapsed time: ") if ( 1 ) { Num_Type((Time_Tick - #32 + 500)/1000,LEFT+NOCR) Message(" seconds.") // Pause at end of message } else { Num_Type(Time_Tick - #32,LEFT+NOCR) Message(" milliseconds.") // Pause at end of message } if (!Is_Option(y)){ Get_Key("") } }} ////////////////////////////////////////////////////////////////////////////// // // Clean up // Buf_Switch(#75,NOMSG) // Switch to the main output file if (#99!=0x57495C44) { // Unless WildFile... File_Save(BEGIN+NOMSG) // Save output file; goto BoF (quickly) } else { // When WildFile... Buf_Close(DELETE|NOMSG) } // // Discard data description buffer. // Buf_Switch(#92,NOMSG) Buf_Quit(OK|DELETE|NOMSG) // // Release source data file. // Reopen normally unless terminating or // running under WildFile. // // if (wstat($)<0){wr($,5,top)};Reg_Lock_Macro(CLEAR);ws($);update() ? Buf_Switch(#90,NOMSG) if (#99!=0x57495C44){ File_Quit(OK) } else { Buf_Quit(OK|DELETE) } if (#99!=0x57495C44 && !(Is_Auto_Execution && (Is_Option(y) || Is_Option(q)))){ File_Open("|@(#12)",OK+NOMSG) } // // Restore text and numerical registers and then terminate. // //{ :DONE: Reg_Lock_Macro(CLEAR) //Disable further error trapping if (Win_Status('h')>=0){ Win_Delete('h') //Remove any Help window } #0=Win_Num Win_Switch(#43,NOMSG) // Switch to the data window, if not there now Win_Zoom(#42) // Restore original window zoom state Win_Switch(#0,NOMSG) if (#41) { //If the FileSelector Window was hidden Do_Visual("\ME\VI") //Reshow it now } Ch_Dir(@(#15)) //Restore original "current" directory if (#99==0x57495C44){ Buf_Switch(MAINBUF|NOMSG) } else { Buf_Switch(#75,NOMSG) //Switch to main output buffer } Reg_Empty(101) //Empty dialog submacro Reg_Empty(102) //Empty unexpected breakout trapper Reg_Pop(20,30) Reg_Pop(0,9) Num_Pop(70,99) //Restore numeric regs Num_Pop(0,59) Config(U_AUTO_CFG,#0) //Restore user's config values Config(F_AUTO_SAVE,#1) Config(F_OVER_MODE,#2) // no Config(F_F_TYPE,#3) // no Config(F_REC_HEAD,#4) Config(E_EXP_TAB,#5) Config(E_RETAB_BK,#6) Config(E_RETAB_FILL,#7 & 0xff ) Config(S_E_MORE,#8) Config(D_DSP_WRAP,#9) Num_Pop(0,10) //Restore remaining user numregs Reg_Lock_Macro(#66) #69 = 1 //WILDFILE flag for next time in if (Is_Option(y)) { XAll(NOMSG) } //If "-Y" invocation, exit now if (#99==0x57495C44) { //If WILDFILE macro running if (!Is_Quiet) { Type_Newline() } } if (#105) { vm(NOMSG) } return // // ShowHelpWindow - // :ShowHelpWindow: #0=Win_Num Win_Switch(#43) // Switch to the data window, if not there now Win_Zoom(#42) // Restore original window zoom state if (Win_Border>=2) { Win_Reserved('h',1,BOTTOM+NOBORDER) } else { Win_Reserved('h',1,BOTTOM) } Win_Switch('h') Win_Color(112) Win_Clear() Message("[VISUAL EXIT] (<\>) when done [VISUAL ESCAPE] (<\>) to quit",EXTRA) Win_Switch(#43) //Switch back to message window return // // Toggle FileSelector Window // :ToggleFileSel: Do_Visual("\ME\VI") return // // BADLAY - NYI // :BADLAY: //} DONE()