/* uvhdcob.c - data file investigation utility                             */
/*           - displays copybook field-names beside field data contents    */
/*           - part of Vancouver Utilities package from UV Software        */
/*           - see documentation at: www.uvsoftware.ca/uvhdcob.htm         */
/*           - see 14 HELP screens in source program further below         */
/*                                                                         */
/*                        ** uvhdcob vs uvhd **                            */
/*                                                                         */
/* uvhd    - displays data records only (no knowledge of copybook fields)  */
/*         - uvhd is shareware & may be downloaded from www.uvsoftware.ca  */
/*         - source program is self-contained (no linkable archives req'd) */
/*                                                                         */
/* uvhdcob - displays copybook fieldnames, preceding data for each field   */
/*         - intended for use in conjunction with uvhd                     */
/*         - does not have all the functionality of uvhd                   */
/*         - displays only the 1st occurrence of occurs fields             */
/*         - uvhdcob requires a 'cobmap' (created from COBOL copybook)     */
/*           (field start,end,length,typ coded on right hand side)         */
/*         - cobmaps can be created with uvcopy job 'cobmap1'              */
/*           a 1 time operation to convert the COBOL copybook directory    */
/*           to a directory of 'cobmaps' (COBOL record layouts)            */
/*         - see instructions to create cobmaps further below              */
/*                                                                         */
/*                         ** uvhdcob FREE **                              */
/*                                                                         */
/* UV Software will give 'uvhdcob' to anybody that requests it (like uvhd) */
/* But, users would need 'cobmap1' to convert copybooks to 'cobmap's       */
/* Since this is a 1 time operation, users could zip the copybook library  */
/* and email to UV Software for conversion & return by email attachment    */
/*                                                                         */
/* ========================================================================*/
/* Owen Townsend, UV Software, 4667 Hoskins Rd, North Vancouver BC, V7K2R3 */
/*         Tel:   604-980-5434          Fax: 604-980-5404                  */
/*         Email: owen@uvsoftware.ca    Web: http://www.uvsoftware.ca      */
/* General purpose utilities for file conversion, maintenance,& sorting.   */
/* ========================================================================*/

/*eject*/
/***************************************************************************/
/*                   ** uvhdcob INSTALL/COMPILE **                         */
/***************************************************************************/
/*                                                                         */
/* The following assumes:                                                  */
/* - the program has been stored in subdir 'src'                           */
/* - subdirectory 'bin' exists to receive the compiled output              */
/* - your Unix/Linux/Windows system has an ANSI C compiler                 */
/*                                                                         */
/* 1. cp uvhdcob.c src/uvhdcob.c   - store program in source subdir        */
/*    ==========================   - ensure the filenmae is 'uvhdcob.c'    */
/*                                                                         */
/* 2. cc -DH64 src/uvhdcob.c -obin/uvhdcob <-- compile the program         */
/*    ====================================                                 */
/*       -DH64 <-- option for 64 bits (omit for 32 bits)                   */
/*                                                                         */
/* 3. Add bin to your PATH so you can execute it from anywhere.            */
/*                                                                         */
/*    PATH=$PATH:/home/userx/bin; export PATH                              */
/*    =======================================                              */
/*                                                                         */
/* Test as follows assuming:                                               */
/* - demo file 'custmas1' downloaded & stored in subdir data/...           */
/* - demo copybook 'custmas1.cpy' downloaded, converted to cobmap          */
/*   & stored in subdir maps/... (remove suffix)                           */
/* - OR, download cobmap 'custmas1.map' & store in subdir maps/...         */
/*   (remove suffix, to specify as just 'maps/custmas1'                    */
/*                                                                         */
/* 4. uvhdcob data/custmas1 maps/custmas1 - test with supplied files       */
/*    ===================================                                  */
/*                                                                         */
/*                 ** converting all copybooks to cobmaps **               */
/*                                                                         */
/* 1. mkdir maps                           - make directory for cobmaps    */
/*                                                                         */
/* 2. uvcopyx cobmap1 cpys maps uop=q0i7p0 - generate cobmaps from copybooks*/
/*    ====================================                                  */

/*eject*/
/***************************************************************************/
/*              ** possible customization re: PRINTING **                  */
/***************************************************************************/
/*                                                                         */
/* Note that the other print command 'p' does not print immediately, but   */
/* collects all the printed data in a tmp/file, which is subsequently      */
/* printed manually after you quit the uvhdcob utility.                    */
/*                                                                         */
/* immediate print 'i' uses the command stored in the variable 'prtcmd'   */
/*                                                                         */
/*     char prtcmd[30] = "uvlp";     (original command)                   */
/*                                                                         */
/* 'uvlp' is a script, 1 of several supplied scripts using the 'uvlist'    */
/*  utility, which supplies page headings & page numbering                 */
/*  - see install.doc for instructions to modify the destination printer   */
/*    used by these scripts                                                */
/*                                                                         */
/* You could modify the script called by the 'i' command                   */
/* - for example to print at 12 chars per inch (vs default 10 cpi)         */
/* - in fact it is uvlp12 that has been coded at prtcmd later in this file*/
/*                                                                         */
/*     char prtcmd[30] = "uvlp12 ";    (modified command)                  */
/*                                                                         */
/*                      ** known bugs **                                   */
/*                                                                         */
/*Dec08/10 - file-locking added                                            */
/*         - 'e'xit to uvhd now gets file-lock if uvhdcob optin 'u'pdate   */
/*         - might prompt to proceeed without lock (option u2) ??          */
/*                                                                         */
/*eject*/
/*                  ** change history - latest 1st **                      */
/*                                                                         */
/*Dec02/11 - changes to compile with MinGW on windows command line         */
/*         - #ifdef DWIN disable lockfile,sleep,                           */
/*         - enable LF64 always (MinGW allows, don't disable via !DWIN)    */
/*         - change lseeki64 to _lseeki64 for MinGW                        */
/*                                                                         */
/*Nov11/11 - allow CR/LF (dont show BadC) if CR/LF in last field of cobmap */
/*                                                                         */
/*Oct08/11 - restore E64 printf %ld or %lld long or long long 32bit HP gcc */
/*Oct05/11 - make H64 the default (unless -DH32 spcfd)                     */
/*         - show machine & H32/H64 on last help screen                    */
/*         - remove hardcoded #define H64, for Mexico test -DH32 long long */
/*         - IBM Mexico compile problems on HP Itanium stat64 missing ?    */
/*         - move #includes prior to struct stat64 fstat1 (unlikely to fix)*/
/*Oct04/11 - changed long's to UVi64 for 32 bit compile gcc HP Itanium     */
/*         - note May19/11 'strtol' should have been 'strtoll'             */
/*Sep30/11 - complete updates for grp occurs nesting                       */
/*           by copying code from display to printec & verify1             */
/*Sep27/11 - debugging group occurs nested level 2                         */
/*Sep26/11 - add code for nested group occurs level 2 only                 */
/*         - prelim, display only, not yet print & verify                  */
/*Sep25/11 - collect group occurs info into a structure                    */
/*         - in prep for adding group occurs nested levels                 */
/*                                                                         */
/*Sep06/11 - fix odo count 0 if odo field 1                                */
/*         - remove bad2hex CR/LF exception to show odo 13 or 10           */
/*Sep04/11 - show search match on 1st screen problem fix for occurs        */
/*         - change maptbl index to data dsplcmnt corrected for occurs     */
/*Sep03/11 - insert bold control codes if search match field               */
/*Sep03/11 - add subrtn lookmap to find maptbl index for matched field     */
/*         - to show search match field on 1st screen of long records      */
/*         - might disable if group/item occurs (too confusing ?)          */
/*Sep02/11 - correct bgn/end bytes for fields following occurs depending on*/
/*         - test last field in record for occurs depending on             */
/*         - increase linemax from 18 to 20                                */
/*         - extra fields RDW ODO fields, try rii+rdwhs endscreen/endrec   */
/*Sep01/11 - allow pic x 1 byte binary for occurs depending on             */
/*Aug26/11 - allow for multiple occurs depending on                        */
/*         - increase maprw.des to 68                                      */
/*Aug25/11 - retrieve dpending on count via *BGNOCCURS start,lth,type adds */
/*           *BGNOCCURSM:c-p:00024*00010=00240:00010-00249:1:00008:02pns   */
/*Aug25/11 - option i4 test non-signif fields 4 functions for 4 field types*/
/*         - testnp=packed,testnb=binary,testnn=numeric,testnc=character   */
/*Aug23/11 - option i4 testnz test all ASCII blanks in packed fields       */
/*Aug22/11 - test end of record when occurs # to # depending on            */
/*           and variable length records (RDW,BDW,IDXFORMAT3/8)            */
/*         - increase RMAX from 16384 to 32768                             */
/*Aug21/11 - option i4 testnb, also test for nulls & EBCDIC blanks         */
/*         - convert occurs options g99/o99 to g99999/o99999               */
/*Aug17/11 - fix bug loop on item occurs within group occurs               */
/*         - at end item occurs, reset ooee as well as ooii                */
/*Aug13/11 - update printrec & verify1 as per screen display               */
/*         - add code to inhibit 0/blank occurs/all fields                 */
/*Aug13/11 - errmsg/quit if data file empty                                */
/*Aug13/11 - chg update to convert op1 lth 99 to  recsize                  */
/*           & if op2 1 byte, then memset all op1 lth to op2 constant      */
/*Aug13/11 - add option i4 to inhibit display of ALL 0/blank fields        */
/*Aug13/11 - combine iprint into print as option 'i'                       */
/*         - chg occurs optn 'v' to optn 'i', allow cmd 'i' to set optn 'i'*/
/*         - use option i for inhibit show 0/b flds, will use LEM          */
/*           i1 = item occurs, i2 = group occurs, i4 = all fields          */
/*                                                                         */
/*Aug13/11 - remove code to display base fields to partial redef records   */
/*         - if req'd add back better code by field count ?                */
/*           (see old solution in versions prior to Aug03/2011)            */
/*                                                                         */
/*Aug03/11 - add code for GROUP OCCURS                                     */
/*                                                                         */
/*eject*/
/*Jun15/06 - fix Jun12 bug, save bdwmin if > bdwsize & bdwmin > rdwmax     */
/*Jun14/11 - fix ERR dsp+lth > rcsz for varlth recs when lth dflt maxsize  */
/*         - chg rszox to rcsmax = rszo (fixlth) or rdwmax (varlth)        */
/*Jun12/06 - ensure BDWmin not saved from last block in file               */
/*         - fix rdwerr report showing bdwsize from build not current BDW  */
/*Jun11/06 - fix move/moven/acum, chg recb to recd except recsave I/O      */
/*                                                                         */
/*May28/11 - search msg progress interval count option p dflt 1,000,000    */
/*         - search op max check based on max recsz not current recsize    */
/*         - add progress check to Index build at __ bytes of __ filesize  */
/*May24/11 - fix 'occurs 0020' allow up to 5 digits vs 3                   */
/*May19/11 - fix index not working fileptr > 2.1 gig, chg fifp1 to UVI64   */
/*         - change strtol (req'd on unixware) to atol                     */
/*May11/11 - fix bug on index reload, set rcountx inhibit rcount calcrecs  */
/*May10/11 - correct BDW/RDW test BDW > 32768, coded 32678 in getrdwh & h2 */
/*May07/11 - enhance rdwerr(), show current BDW/RDW hor hex (like last BDW)*/
/*May04/11 - enhance rdwerr(), add values of RDW & last BDW val,rn#,fp,etc */
/*May03/11 - provide $UVTMPDIR define subdir for print,write,drop,index,etc*/
/*         - vs defaulting to tmp/ in current working directory            */
/*Apr29/11 - change 'help01 -' to 'H01.' to facilitate hyperlinks          */
/*           when help screens extracted for web docmentation              */
/*         - simplify f1 dflt build varlth, f0 no build, f2 force build    */
/*Apr28/11 Improve BDW/RDW z8 processing, while building index:            */
/*         - calc fileptr for next BDW & validate/bypass when reached      */
/*         - save min BDW (except last) to validate BDW bypass on find     */
/*         On find: bypass BDWs validating BDW > RDW & BDW >= min BDW saved*/
/*         major rewrite: getrdw(), getrdwh(), getrdwh2(), rdwerr(),       */
/*         - remove scans for RDW headers if off-track                     */
/*Apr04/11 - do not translate *TYPEs coded in hex                          */
/*Mar29/11 - change findex build index for Todd Reineke IBM                */
/*         - store fileptr corspndng to recnum1 in 1% slots                */
/*Mar13/11 - fix rcount 1 too high for varlth RDW files see getrec()       */
/*         - for -1 at EOF varlth, use rcount (last rec#) for findrec()    */
/*Mar07/11 - all %lld change to %ld (%lld problem on SUN, %ld OK)          */
/*         - old E48/E64 def of %lld/%ld/%d removed                        */
/*Mar05/11 - add EOF test in getrdw1 as well as in getrdw                  */
/*Feb27/11 - allow RDW records up to 32K (vs 16K)                          */
/*         - problem sprintf %lld on SUN, changed to %ld OK                */
/*Feb26/11 - add crossfoot option x to acum command                        */
/*         - if cmd line option 'a', chg default coding in parse to EBCDIC */
/*         - fix tstsignz for EBCDIC separate sign recognition             */
/*Feb25/11 - show hex for bad fields > 9 bytes on 2nd line                 */
/*Feb24/11 - define H64 always (all machines now 64 bits)                  */
/*         - change optn 'g' (0/1 relative) to optn 'c'                    */
/*         - add option g# recsize extra bytes (for LF or CR/LF etc)       */
/*Feb22/11 - show decimal value on right for 8 byte binary fields          */
/*Jan14/11 - fix z8 bug, do not bypass prefix if next prefix all nulls     */
/*         - allow option z8 write BDW = RDW+4 (on every record)           */
/*Jan12/11 - screen/print hdr#1: "now=yymmdd:hhmm uvhd filename options    */
/*         - screen/print hdr#2: "version=yymmdd records=... etc           */
/*         - fix bug, chg search4 to search234                             */
/*eject*/
/*Jan10/11 - add optn x1/x2/x4 inhibit validity check num/pack/char fields */
/*         - insert version date in screen/page headings                   */
/*         - build index for all file types, add option f0 to inhibit      */
/*           change existing option f# to b# rec# begin display            */
/*         - fix findrec not finding rec#s lower than current rec#         */
/*         - promote f0->f1 & fix 0 rel findex problem ?                   */
/*         - inhibit convert 99 to 999999999 if find command               */
/*         - use optn b fileptr byte# vs f0 now inhibit build Find index   */
/*                                                                         */
/*Jan02/10 - insert cmd & filename when verify print file opened           */
/*                                                                         */
/*Dec31/10 - append verify stats at end of print output file               */
/*Dec30/10 - fix bug field ctr not reset when printing - see printrec()    */
/*Dec30/10 - on verify print add option j write formfeed every j# records  */
/*Dec29/10 - add cmd 'l' to close files (lw,lp,lvp,lvw)                    */
/*Dec28/10 - add verify option to write/print records with verify errors   */
/*Dec28/10 - insert 'Bad@ 1234' if verify stored err dsplmcnt beyond occurs*/
/*Dec27/10 - add option to show occurs o1 deflt, o2 all, o4 1st or 1st err */
/*         - chg current optn o to optn j (execute cmd & quit)             */
/*Dec27/10 - chg optns for 4 field start bytes to 2 ranges a-b & c-d       */
/*Dec26/10 - add 'move Numeric' command (n)                                */
/*Dec26/10 - default command records to process count to 1 if unspcfd      */
/*      ---> should this be done in parse ?? <---                       */
/*         - add verify optn z4 cnvrt unprintables to periods              */
/*           in ASCII & EBCDIC files (add trnslt table trtprintE.c)        */
/*Dec25/10 - add verify optns z1/z2 to cnvrt all blank num/pack to zeros   */
/*Dec24/10 - reorganize command line options                               */
/*         - use x1/x2/x4 nostop on verify num/pack/char (chg x to o)      */
/*         - fix bug rollback displaying next record                       */
/*         - fix bug acum > 2 gig total bad (chg %d to %ld)                */
/*         - allow sign options on v cmd as well as cmd line               */
/*Dec24/10 - add alt verify msg with 1st & last rec#s with errors          */
/*           when no-stop-on-err options used to count errs til EOF        */
/*         - inhibit screen field titles if EOF (rsize 0)                  */
/*         - inhibit "continue til EOR -->" if EOF (rsize 0)               */
/*         - removed optn c1 to disable default nondisplay to periods      */
/*Dec23/10 - add verify no-stop-on-error options h1 num, h2 packed, h4 char*/
/*         - if vv has options, replace vargs options with cargs options   */
/*         - + opmsg3 for verify, use vv99 continue, vv99x7 count/nostop   */
/*         - change '999' to '99' to set count 999999999 for EOF           */
/*Dec23/10 - test options to allow signs in units of numeric fields        */
/*      y1 - (default) Micro Focus COBOL comatible neg x'70' p-q           */
/*      y2 - EBCDIC signs, optn 'a' translates to ASCII before verify num  */
/*         - orig EBCDIC signs: pos {A-I x'C0'-x'C9' neg }J-R x'D0'-x'D9'  */
/*         - after translation:     pos '{' & 'A'-'I' neg '}' & 'J'-'R'    */
/*      y4 - separate +/- signs anywhere in field                          */
/*      h1 - dont stop on verify num err (vs c1 conflict '.' unprintable)  */
/*      o1 - allow CR &/or LF in character pic x fields                    */
/*Dec22/10 - require write to spcfy number or pattern (use w999 for all)   */
/*         - add options to allow signs in units of numeric fields         */
/*Dec21/10 - add 'acum1' command from uvhd (+ getop,putop1,etc)            */
/*         - use updated parse() from uvhd                                 */
/*         - 1st change uvhdcob atol1a/atol3a back to atol1/atol3          */
/*eject*/
/*Dec07/10 - in upfileptr() calc recnum1 if Fixlth                         */
/*         - fix '-' records upfileptr(-(cmn*rsz1))                        */
/*         - setlock on fileopen if option u (but not u2)                  */
/*         - verify move op1 dsp+lth not > recsize                         */
/*         - allow update constant lth < op1 lth & blank excess            */
/*         - if optn a EBCDIC, constants s/b EBCDIC & clear blank EBCDIC   */
/*                                                                         */
/*Dec06/10 - add MOVE field/cosntant command                               */
/*         - allow count on repeat cmd (uu99, mm99, etc)                   */
/*         - convert 999 to 999,999,999                                    */
/*                                                                         */
/*Nov25/10 - add write option d for dsplcmnt to begin output record data   */
/*         - consider write option d in calc of wrec1b & wrs1w vs fwrite   */
/*                                                                         */
/*Nov22/10 - default numeric cmd to 'r' fixed OR 'f' if variable length    */
/*         - convert +/- to find cmds for varlth files                     */
/*         - allow longer filenames, 180 for dir/filename, 128 for filename*/
/*                                                                         */
/*Nov21/10 - make build Find Index automatic at startup for varlth files   */
/*         - allow hex constants on cobmap *TYPE=0(1),=X'FF','fieldname'   */
/*                                                                         */
/*Oct13/10 - insert space between bgn/end (John Faulhaber IBM)             */
/*                                                                         */
/*Aug22/10 - test optn g1 to report dsplcmnts 1 rel vs 0 rel               */
/*Aug21/10 - use '-Wall' to eliminate all Warnings on -DH64 compile        */
/*         - still get warns on 32 bit on printf %ld UVi64 (E64 to fix ?)  */
/*Aug19/10 - add option k1 to set command help prompts on (same as cmd k1) */
/*Jul11/10 - if variable lth, initial prompt to use indexing               */
/*         - prompt to use fi/f# if r# used on varlth files                */
/*         - add Indexing elapsed time msg                                 */ 
/*         - build index by option 'fi' (from anywhere, high count N/R)    */
/*Jul09/10 - build Index tables for findrec() faster access by record#     */
/*         - tables of fileptrs & record#s to 1,2,3% etc of filesize       */
/*         - init/build when find cmd at rec#1 & optn 'i' or count 9999    */
/*Jun05/10 - on exit to uvhd, pass optns from orig uvhdcob cmd (z4,etc)    */
/*         - chg exit cmd optn 'f' to fileptr(byte#) vs 1st rec# to display*/
/*         - allow numeric values>2gig on cmds b2200000000 fix setfileptr  */
/*         - add menu summary as help screen#1, expand to 13 help screens  */
/*Jun04/10 - test option to transfer update & tally args to search args    */
/*         - for subsequent 'ss' to verify updates & tallys                */
/*         - chg rsz1 to rszo for parse() check for varlth files           */
/*Jun03/10 - inhibit options not working on 1st field in record            */
/*         - change 1st test (if maprw.bgn > 0) to maprw.lth               */
/*         - added (vargs.opc['a'-'a']), etc - now OK                      */
/*Jun02/10 - inhibit subsequent calcrecs when EOF detected in getrec()     */
/*May31/10 - major updates as per uvhd: new getrec,getrwd with upnext ctl  */
/*         - add cmds k0 to kill help prompts & k1 to restore              */
/*         - replace filename on stats (at bottom screen) with filepointer */
/*           (filename shows at top when at begin file)                    */
/*         - default record dsplcmnts all segments vs fileptr at recdsp 0  */
/*           option d2 - show file dsplcmnts on all segments               */
/*May22/10 - chg getrect back to bufn=0 each get & set buf rdsize rszo+128 */
/*         - so reset rec# works, need to force reread after seek          */
/*May21/10 - use getrect/getcbuf from uvhd                                 */
/*         - at begin rec, clear rec area to rszox (rszo+256)              */
/*eject*/
/*May20/10 - allow TYPE by record-size (for RDW, IDX, text)                */
/*         - change getrect/getcbuf read 8000 bytes vs rszo                */
/*May19/10 - clear recb to blanks lth RMAX at program init                 */
/*         - clear recb to blanks (vs nulls) lth rszo before each getrec   */
/*May19/10 - change optn z8 to BDW/RDW, bypass BDW in getrdw1()            */
/*         - BDW/RDW 4+4, BDW bypasswd, else like z4                       */
/*         - writerec optn t1/t2 change terminator back to follow recsize  */
/*         - losing data if input is RDW                                   */
/*Mar21/10 - add options a,b,c,d to verify to inhibit fields by start byte#*/
/*Mar20/10 - inhibit verify of redefined fields                            */
/*         - especially for packed fields redefined as numeric             */
/*Feb06/10 - chg optn c1 from do not display num fld bad data msg          */
/*           to do not stop on bad num field                               */
/*Apr21/09 - concat cmd line options on any UVHDCOBROP (was overwriting)   */
/*Mar19/09 - if RCSZ=..... not found on 2nd line cobmap, errmsg/exit       */
/*         - if rszmap not stored, default to 256 to prevent core dump     */
/*Mar07/09 - add subfunctions for standalone compile (for free-ware)       */
/*         - BUT cannot make freeware because we need uvcopy cobmap1 !!!   */
/*Feb12/09 - 'vv' to bypass current record before verify search            */
/*Feb08/09 - try 3 ways to access copybook from arg2 entered               */
/*         - arg2 as entered, $RUNLIBS/arg2, or $RUNLIBS/maps/arg2         */
/*Feb05/09 - combine getrev & getrecx as getrecv using getrecx code        */
/*         - change all UVint to int                                       */
/*         - on write cmd, remove option x to write 2nd file of non-matches*/
/*         - write options changed from command line to write command:     */
/*         - a2->a1(ASCII), c2->c1(chars) ,k1/k2->n1/n2(recsizenumerics)   */
/*         - w#->r#(recsize), y#->t#(terminator)                           */
/*         - add write optns z2/z4 to write RDW records                    */
/*         - common subfunctions openfileX & closefileX for P,I,W, files   */
/*         - chg P/I/W cmds to open & close output file on each cmd        */
/*         - cmd line option w1 to write 1 combined file vs separate       */
/*Feb03/09 - add bad numeric test to printrec (from display)               */
/*         - chg verifyn to allow signs in units byte                      */
/*         - for numerics, replace unprintables with '.'s (not non-numerics)*/
/*Feb02/09 - also verify numeric fields (add subfuns verifyn, badn2hex)    */
/*         - provide option c1 to inhibit stop on bad nums (Feb06/10)      */
/*         - recnum1 fixed RDW files, incrmnt only if fileptr > fileptrLG  */
/*         - update fixed, change 'recd' to 'recb' for I/Os in update      */
/*Jan29/09 - verify packed & character fields command added                */
/*Jan27/09 - got warn asngmnt makes ptr from int w/o cast (atol1 & spcopy) */
/*         - changed all 'UVint' to 'int' & some errs went away            */
/*         - copied atol1 & spcopy into uvhdcob (renamed atol1a & spcopya) */
/*         - if char data has unprintables, show hex on right, bad2hex()   */
/*Jan2009 - uvhdcob updated from uvhd (many updates not made to uvhdcob)   */
/*        - allow Large Files > 2 gig, allow RDW files, etc                */
/*Jan1999 - uvhdcob created from uvhd + code for copybook fieldnames       */
/*Jan2009 - uvhdcob updated from uvhd (many updates not made to uvhdcob)   */
/*        - allow Large Files > 2 gig, allow RDW files, etc                */
/*Oct21/06 - add program name 'uvhdcob' on record header                   */
/*Mar2005 - show decimal values for 2 & 4 byte binary fields               */
/*Nov2004 - not yet updated for LARGEFILE suport (as per uvhd)             */
/*Jan2002 - revise for new cobmap1 layout                                  */
/*9911 - add support for Micro Focus ISAM variable length records          */
/*     - implement as option v (see cmd line optins v1,v2,v4)              */
/*Jan99 - original creation, based from uvhd                               */

/*eject*/
/*uvhdcob-------------- command help screens  ------------------------*/
/* - displayed if cmd line has no args or too many args                */
/* - displayed if operator command incorrect                          */

char *help01[28] = {
" ",
"              ** H01. Help Menu, uvhdcob version 20111202 **",
" ",
"H01. Help Menu Summary (enter # to goto desired help screen)",
"H02. uvhdob command format (datafile, copybook,& options)",
"H03. command line options a - t",
"H04. command line options u - z",
"H05. Browsing, jump to rec# or byte# (fixed-lth), find by rec# (var-lth)",
"H06. Searching by data strings with optional qualifiers",
"H07. Update 1 or multiple records, with optional qualifiers",
"H08. Update/Clear record areas to the 1 byte specified by op2",
"H09. Accumulate(a) record field (zoned/packed/binary)(all or qualified)",
"H10. print to a file (option 'i' to schedule lp if configured)",
"H11. write records to subdir $UVTMPDIR/... (selected by qualifier patterns)",
"H12. Write options (recsize, fixlth, text, RDW, etc)",
"H13. sequence check & tally (count records) ",
"H14. Verify data: digits/signs in numeric/packed, unprintables chars",
"H15. option z correct blanks in numeric/packed & unprintables in pic x",
"H16. Move character (m) & move Numeric (n) ",
"H17. Move Application - create Telephone list from customer master",
"H18. Exit to uvhd (hexdump of record, quit uvhd returns to uvhdcob)",
"H19. set Item/Group Occurs display & Inhibit zero/blank fields",
"H20. Multi Record *TYPE files (type control record in copybook maps)",
"H21. Index file saved in $UVTMPDIR/..., saves for next uvhd same file&size",
"uvhdcob version 20111202 - Copyright (C) UV Software Inc. 1993-2011",
"see complete documentation at: www.uvsoftware.ca/uvhdcob.htm",
"!"};

/*eject*/
char *help02[28] = {
" ",
"                 ** H02. command format & options **",
" ",
"uvhdcob    datafile     copybook-map   [options]   <-- uvhdcob format",
"================================================",
" ",
"uvhdcob dat1/custmas1 cobol/maps/custmas1 r256m50u <-- example",
"==================================================",
"options 'r256m50u' - must be contiguous (alpha+digits+alpha+digits+...)",
"         r256      - rec-size, omit to use RCSZ= in map, specify to override",
"             m50   - max lines per screen, default 25, use 50 for PC terminal",
"                u  - allow Updates (specify on command line if update intent)",
" ",
"uvhdcob dat1/custmas1 cobol/maps/custmas1   <-- may omit reciord-size",
"=========================================       if copybook/map correct",
"R#    - change Rec-size (Fixed-lth) vs option 'r' on command line",
"?     - display help screens",
" ",
"uvhdc2 dat1/custmas1  <-- uvhdc2 format - uvhdc2 script omits copybook-map",
"====================      via ctlfile54I relating datafile to copybook-map",
"                        - may specify options as arg2 to override defaults",
"Note - uvhdc2 script needs to be setup & customized at each site",
"     - see www.uvsoftware.ca/uvhdcob.htm#K1 - K6",
" ",
"!"};

/*eject*/
char *help03[28] = {
" ",
"                  ** H03. command line options **",
" ",
"a   - Assume EBCDIC input, translate char fields to ASCII display",
"b#  - Begin display with this record# (vs default #1)",
"c1  - show field begin/end 1 relative vs 0 rel (assumes copybook is 0 rel)",
"d1  - display Debug msgs for cobmaps with multi *TYPE defs",
"e1  - inhibit Errmsg when file-size not evenly divisible by record-size",
"f1  - build Index for Variable-Length files (BDW/RDW,IDXf8,text)",
"    - build Index for Fixed-Length files NOT required, can calc fileptrs",
"f0  - inhibit Index build (save time if only need to see 1st few records)",
"f3  - force Index re-build even if existing & filesize unchanged",
"g#  - Group occurs display desired, default 1st only, g99 for copybook max",
"    - Group & Item occurs may also be set by commands g & o, see H19",
"i1/2/4 - inhibit display zero/blank entries, i1=Item occurs,i2=Group,i4=ALL",
"       - inhibit 0/b entries may also be set by command i, see H19",
"j=..- command to execute & exit from uvhdcob",
"k1  - set command help prompts on (2 extra lines below data display)",
"m#  - Max lines/screen (default 16) allow for hex/char, sp1/sp2",
"o#  - Item Occurs display desired, default 1st only, o99 for copybook max",
"    - may also enter desired group/item occurs g#/o# at the command prompt",
"p#  - progress message interval (search,index) record count default 1000000",
"r#  - Record size overrides RCSZ= in cobmap file  default 256",
"s2  - Space 2 between headings & field names/data lines ",
"t   - Text records ended by LF=x'0A' (specify option r if recsize > 256)",
"! exclamation mark in 1st col ends the help screen display" };

char *help04[28] = {
" ",
"                  ** H04. command line options **",
" ",
"u    - allow Updates to file (will lock file) else read only",
"       applies to: Update,Move,& Verify option z correct blank numerics",
"u2   - updates without file-lock (to allow Exit 'e' to uvhd)",
"v    - Variable length records in Micro Focus Indexed file ",
"       show recs: v1=active, v2=deleted, v4=system, v8=system1 (default=v7)",
"x1   - inhibit validity check <-BadN on numeric fields", 
"x2   - inhibit validity check <-BadP on packed fields", 
"x4   - inhibit validity check <-BadC on character fields", 
"x7   - inhibit validity checks on all field types (x1+x2+x4=x7)",
"y_   - option for signs in numeric fields for 'verify' (v) command",
"     - may specify on command line OR on each verify command",
"y1   - MF COBOL comatible (default): -0123456789 = pqrstuvwxy (zones x'70')",
"y2   - EBCDIC signs: +0123456789 = {ABCDEFGHI, -0123456789 = }JKLMNOPQR",
"y4   - separate +/- signs (leading or trailing)",
"y1   - default is y1 if input file is ASCII (default)",
"y2   - default is y2 if input file is EBCDIC (option 'a' on command line)",
"z#   - input RDW format (2,4,8 byte prefixes with recsize in binary)",
"z2   - RDW prefix 2 bytes only, recsize EXCLUDES prefix size",
"z4   - RDW prefix 4 bytes, recsize 1st 2, 3&4 nulls, recsize INCLUDES prefix",
"z8   - BDW/RDW 4+4, BDW bypasswd, else like z4",
"z1   - (+ 1 bit) = z3/z5/z9 Little-end binary, z2/z4/z8 default BIG-end",
" ",
"! - exclamation mark in 1st col ends the help screen display" };

/*eject*/
char *help05[26] = {
" ",
"                  ** H05. Browsing, Jumping, Finding **",
" ",
"null  - next record (or next segment if rcsz > 384)",
"b#    - goto a specific byte#  within the file (zero relative)",
"r#    - goto a specific record# within the file (one relative)",
"###   - may omit 'r', a number assumed to be a record# (if Fixed-length)",
"+#    - advance a specified # of records (from current position)",
"-#    - backup  a specified # of records (from current position)",
" ",
"f#   - find records by record# in LARGE variable length files (RDW,text,IDX)",
"f#   - use 'f#' if you need exact record# in Large Variable-Length files",
"f#   - uses an Index of record#s & filepointers to find records quickly",
"     - Index built at program startup if variable lth input (RDW,text,IDX3/8)",
"###  - may omit 'f', find record# assumed if BDW/RDW variable length file",
" ",
"r1        - might return to record #1 before using options m & n",
"f99m123   - option 'm' to find record with specified record-size",
"f99m50n90 - option 'm' & 'n' to find records from minimum to maximum size",
"          - 'f99' used to search to EOF (99 is short for 999999999)",
"ff        - repeat prior find command, to find next rec with m & n size",
"ff        - 'ff' saves retyping big numbers & options m & n",
"!"
};

char *help06[26] = {
" ",
"                        ** H06. Search ** ",
" ",
"uvhdcob dat1/custmas1 cobol/maps/custmas1  <-- run uvhdcob on customer master",
"=========================================      data-file & copybook-map",
" ",
"s 'ABC'           - search (until EOF) for 'ABC' anywhere in the record",
"s 40(40),'ABC'    - search for 'ABC' anywhere in columns 41-80",
"s 20(3),!'000'    - search for records with cols 21-23 NOT 000",
"s 0(80),=x'0C'    - search for a FormFeed x'0C' anywhere in 1st 80 bytes",
"s 0(80),>x'7F'    - search for any byte > x'7F' in 1st 80 bytes of records",
" ",
"s 'ABC',,'XYZ'    - search for 'ABC' AND 'XYZ' anywhere in record",
"s 'ABC',|,'XYZ'   - search for 'ABC' OR  'XYZ' anywhere in record",
" ",
"s 0(40),'AB',40(40),'CD' - search for 'AB' in cols 1-40 & 'CD' in cols 41-80",
"s 0(1),'1',|0(1),'9' - search for '1' OR '9' in byte 0 (col 1)",
"s 0(1),'1',|,'9'  - same as above, op3 start(lth) defaults to op1",
"s 0(1),>'0',,<'9' - search for records wwith 1-8 in the 1st byte",
" ",
"ss                - repeat last search (from current record)",
"sss               - repeat search (in same record incrementing column)",
" ",
"!"
};

/*eject*/
char *help07[26] = {
" ",
"                      ** H07. Update **",
" ",
"uvhdcob dat1/custmas1 cobol/maps/custmas1 r256u <-- must specify option 'u'",
"==============================================*     on command line",
"u 0(3),'ABC'     - update 1st 3 bytes of current record to 'ABC'",
"u 78(2),x'0D0A'  - update bytes 79 & 80 of current record to x'0D0A'",
"uu               - repeat last update (on current record)",
" ",
"u99 0(3),'ABC'         - update until EOF ('99' is short for 999999999)",
"u99 10(1),'*',8(1),'D' - update byte 10 to '*', IF byte 8 is 'D'",
"u99 8(1),'X',8(1),'D'  - change any 'D' in column 9 to 'X'",
" ",
"x  - rollback last update to current rec (repeat toggles last update)",
"X  - rollback all updates to current rec (repeat toggles all updts)",
"   - rollback ability is lost if you move off current updated record",
"   - no rollback is possible for multi-record updates",
"   - could 'w'rite (backup) entire file to tmpdir before updts",
" ",
"u99s 77(2),'AB',,'AL' - update bytes 77-78 with 'AB' if currently 'AL'",
"   s        <-- note option 's' on 'u99s' saves update args in search args",
"1               for subsequent reset to BOF (by goto record #1)",
"ss          <-- and 'ss' to verify updates (without re-entering arguments)",
" ",
"!"
};

char *help08[26] = {
" ",
"                      ** H08. Update/Clear **",
" ",
"uvhdcob dat1/vendormas3 cobol/maps/vendormas z4u <-- options RDW & Update",
"================================================",
"- update may clear large areas to the 1 byte op2 constant",
"- specify op1 length as (99) to clear entire variable length records",
" ",
"u 0(99),x'00'  - clear record to hex zeros, (99) indicates entire record",
"               - clear variable length records (except BDW/RDW prefixes)",
"u 4(99),x'00'  - use 0(99) for uvhdcob, but 4(99) for uvhd since RDW shown",
" ",
"uu             - repeat last update (after moving to new record)",
"X              - rollback updates to current record",
" ",
"u99 0(99),'_'  - clear all records to all underscores (assuming on record#1)",
"               - clears all bytes of all records (except BDW/RDW if variable)",
"X              - NO rollback for multi-record updates",
"               - recommend backup/copy file before multi-record updates",
" ",
"!"
};

/*eject*/
char *help09[26] = {
" ",
"                   ** H09. Accumulate (a) **",
" ",
"uvhdcob dat1/custmas1 cobol/maps/custmas1 r256 - customer mstr sales history",
"==============================================",
"                   - see custmas1 demofile at www.uvsoftware.ca/uvhd.htm#4A2",
"a 120(5p)        <-- accum 5 byte packed field from current record until EOF",
"=========",
"1                                  <-- return to begin file before next acum",
"a 120(5p),,77(2),'BC'              <-- acum if 'BC' in bytes 77-78",
"a 120(5p),,77(2),'AB',|77(2),'YK'  <-- acum if 'AB' or YuKon",
"a 120(5p),,77(2),'AB',|,'YK'       <-- acum if 'AB' or 'YK', omit 2nd 77(2)",
"a 120(5p),,77(2),'BC',90(3),!'604' <-- acum if 'AB' and area code not=604",
"ax12 120(5p)  <-- crossfoot & acum 12 x 5 byte packed fields (this yr sales)",
" ",
"uvhdcob dat1/sales2 cobol/maps/sales2 r64 - sales detail records",
"=========================================",
"             - see sales2 demofile at www.uvsoftware.ca/uvhd.htm#4A3",
"a 53(9)    <-- acum 9 bytes (assume unpacked Ascii, sign in zone or sep +/-)",
"=======      - zone +sign x'3_', -sign x'7_' (Micro Focus COBOL compatible)",
"a 53(9ze)  <-- acum 9 byte Zoned Ebcdic, +sign x'F_' or x'C_', -sign x'D_'",
"=========    - do not need (_ze) if option 'a' on cmd line for EBCDIC input",
"a 53(9zx)  <-- need (_zx) ASCII file with EBCDIC signs vs Micro Focus signs", 
" ",
"!"
};

char *help10[28] = {
" ",
"                            ** H10. print **",
" ",
"print - write formatted records to a file for subsequent lp,uvlp,vi,etc",
"      - writes $UVTMPDIR/filename.yymmddhhmmP (concatenated for uvhd session)",
" ",
"p5              - print 5 recs from current position",
"p 'ABC'         - search for & print records with 'ABC' anywhere in record",
"p5 0(40),'ABC'  - search & print 5 max with ABC within 1st 40 bytes",
"p 40(3),e'ABC'  - print if EBCDIC 'ABC' 41-43 (use with cmdline a optn)",
"p9f3            - print 9 records, formfeed after every 3rd record",
"p <' '          - print records with any bytes < space char",
"p5 0(40),<x'20' - print 5 max with any bytes < space in 1st 40 bytes",
"p24f4           - print 24 records, formfeed after every 4th record",
"pp              - repeat last print command (from current position)",
" ",
"lp  <-- may follow print command with 'lp' command to close file for separate",
"        output files or omit for combined outputs from multi print commands",
" ",
"p5i <-- option 'i' Immediate print (Aug2011 change to option vs command 'i')",
"      - calls script 'uvlp12' which schedules 'lp' to print the tmp/... file",
"        'export UVLPDEST=-dPRINTERNAME' in profile defines printer near you",
"      - see uvhd doc for more info on immediate printing",
"!"
};

/*eject*/
char *help11[26] = {
" ",
"                  ** H11. write records to $UVTMPDIR/... ** ",
" ",
">>> write - write data records only for later use (test files,etc)",
"          - write output is written to $UVTMPDIR/filename.yymmddhhmmW",
"          - multiple write command outputs collected into 1 common file",
"          - writes start at current position & end at EOF (or max count)",
"w5              - write (unformatted) 5 records from current position",
"w ' SMITH '     - write records with ' SMITH ' anywhere in record",
"w5 0(3),>'400'  - write 5 max records whose 1st 3 bytes > 400 ",
"ww              - repeat last write command (from current position)",
"w 77(2),'BC'    - select province BC in bytes 77-78 (zero relative)",
"w 0(1),'2',0(64),'ABC' - write recs with '2' byte 0 & ABC anywhere in 0-64",
"wi     - write entire file, dropping ISAM deleted records",
"         (option 'i' drops records with x'00' in last byte)",
" ",
"we10            - write every 10th record (to make smaller test file ?)",
"w100e5          - write 100 records, select every 5th (file must have 500+)",
"we10 77(2),'VA' - write every 10th rec with state = 'VA' (from here to EOF)",
" ",
"w100r64t2 - sample Write command to Write next 100 records with options",
"          - r64=fixedsize 64 byte recs, t2=terminate with LF in last byte",
"w99z2a1c1 - write next 99 recs in RDWz2 format (recsize in 2 byte prefix)",
"          - translate to ASCII, translate any unprintable chars to periods",
"          - see write options on next help screen",
"!"
};

char *help12[26] = {
" ",
"                      ** H12. Write options **",
" ",
"a1   - translate to ASCII, write command output records",
"d#   - displacement to 1st byte to be written",
"c1   - convert unprintable chars in write output records to periods",
"n1   - insert variable recsize as 4 numerics at BEGIN write output",
"n2   - insert variable recsize as 4 numerics at END write output",
"r#   - record size for fixed-length output, omit for RDWz2/z4",
"t1   - insert Carriage-Return at end write records (for MAC)",
"t2   - insert Line-Feed at end of write records (for Unix/Linux)",
"t3   - insert both CR & LF at end write records (for some Windows programs)",
"t4   - insert after Last-Non-Blank, else at end recsize (t6 for LF)",
"z#   - write RDW format (2 or 4 byte prefixes with recsize in binary)",
"z2   - prefix 2 bytes only, recsize EXCLUDES prefix size",
"z4   - prefix 4 bytes, recsize 1st 2, 3&4 nulls, recsize INCLUDES prefix",
"z1   - (add 1 bit) = z3/z5 Little-end binary, z2/z4 default BIG-end binary",
" ",
"w50d10r25t6 - Write next 50 records, option d10=dsplcmnt to 1st byte to write",
"            - r25=recsize to write, t6=terminate LF after last nonblank",
"            - writes just customer name field of demo file dat1/custmas1",
" ",
"lw  <-- may follow write command with 'lw' command to close file for separate",
"        output files or omit for combined outputs from multi write commands",
" ",
"!" };

/*eject*/
char *help13[28] = {
" ",
"          ** H13. sequence check & tally (count records) **",
" ",
">>> check  - check sequence in specified field - until EOF or SEQUENCE ERR",
"c  0(6)    - check sequence in columns 1-6, show 1st record out of sequence",
"cd 0(6)    - check sequence descending (vs ascending default)",
"ce 0(6)    - check seq equal not allowed (may use with ascending/descending)",
"cc         - repeat last sequence check (from current position to EOF)",
" ",
">>> tally - count records from current point to EOF",
"t                - count records from current position to EOF",
"t 'ABC'          - count records with 'ABC' anywhere in record",
"t500 10(3),'ABC' - count (within next 500 recs) recs with ABC in cols 11-13",
" ",
"t 10(1),'A',77(2),'BC' - count records with 'A' col 11 AND 'BC' col 78-79",
"t 8(1),'D',|8(1),'X'   - count records with 'D' OR  'X' col 9",
"t 0(1),>'2',0(1),<'7'  - count records with 1st byte 3,4,5,or 6",
"t 0(1),>'2',,<'7'      - same op3 omitted (,,) defaults same as op1",
" ",
"ts 'ABC'    - count records with 'ABC' anywhere in record",
" s        <-- note option 's' on 'ts' saves tally args in search args",
"1             for subsequent reset to BOF (by goto record #1)",
"ss          - and 'ss' to review selected records (w/o re-entering arguments)",
" ",
"!"
};

/*eject*/
char *help14[26] = {
" ",
"                    ** H14. Verify data fields **",
" ",
"v99  - verify Packed,Numeric,Character fields to EOF (99 short for 999999999)",
"     - will display 1st record found with bad data",
"     - shows packed fields in hexadecimal, with <-BadP note",
"     - replaces unprintable chars with '.'s & flags <--BadC or <--BadN",
"     - might print record for further investigation",
"vv   - enter 'vv' to advance to next record & continue search/verify",
"v100 - verify next 100 records vs until EOF (indicated by v99)",
" ",
"...x  - option 'x' no-stop-on-error, count for display at EOF (or max# spcfd)",
"v99x1 - nostop on errors in numeric fields",
"v99x2 - nostop on errors in packed fields",
"v99x4 - nostop on errors in character (pic x) fields",
"v99x3 - nostop on errors in numeric + packed fields",
"v99x7 - nostop on errors in numeric + packed + character fields",
" ",
"...y  - option 'y' specify valid signs for numeric fields",
"v99y1 - Micro Focus COBOL negatives: -0123456789=pqrstuvwxy x'70' zones",
"v99y2 - EBCDIC signs: +0123456789={ABCDEFGHI, -0123456789=}JKLMNOPQR",
"v99y4 - separate +/- signs (leading or trailing)",
"   y1 - default y1 if input file is ASCII (default)",
"   y2 - default y2 if input file is EBCDIC (option 'a' on command line)",
" ",
"!"
};

char *help15[28] = {
" ",
"                    ** H15. Verify (continued) **",
" ",
"uvhdcob dat1/sales0 cobol/maps/sales r64a  <-- sales0 is EBCDIC (option'a')",
"=========================================    - recsize 64 (option 'r64')",
"v99y2 - verify numeric fields with EBCDIC signs",
"      - no need to specify option 'y2', will default when input file EBCDIC",
"        (overriding default 'y1' when input file ASCII)",
" ",
"...z - option 'z' correct blank numeric/packed,& pic x with unprintable chars",
"v99z1 - convert any all blank numeric fields to numeric zeros",
"v99z2 - convert any all blank packed fields to packed zeros with x'_C' sign",
"v99z4 - convert any any unprintable characters in pic x fields to '.' periods",
"v99z7 - all of above",
" ",
"   abcdef - options to inhibit verify in 3 areas ID by offset from/to",
"v99a120b239 - inhibit verify in all fields from dsplcmnt 120 to 239",
"            - to bypass known bad fields (to search for unknown bad fields)",
"v99a100b120c200d220e300f320 - inhibit verify in 3 record areas max",
" ",
"v99x7p99 - verify all records (v99) with option x7 for nostop (count only)",
"         - option 'p99' prints all errs to $UVTMPDIR/filename_yymmdd_hhmmssVP",
"         - option 'w99' writes all errs to $UVTMPDIR/filename_yymmdd_hhmmssVW",
"         - may follow with lvp/lvw to close files or omit to combine outputs",
" ",
"!"
};

/*eject*/
char *help16[28] = {
" ",
"               ** H16. Move character & move Numeric **",
" ",
"uvhdcob dat1/custmas1 cobol/maps/custmas1 r256u <-- must specify option 'u'",
"==============================================*     on command line",
" ",
"m 35(12),90       <-- Move character (m), omit op2 lth assumes same as op1",
"m 35(30),90(12)   <-- move 90-101 to 35-46, 47-64 extra op1 length blanked",
"n 64(9z),120(5p)  <-- move Numeric (n), unpacks 5 bytes into 9 bytes Zoned",
"n 130(5p),64(9z)  <-- move Numeric (n), 9 zoned bytes to 5 packed bytes)",
"n 51(4b),120(5p)  <-- move Numeric, 5 bytes packed to 4 bytes binary",
"n 140(5p),123456  <-- move Numeric value (length omitted) to 5 bytes packed",
"n 64(9ze),120(5p) <-- move Numeric, unpacks 5 bytes into 9 bytes Zoned EBCDIC",
"                  - data type codes z/p/b (z default) 1st alpha after length",
"                  - Ascii/Ebcdic codes a/e (a default) 2nd alpha after length",
" ",
"n 120(5p),0,,77(2),='BC' <-- clear 5 bytes packed (move 0) if province 'BC'",
"                           - conditional moves via qualifiers in op3-op6",
"n99 120(5p),0 <-- clear this yr Jan sales in all records (99 means 999999999)",
"                - use m99/n99 to move on all records until EOF reached",
"x             <-- use 'x/X' to rollback (only for moves on 1 record)",
"!"
};

char *help17[28] = {
" ",
"                  ** H17. Move Application **",
" ",
"Move Example - create Telephone-List from custmas1 demo file (layout follows)",
"00-05 cust, 10-34 cust-name, 35-89 address, 90-91 tel#, 120-240 packed fields",
"desired: move tel# after cust-name, blank fill,& write 64 byte text records",
"             - see this example illustrated at www.uvsoftware.ca/uvhd.htm#4K1",
" ",
"cp dat1/custmas1 tmp/cm1  <-- 1st copy custmas1, rename (not final output)",
"========================",
" ",
"uvhdcob tmp/cm1 cobol/maps/custmas1 r256u <-- specify option 'u'",
"========================================*",
" ",
"m99 35(30),90(12)         <-- Move tel# after cust-name & blank to 64",
"==================          - on all records (99 short for 999999999)",
" ",
"w99r64t6                  <-- Write, max Recsize 64, Textfile option 't6'",
"=========                   - t6 appends LF after last nonblank",
" ",
"cp tmp/cm1_yymmdd_hhmmssW dat1/tellist <-- copy/rename date_time_stamped",
"======================================     tmp file output as desired",
" ",
"!"
};

/*eject*/
char *help18[26] = {
" ",
"             ** H18. Exit to uvhd & return to uvhdcob **",
" ",
">>>Exit - exit to uvhd, to display data record without COBOL fieldnames",
"     - to see fields longer than 36 bytes",
"     - or all occurrences of occurs (uvhdcob can do, but more lines)",
" ",
"e    - exit to uvhd (to display entire record w/o fieldnames)",
"     - will display same record",
"eu   - may specify options (eg: u=update)",
"q    - quit (in uvhd) returns you to uvhdcob",
" ",
" ",
"           ** lw/lp/lvw/lvp separate or combined write/print files **",
" ",
"lw  <-- may follow write command with 'lw' command to close file for separate",
"        output files or omit for combined outputs from multi write commands",
"lp  <-- similar command close print files for separate or omit for combined",
"lvw <-- similar command close verify writes for separate or omit for combined",
"lvp <-- similar command close verify prints for separate or omit for combined",
" ",
"!"
};

char *help19[26] = {
" ",
"             ** H19. Occurs display & Inhibit 0/b fields **",
" ",
"o1   - display only 1st of Item occurs (default)",
"     - Item occurs on same line as pic (vs Group occurs)",
"o99  - display all Item occurs (as specified in copybook/map)",
"o3   - display only 1st 3 fields of Item occurs",
" ",
"g1   - display only 1st of Group occurs (default)",
"g99  - display all Group occurs (as specified in copybook/map)",
"g3   - display only 1st 3 fields of Group occurs",
" ",
"               ** set Inhibit zero/blank fields **",
" ",
"i1   - Inhibit display zero/blank fields of Item occurs",
"i2   - Inhibit display zero/blank fields of Group occurs",
"i4   - Inhibit display all zero/blank fields (includes Item/Group occurs)",
"i4   - use option 'i4' to see only significant fields of large records",
"     - dropping zero/blank fields to see more info on each screen",
" ",
"o5i1 - may specify 0/b display inhibit options on 'o' or 'g' commands",
"o5g5i3 - may specify occurs & inhibit display options on uvhdcob command line",
"!"
};

/*eject*/
char *help20[28] = {
" ",
"                 ** H20. Multi Record *TYPE files **",
" ",
"cobmap may specify record types on *TYPE comment lines, for example:",
"*TYPE=0(1),=C'P','PAY-RECORD'  <-- 'P' 1st byte displays pay-record fields",
"*TYPE=0(1),='T','TIME-RECORD'  <-- 'T' 1st byte displays time-record fields",
"*TYPE=0(1),='H','HDR-RECORD'   <-- 'H' 1st byte displays hdr-record fields",
"*TYPE=0(1),!'H','HDR-RECORD'   <-- last entry !not= for EOF display short rec",
"*TYPE=0(1),=X'FF','HEX-RECORD' <-- may code TYPE as HEX constant",
" ", 
"*TYPE - starts display with 1st cobmap fieldname matching fieldname ",
"      - insert *TYPE control records at begin copybook with redefined records",
"      - then rerun cobmap1 to convert copybooks to cobmap record layouts",
"      - do not insert in cobmaps (would be lost when cobmap1 rerun)", 
"      - see details at www.uvsoftware.ca/uvhdcob.htm#J1 - J2",
" ",
"             ** Alternate TYPE format for variable length records **",
" ",
"*TYPE=0:45,'VEN-NAME' <-- Alt format for variable length (RDW,IDXf3/8,text)",
"                        - identify type by record size range",
"*TYPE=46:99,'VEN-PAY' <-- ven-pay layout if size 46:99, ven-name if 0:45",
" ",
"!" };

char *help21[28] = {
" ",
"                  ** H21. Index file saved for re-use **",
" ",
"uvhdcob dat1/vendormas3 cobol/maps/vendormas z4  <-- demo uvhd RDW testfile",
"===============================================",
"vi $UVTMPDIR/uvhdindex_vendormas3 <-- investigate saved Index file",
"=================================   - sample Index save file listed below",
" ",
"#01:uvhdindex_vendormas3",
"#02:filesize=249,options=z4",
"#03:IndexCreated=110429_075017,BuildTimeSeconds=0",
"#04:BDWmin=0,BDWmax=0,BDWavg=0,Blocks=0",
"#05:RCSZmin=23,RCSZmax=45,RCSZavg=31,Records=8",
"#06:1=0,2=23,3=53,4=98,5=129,6=158,7=185,8=219,8=249,",
" ",
"- uvhd builds an Index file of file-pointers & record-numbers on startup",
"- saved to $UVTMPDIR/uvhdindex_...filename... to reload & save rebuilding",
"  the next time uvhd used on same filename with same filesize",
"- saved Index file contains statistics that may be useful to you",
"- contains 100 entries of rec#=fileptr (files < 100 records shows all rec#s)",
" ",
"!" };

char *help22[26] = {
" ------------------------- H22. ---------------------",
"                           unused  ",
" ",
"!"
};

/*Jan10/11 - version date for screen/print headings */
char uvversion[16] = "20111202";

/*eject*/
/*uvhdcob-------------------- LargeFile support ------------------------*/
/*May2001 - test largefile -DLF64 set in compile script                 */
/*        - tested on unixware 7.1.1, see intro(2) describes 2 methods  */
/* method#1 _FILE_OFFSET_BITS=64   <-- excludes method#2 ??             */
/* method#2 _LARGEFILE_SOURCE 1  + explicit calls open64 lseek64        */

#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS 64
#define __USE_LARGEFILE64 1

/*Dec08/07 - above used for other uv programs, check folwng Nov2004 cmt?*/
/*Nov2004 - RedHat Linux uses __USE_LARGEFILE64 ????? */
/*Dec2007 - adding __USE_LARGEFILE64 also ?? */
/*Dec08/07 - LF64 always defined for Linux */
/*Dec02/11 - enable LF64 always (OK for MinGW, don't disable by !DWIN) */
#define LF64 1

/*uvhdcob----------------- includes & defines ------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <unistd.h>

/*eject*/
/*Dec07/07 - for lcc-win32, use _stati64 */
/*May18/08 - problems on Windows for 64 bit lseeki64  */
/* - tf/tabtest1 text files seek problem, reads 256 ? */
/* - stuck at EOF, r1 does not return to BOF          */
/* So - LF64 NOT defined on DWIN (see above)          */
/*    - use stat vs stati64 on DWIN (below)           */

/*Oct05/11 - IBM Mexico compile problems on HP Itanium stat64 missing */
/* - moved #includes prior to struct stat64 fstat1 (unlikely to fix)  */
/* BUT, then got stat64 undefined                                     */
/* - fixed by moving the LARGEFILE defines ahead of the #includes ?   */

#if defined(DWIN)
#if defined(LF64)
struct _stati64 fstat1;
char uvlargef[16] = "LF64W";
#else
struct stat fstat1;
char uvlargef[16] = "LF32";
#endif

#else /* not DWIN */
struct stat64 fstat1;
char uvlargef[16] = "LF64";
#endif

/*eject*/
/* #include "UVtyp.h" - def's common to Vancouver utility C programs     */
/* - most Vancouver Utility prgms #include UVtyp.h header file           */
/*   but typdefs included in uvhd.c self-contained for internet freeware */

typedef int UVi32;
typedef unsigned char Uchar;
typedef unsigned int  intU;


/*Jul23/07 - chg compile script I64 to H64,S64,S32 (H64 to set PTR64) */
/*         - H64,S64 set I64 for 64 bit counters                      */
/*Dec05/07 - above chg in July was missed for uvhd until Dec05/07     */
/*Dec08/07 - H64/S64/H32 changed to L32/L64 + P64/P32                 */
/*Jan12/08 - compile scripts changed, L32/L64&P32/P64 combined to H32/H64*/
/* - always set I64 64 bit acums (long if H64, else long long assumed)*/
#define I64 1

/*Feb24/11 - define H64 always (all machines now 64 bits) */
/*Oct05/11 - remove hardcoded #define H64, for Mexico test -DH32 long long */
/* #define H64 1   <--- commented out Oct05/11 */

#if defined(H32)
char longbits[12] = "longlong64";
char H32H64[8] = "H32 ";
#else
char longbits[8] = "long64";
char H32H64[8] = "H64 ";
#define PTR64 1
#endif

/* define UVI64: 64 bit long if -DH64, else long long */
#if defined(H64)
typedef long UVi64;
#else
typedef long long UVi64;
#endif

#if defined(H64)
char E64[8] = "%ld";      /*Mar05/08 chg %lld to %ld */
#else
char E64[8] = "%lld";     /*Mar05/08 chg %d to %lld  */
#endif

/*Oct08/11 - restore E64 printf %ld or %lld long/longlong 32bit HP gcc   */
char fpedit1[20];        /* fileptr edited by E64 %ld/%lld long/longlong */
char fpedit2[20];        /* fileptr or record dsplcmnt on 2nd+ segments  */
char fsedit[20];         /* filesize edited by E64 %ld/%lld long/longlong*/
char fpedit1e[20];       /* fileptr to last record in file %ld/%lld      */

/*eject*/
/* capture machine type from compile script manifest define       */
/* also define BEM (Big End Machines) vs LEM (Little End Machines)*/
#if defined(SCO)
#define LEM 1
char machine[8] = "SCO";
#elif defined(INT)
#define LEM 1
char machine[8] = "INT";
#elif defined(HP)
char machine[8] = "HP";
#define BEM 1
#elif defined(SUN)
char machine[8] = "SUN";
#define BEM 1
#elif defined(AIX)
char machine[8] = "AIX";
#define BEM 1
#elif defined(DEC)
char machine[8] = "DEC";
#define BEM 1
#elif defined(LNX)
#define LEM 1
char machine[8] = "LNX";
#elif defined(UWIN)           /* UWIN or CYGWIN under windows */
#define LEM 1
char machine[8] = "UWIN";
#elif defined(CWIN)           /* UWIN or CYGWIN under windows */
#define LEM 1
char machine[8] = "CWIN";
#elif defined(SFU)            /* SFU under windows */
#define LEM 1
char machine[8] = "SFU";
#else 
#define LEM 1
char machine[8] = "XXX";
#endif

#if (BEM)
#define LEM 0
#endif
#if (LEM)
#define BEM 0
#endif

/*Jan2004 - replace compound machine type tests with 1 simple test   */
/* #if defined (INT) || defined (LNX)  <-- I sometimes forgot LNX    */

/*Dec07/10 - allow for EDEADLOCK not defined on some systems */
/*         - in /usr/include/sys/errno.h                     */
#ifndef EDEADLOCK
#define EDEADLOCK EDEADLK
#endif

/* misc work areas */
char w1[256];
char w2[256];

/*eject*/
/*uvhdcob----------------- defines,etc ------------------------------*/
#define RMAX  32768         /* maximum record size                   */
/*Aug22/11 - increase RMAX from 16384 to 32768                       */
#define RDFLT 256           /* default rcsz - if no option 'r'       */
#define LMAX  64            /* maximum line size                     */
#define LDFLT 64            /* default line size - if no option 'l'  */

#define MAPMAX 2000         /* max recs in cobmap file & maprec maptbl*/
#define TYPMAX 200          /* max *TYPEs in cobmap file & typtbl    */

time_t tmsecs;              /* unix time - seconds since 1970        */
char today[16];             /* todays date "yyyymmddhhmm"            */
char todttm[16];            /* todays date "yyyymm:ddhh"             */
char date6[8];              /* date in 6 digits                      */
char time6[8];              /* time in 6 digits                      */

/*------------------- MSDOS/unix dependent defs ---------------------*/
#if MSDOS
char slashc = '\\';
char slashs[2] = "\\";
#else
char slashc = '/';
char slashs[2] = "/";
#endif

/*--------------------- option storage ------------------------------*/
char opsu[40];              /* options from cmnd line                */
char opsc[28];              /* option characters                     */
                            /* sorted into alpha position            */
int opsi[28];               /* option parameter integer storage      */
                            /* opsp numerics cnvrtd by atoi          */
char *opsp[28];             /* option string pointers                */
char  opsb[256];            /* buffer for option string data         */

/*------------------ execute 1 cmd & quit option --------------------*/
/*ex: uvhdcob file cobmap x=p99999999    <-- print all recs & quit   */
/*                                           to tmp/file:HHMMSSP     */

char cmd1s[64];             /* command from option x=string          */

int cmd1x;                /* switch to control 1 time & quit       */


/*eject*/
/*uvhdcob---------------- file access vital w/s ----------------------*/

char recb[RMAX+8];      /* record base area                            */

char *recd;              /* ptr to record data, stored at prgm init    */
                         /* for fixed recs recd = recb                 */
                         /* for variable(MF or RDW) = recb +2 or +4    */

char *irecd = recb;      /* record data same as record base for uvhd   */
                         /* uvhdcob offsets by IDX or RDW prefixes     */

char recda[256];         /* record data for rec type testing           */
                         /* - trnsltd to ASCII if EBCDIC input         */

/*Jan28/09 - allow rec type testing for EBCDIC input */
/* - will copy 1st 256 of recd to recda      */
/*   & translate to ASCII if input is EBCDIC */

/* provide *deleted* flag (vs fieldname in record header)              */
/* - if ISAM file & last byte of rcsz = x'00' (vs x'0A')               */
char fldname[10] = "fieldname";
char delflag[10] = "*deleted*";
char fnmflag[10] = "         ";

/*------------------------ exit command to uvhd ------------------------*/

char exitcmd[128];           /* build area for exit command (to uvhd)   */

/* builds command: uvhd datafilename r#[options]                        */
/*                 ====================                                 */

/*-------------------------- getcbuf buffer ----------------------------*/
/* for getcbuf subfunction - get 1 byte at a time from a text file      */
/* - returns 1 character (unsigned) or EOF (-1) at end of file          */
/* - buffered by reading 8000 bytes at begin program                    */
/* - buffer refilled when empty                                         */

char bufa[RMAX];         /* buffer read area            */
char *bufp = bufa;       /* buffer pointer to next char */
int bufn = 0;            /* buffer bytes remaining      */

/*eject*/
/*uvhdcob---------------- file access vital w/s ----------------------*/
/* May2001 - change fopen,fread,fseek,fwrite to open,read,lseek,write */
/*         - because there is no fseek64                              */
/* - will use: open64, lseek64, stat64 for Large Files (> 2 gig)      */
/* - will still use fopen,fwrite for output files (print,write,etc)   */

char fn1[180];          /* filename from prmtr1 of cmnd line          */
char fn1b[128];         /* base filename (after last '/')             */
char fmdate[16];        /* file modifiction date "yyyymmddhhmm"       */
int openflags;          /* fileopen flags default O_RDONLY (0)        */
                        /* changed to O_RDWR (2) by option u (update) */
                        /* see subfunc fileopen()                     */
char fn1x[128];         /* filename suffix '.dat' adds 1 to mapsize   */

/*Jan29/09 - getting seek errs because of bad file descriptor ?        */
/*         - suround with know values so we can check memory clobber ? */
int fd0 = 1;
int fd1save;             /* file dscrptr backup saved after open       */
                         /* fileseek will restore fd1 if not same      */
int fd1;                 /* file descriptor from open (May 2001)       */
int fd2 = 2;

int flwait1;                /*Dec07/10 file lock wait acumulator       */
int lockstat;               /* setlock return status 0/1 not/locked    */

char linr[LMAX+40];      /* record segment extracted from record       */
                         /* - for display on 3 vertical hex lines:     */

Uchar linc[LMAX+40];     /* line 1 - char with ctlchars cnvrtd to '.'s      */
Uchar linp[LMAX+40];     /* line 1 - smso/rmso codes inserted for search pat*/
char linz[LMAX+40];      /* line 2 - zones for vertical hex display         */
char lind[LMAX+40];      /* line 3 - digits for vertical hex display        */

UVi64 filesize;          /* end of file fileptr (via stat)             */
UVi64 filesiz0;          /* filesize evenly divisible by rcsz (but <)  */
UVi64 filextra;          /* partial record at EOF (fsize % rsize)      */
int filextra2;           /* (fsize % rsize) for sprintf %d stop warning*/

/*uvhdcob------------------ current fileptr ---------------------------*/
UVi64 fileptr;        /* new file position                             */
                      /* modified by user commands for byte# or rec#   */
                      /* never allowed < 0 or > filesize               */
UVi64 fileptrp;       /* fileptr from previous getrec()                */
UVi64 fileptr1;       /* ptr to last record in file fsz1-rszo (fixlth) */
                      /* stored when index built for varlth(RDW,text,IDX)*/
char fileptr1s[20];   /* used by findexload, store info from findexsave*/
                      
UVi64 fpsv;           /* save file position                            */
int   rnsv;           /* save record number                            */
                      /* used to show last rec updated, written, etc   */
UVi64 fileptrp;       /* previous file ptr saved before get            */

/*eject*/
int recnum1;          /* recnum1 for display/print (1 relative)        */
                      /* fixed size - recum + 1                        */
                      /* text/variable - increment on get              */
                      /*               - reset to 1 when fileptr reset */

int recnum1o;         /* recnum1 % option 'o' display scale every # recs*/

UVi64 frecsc;         /* records calculated (filesize/rcsz)         */
char rcounts[16];     /* rcount string from rec#05 on Index reload  */
int rcount;           /* total records for screen headings          */
int rcountx;          /* set at EOF in findrec() for varlth files   */
int eof1;             /* count times reached EOF                    */
                      /* > 1 inhibits subsequent changes in rcount  */

int rsz1p;            /*May25/10 Prior Record Size - saved at end getrec()*/
                      /* - used to incrmnt fileptr at begin next getrec*/
                      /* - for variable lth recs (not fixed)           */

int rsz2p;            /*Nov21/10 - recsize 2 recs back for -1 varlth   */

int upnext;           /*May25/10 - switch control fileptr update in getrec*/
                      /* - set off at begin prgm & by reposition r#/b#    */
                      /* - set on at end of getrec assuming browse follows*/

int remndr;            /* remainder filesize % recsize for errmsg    */

int rszo;              /* record size from option r or RDFLT         */
int rszox;             /* recsize option r/RDFLT +eXtra 256          */
int rszoy;             /* recsize option r/RDFLT +eXtra 128          */
char rszop[12];        /* rcsz as option r# (pass to uvhd on exit cmd)*/

int rszmap;            /* record size from copybook map              */

int lszo;              /* line size from optn l or dflt to LDFLT     */

/*eject*/
int rsz1;             /* current recsize -  returned by getrec()       */

int rsz1d;            /* actual data size - depending on file type     */
                      /* (rsz1 - hdr size of RDW or IDX files)         */

int rsz2;             /* record size for current command calcs         */
                      /* - to calc prt from rec#                       */
                      /* fixed files - use rszo from r optn on cmd line*/
                      /* text files - use last rsz1                    */

int lsz1;             /* current line size                             */

int rii;              /* record index to current byte in record        */
UVi64 rii1;           /* record index b4 current line segment          */
int lii;              /* line   index to current byte in line          */

int screenctr;        /* screen ctr for current record                 */

int linectr;          /* line ctr on current screen                    */
                      /* depending on hex, char only, space 1/2        */

int linemax;          /* max line count per screen option m            */

int xchar;            /* indicator 0/1 print current record in hex     */
                      /* 1 if any < 0x20 or > 0x7E                     */
                      /* But allow hex chars in last 2 bytes of record */
                      /* - to allow LF in last byte or CR/LF last2     */
                      /* also depends on option 'h'                    */
                      /* h0=auto determine, h1=chars only, h2=force hex*/

char firstop[12];     /* option f# for first rec to be displayed       */

int rpsctr;           /* records per screen - for option n              */
                      /* used only on null reply when browsing          */
UVi64 fileptro1;      /* fileptr saved from 1st on screen               */
                      /* restored on cmds other than browse, rec#, byte#*/

char opmsg1[128];     /* operator msg, stored by subrtns       */
char opmsg2[128];     /* operator msg2, stored by subrtns      */
char opmsg3[128];     /* operator msg3, stored by subrtns      */
                      /* for display after current screen      */

/*May28/11 - search progress message interval option p default 1 million */
int pmsgcnt;          /* option p default 1000K (1 million) */
int pmsgctr;          /* counter up to option p for msg     */

int rcsmax;              /* recsize parse check max op for search,etc  */
                         /* rszo if Fixed, else rdwmax May28/11        */
char rdwmaxs[20]; /* capture from RCSmax= for atol() */

/*eject*/
/*Jan25/09 - fields recovered from uvhd.c or uvhdcob.old */

char fn1i[128];         /* filename.idx to test for presence          */

struct stat fs1;        /* file status structure                      */
                        /* to get file size & modifctn date           */

struct stat fs1i;       /* file status for .idx partition (if any)    */
                        /* if present, will add 1 to data rcsz        */

/*Nov11/07 - filetype code f,t,v,x,z to simplify tests */
/* - set by options t,v,x,z, else default to f         */
char ftype = '?';

/*Feb2003 -  control codes to highlight found search patterns             */
char smso[16] = "\x1B\x5B\x37\x6D"; /* start bold standout mode           */
char rmso[16] = "\x1B\x5B\x6D";     /*  end  bold standout mode           */
int smsol;                          /* lth of smso calculated at prgm init*/
int rmsol;                          /* lth of rmso calculated at prgm init*/

/*Mar18/03 - warning message areas for printRV (reverse video)        */
char warnmsg1[100];
char warnmsg2[100];

/*eject*/
/*uvhdcob------------------ cobmap file access ---------------------------*/

char runlibs[128];            /* $RUNLIBS value from getenv           */
char fn2a[128];               /* filename from arg2 on cmd line       */
char fn2b[128];               /* filename $RUNLIBS/arg2               */
char fn2c[128];               /* filename $RUNLIBS/maps/arg2          */
char fn2d[128];               /* filename selected                    */

struct stat fn2astat;          /* test arg2 file present               */
struct stat fn2bstat;         /* test $RUNLIBS/arg2 file present      */
struct stat fn2cstat;         /* test $RUNLIBS/maps/arg2 file present */

FILE *fp2;                    /* file ptr for cobmap                  */

char maprec[128];             /* cobmap read area                     */

/*uvhdcob-------------- cobmap field data retrieval ----------------------*/
/* current cobmap field data retrieval work areas                         */
/* - data extracted from current rec depending on cobmap field bgn/lth/typ*/

char fdat1[64];            /* current field data retrieval from record    */

char fdat2[64];            /* current field for display char or hex       */

char fdat2b[64];           /* bold start/stop around data if search match */

char fdat3[64];            /* current field with decimal value aon right  */
                           /* - for binary 2,4,or 8 byte fields           */

/*Feb25/11 - show hex for bad fields > 9 bytes on 2nd line                */
char fdat4[64]; 

int flth1;                 /* field length for retrieval max 32 (16 if hex)*/

int flth2;                 /* field length for display max 32              */

char zlth[8];              /* zero sup length (4 bytes) zzz9               */
char zbgn[8];              /* zero sup begin  dsplcmnt (4 bytes) zzz9      */
char zend[8];              /* zero sup end    dsplcmnt (4 bytes) zzz9      */

/*eject*/
/*Dec27/10 - add option to show occurs o1 deflt, o2 all, o4 1st or 1st err */
int ooii;        /* occurs index 00 --> occurs value            */
int ooff;        /* occurs offset = (occurs index * field-lth)  */
int oonn;        /* occurs value from cobmap                    */
int ooee;        /* occurs end print index, oonn or 1 of optn o1*/
int oozz;        /* occurs end dsplcmnt (begin + (occurs*lth)   */
int ooni;        /* edit item occurs oonn or ooii+1             */

/*Aug03/11 - add control fields for GROUP OCCURS         */
/*Sep25/11 - collect group occurs info into a structure  */
/* - in prep for adding group occurs nested levels       */
struct GOC
{ int max;    /* group occurs max (to) count             */
  int ctr;    /* group occurs counter                    */
  int lth;    /* group occurs total length each group    */
  int nest;   /* group occurs nest level 1 or 2(max)     */
  int end;    /* group occurs end count from option 'g'  */
  int odo1;   /* edit group occurs goc1.max or goc1.ctr+1*/
  int max1;   /* save orig goc1.max to edit odo 1        */
  int off;    /* group occurs offset to current set (goc1.lth*goc1.ctr) */
  int mti;    /* index to current *BGNOCCURS in maptbl*/
};

struct GOC goc1;   /* group occurs control level 1 */
struct GOC goc2;   /* group occurs control level 2 */
struct GOC goc0;   /* zero structure to clear goc1/goc2 */

/*Sep27/11 - goctoff = goc1.off + goc2.off */
int goctoff;

/*Aug25/11 - *BGNOCCURS modified to add depending on field start,length,type*/
/*          1         2         3         4         5         6         7   */
/*01234567890123456789012345678901234567890123456789012345678901234567890   */
/**BGNOCCURSM:c-p:00024*00010=00240:00010-00249:1:00008:02pns               */
int  godpl2;     /* dpo field lth retrieved from maptbl           */
char godpc[12];  /* depending on count field retrieved here       */
int  godpb;      /* packed/binary/numeric covnerted to binary int */
short godpb2;    /* retrieve short & switch ends if LEM           */

/*Aug26/11 - allow for multiple occurs depending on */
/* record field dsplcmnt correction required if dpo occurs < max(occurs to) */
int goffcor1;    /* dpo correction for current dpo (calc at *ENDOCCURS) */
int goffcor2;    /* total dpo correction acum from ultiple dpo's        */
int recdoff;     /* current field record offset total */
int recdend;     /* test current field end = end of record Sep02/11*/

/*Aug13/11 - use option i for inhibit show 0/b flds, will use LEM */
/* - chg occurs optn 'v' to optn 'i', allow cmd 'i' to set optn 'i' */
/*           i1 = item occurs, i2 = group occurs, i4 = all fields */
/* - previously used separate options ooioptn, goioptn, allioptn */

int sigval;      /* significant value indicator */
                 /* returned by testnp/nb/nn/nc inhibit display zero/blank */
                 /* occurs fields after 1st if option v1+ on o/g command */

/*eject*/
/* uvhdcob------------- cobmap layout (Jan2002+) ------------------------*/
/* 000(60) - cobol text (original cols 7-66)                             */
/* 060(05) - field start byte (5 bytes, zup on 1st)                      */
/* 065(05) - field end byte   (5 bytes, zup on 1st)                      */
/* 070(05) - field length bytes (5 bytes, zup on 1st 2)                  */
/* 075(01) - field type (p=packed, b=binary, blank=alphanum)             */
/* 076(01) - field type (n=numeric, blank=alphanum)                      */
/* 077(01) - field type (s=signed, blank=alphanum)                       */
/* 078(02) - field length digits (2 bytes, zup on 1st)                   */

/* structure for cobmap records - to be tabled                          */
/*Nov21/10 - allow hex constants on cobmap *TYPE=0(1),=X'FF' (tc below) */
struct MAPREC
{ char lvl[4];                /* field level# 01-99                   */
  char fnm[32];               /* field name                           */
  char typ[16];               /* field type (p/b/_,n/x,s/_)           */
  char cc[4];                 /* condition code =!<> for *TYPE test   */
  char tc[4];                 /* Type Code allow 'X' hex dflt 'C' char*/
  int lth;                    /* field lth (binary)                   */
  int bgn;                    /* field begin dsplcmnt                 */
  int end;                    /* field end dsplcmnt                   */
  int occurs;                 /*Dec27/10 occurs value                 */
  int mtibgntyp;              /* mti cobmap index for R/T bgn display */
  int mtiendtyp;              /* mti cobmap index for R/T end display */
  int gocmax;                 /*Aug03/11 group occurs max/to count    */
  int goclth;                 /*         group occurs total set length*/
  int gocnest;                /*Sep26/11 grp occurs nest level 1/2    */ 
  int godps;                  /* depending on start from *BGNOCCURS   */
  int godpl;                  /* depending on length                  */
  char godpt[4];              /* depending on type p/b/n              */
  char des[68];               /* dscrptn (pic,occurs,etc)             */
  char rdf;                   /* 'r' = redefined field                */
  char ext[3];                /* multiple of 8                        */
};

/*uvhdcob------------------ cobmap table -----------------------------*/
/* cobmap storage - table of MAPREC structures                        */
struct MAPREC maptbl[MAPMAX]; /* storage for cobmap file records      */

struct MAPREC maprw;          /* MAPREC work record                   */
                              /* cobmap rec reformatted here          */
                              /* before storing in maptbl             */
struct MAPREC maprz;          /* MAPREC zero record for clearing maptw*/

/*eject*/
/* maprec table index & controls */
int mti;                      /* index for maptbl                     */
int mtimax;                   /* cobmap table entry count             */

int mtibgn;                   /* mti cobmap index for bgn display     */
                              /*     = 0 if no types present          */
int mtiend;                   /* mti cobmap index for end display     */
                              /*     = mtimax if no types present     */

/* mtibgn/mtiend control fields to be displayed for Record/Types      */
/* when cobmap table loaded, table index of fieldnames matching type  */
/* - is stored in the mtibgntyp field of the type table entry         */
/* when record are read & matched to the type table,                  */
/* - the mtibgntyp index is stored for the 1st field to be displayed  */
/* - the mtiendtyp index is stored for the last field to be displayed */

int mtir;          /* index for record(redef)field display*/
int mtib;          /* index for record base field display */
int mtir1dsp;      /* dsp of 1st field in current R/TYPE  */

int mtiri;         /* 0/1 for delayed incrmnt mtir        */
int mtibi;         /* 0/1 for delayed incrmnt mtib        */
/* above fields control field display for redef recs *type defs present*/
/* - to allow for redef recs that do not redefine entire record        */
/* - to show the record base(key) fields not in the redef fields       */
/* - will display fields from record base until we reach dsp => mtir1dsp*/
/*Aug13/11 - remove code to display base fields to partial redef records  */
/* - see old solution in versions prior to Aug03/2011                     */
/* - old code used mtibi/mtiri 1/0 or 0/1 to inc base or redef (kludgy)   */
/* - recode use mtir only from 0 base & chg mtir to redef after base fld cnt*/

/*Sep03/11 - add subrtn lookmap to find maptbl index for matched field     */
/*         - to show search match field on 1st screen of long records      */
int recdmatch;      /* dsplcmnt to search matched field     */
int recdmatchb;     /* 2nd copy for bold insert trigger     */
int mtimatch;       /* maptbl index <= matching field specs */

/*Sep03/11 - insert bold control codes if search match field    */
char bold1[8] = "\x1B\x5B\x37\x6D"; /* start bold standout mode */
char bold2[8] = "\x1B\x5B\x6D";     /*  end  bold standout mode */

/*eject*/
/*uvhdcob------------------ cobmap TYPE table -------------------------*/
/* cobmap may specify record types on *TYPE comment lines              */
/* start display with 1st cobmap fieldname matching fieldname on *TYPE */
/*                                                                     */
/*TYPE=0(1),='N','name-record'  <-- data records with 'N' in byte 0    */
/*TYPE=0(1),='P','pay-record'   <-- data records with 'P' in byte 0    */
/*                                                                     */
/*type=0(1),!'N','name-record'  <-- data records without 'N' in byte 0 */
/*                                                                     */
/* TYPE/type may be UPPER or lower case                                */
/* record type field contents usually UPPER for aplctns from mainframes*/
/* record fieldnames must be lower case since cobmap trslts to lower   */

/*May20/10 - allow TYPE by record-size (for RDW, IDX, text)            */
/*         - identify alt format by maprec.lvl[0] == 'R' (vs 'T')      */
/*                                                                     */
/* TYPE=99:999,'recname'    <-- alternate format for ID by recsize     */
/*                                                                     */

struct MAPREC typtbl[TYPMAX];

int tti;
int ttimax;

struct MAPREC typrw;

int fldctr;           /* field ctr on current screen                    */
                      /* (linectr includes spaces if option s2)         */
int fldctr1;          /* field ctr save for 1st field in group occurs   */
int fldctr2;          /* field ctr save for 1st field in group occurs   */
                      /*Sep26/11 - for nested level 2                   */

char fldnam[40];      /* field name formatted with seq# on left         */
                      /* if option n1                                   */

/*eject*/
/*uvhdcob----------------- command formats -----------------------------*/
/* command format - 2 types                                             */
/* type1 - 1 char command + optional numeric value                      */
/* r100                     - goto & display record #100                */
/*                                                                      */
/* type2 - cmd + op1,op2,op3,op4,op5,op6                                */
/* s 0(20),='ABC'             - search for ABC within 1st 20 bytes      */
/* p 0(3),>'800'              - print records > 800 in 1st 3 bytes      */
/* u 0(3),='ABC'              - update cols 1-3 of current rec w ABC    */
/* s ='ABC'                   - search for ABC anywhere in entire record*/
/* s 0(3),!'ABC'              - search for NOT ABC in cols 1-3          */
/*note - op1 search lth must match op2 constant lth                     */
/*       if searching NOT EQUAL (!) on fields > 1 byte                  */
/*                                                                      */
/* s 0(40),='ABC',40(40),='XYZ' - search for ABC in 1-40 & XYZ in 41-80 */
/*                                                                      */
/* s 0(1),='1',40(1),='A'   - search for 1 in byte 0 AND A in byte 40   */
/* s 0(1),'1',|40(1),'A'    - search for 1 in byte 0 OR A in byte 40    */
/*                                                                      */
/* s 0(1),>'1',40(1),<'Z'   - search for >1 in byte 0 & <Z in byte 40   */
/*                                                                      */
/* s 0(80),<x'20',0(80),>x'7E' - search for non printable chars in 1-80 */
/*                                                                      */
/* s 0(1),'1',|,'2'         - op3 omitted defaults to op1 search area   */
/*                          - must specify OR (|) for = conditions      */
/* s 0(1),>'1',,<'9'        - search for 2-8 in byte 0 (range search)   */
/*                                                                      */
/*eject*/
/*uvhdcob-------------- command argument storage -----------------------*/
/*                                                                      */

char opcmd[80];                /* oprtr reply to command prompt         */
char opcmd2[80];               /* op reply alt w/s to dflt 99 to r99    */

char cms[80];                  /* command string (up to 1st space)      */

char cops[80];                 /* command options string                */

char copsn[24];                /* numeric digits isolated from cops     */

UVi64 cmn;                     /* numeric value appended to cmnd        */
                               /* May2001 - cmn changed to UVi64        */

char copsc[28];                /* cmd options char array                */
int copsi[28];                 /* cmd options integer array             */

char args[128];                /* arguments (after 1st space to next sp)*/
int argsd;                     /* dsplcmnt to current arg (for sdscopy) */

char wopsc[28];                /* work area to test any optns spcfd     */

/*Dec07/10 - Ascii or Ebcdic Blank if optn 'a', for move/updt clear excess*/
char AEB = ' ';          /* changed to 0x40 if option a EBCDIC data input */
char AEC[4] = "=c";      /* changed to "=e" if option a EBCDIC data input */

/*eject*/
/* args separated op1,op2,op3,op4 before standardizing & defaulting     */
char arg1a[80];                /* field1 search area - dspl(lth)        */
char arg2a[80];                /* field1 search constant                */
char arg3a[80];                /* field2 search area - dspl(lth)        */
char arg4a[80];                /* field2 search constant                */
char arg5a[80];                /* field3 search area - dspl(lth)        */
char arg6a[80];                /* field3 search constant                */

/* args after defaulting & standardizing constants =c'ccc' >x'xx',etc   */
char arg1b[80];
char arg2b[80];
char arg3b[80];
char arg4b[80];
char arg5b[80];
char arg6b[80];

/* args after stripping quotes/conditions & cnvrsn to hex if indicated  */
char arg1c[80];
char arg2c[80];
char arg3c[80];
char arg4c[80];
char arg5c[80];
char arg6c[80];

/* arg dsplcmnts & lengths (only lengths for constants op2/op4)       */
int arg1d;                    /* op1 displacement                     */
int arg1l;                    /* op1 length                           */
int arg2d;                    /* op2 dsplcmnt for move Dec06/10       */
int arg2l;                    /* op2 length (constant)                */
int arg3d;                    /* op3 displacement                     */
int arg3l;                    /* op3 length                           */
int arg4l;                    /* op4 length (constant)                */
int arg5d;                    /* op5 displacement                     */
int arg5l;                    /* op5 length                           */
int arg6l;                    /* op6 length (constant)                */
int op1dflt;                  /* op1 defaulted to 0(rsz1)             */

/*eject*/
/*uvhdcob-------------- command structure storage ----------------------*/
/* structure to store command values                                    */
/* - initially stored here, then moved depending on 's' 'p' 'u'         */

struct CA {
  char cmd[80];             /* orig cmnd for errmsgs             */
  char cmc[80];             /* command chars                     */
  char cmo[80];             /* command options                   */
  char a2c[80];             /* op2 constant data                 */
  char a4c[80];             /* op4 constant data                 */
  char a6c[80];             /* op4 constant data                 */
  char a1cc[4];             /* op1 condition (not used)          */
  char a2cc[4];             /* op2 condition <=!> (in 1st byte)  */
  char a3cc[4];             /* op3 condition '|' 1st byte = OR   */
  char a4cc[4];             /* op4 condition <=!> (in 1st byte)  */
  char a5cc[4];             /* op5 condition '|' 1st byte = OR   */
  char a6cc[4];             /* op6 condition <=!> (in 1st byte)  */
  int cmv;                /* cmd value (numerics appended)     */
  int a1d;                /* op1 dsplcmnt                      */
  int a1l;                /* op1 length                        */
  int a2d;                /* op2 dsplcmnt for move Dec06/10    */
  int a2l;                /* op2 length                        */
  int a3d;                /* op3 dsplcmnt                      */
  int a3l;                /* op3 length                        */
  int a4l;                /* op4 length                        */
  int a5d;                /* op5 dsplcmnt                      */
  int a5l;                /* op5 length                        */
  int a6l;                /* op6 length                        */
  int op1dflt;            /* op1 defaulted to 0(rsz1)          */
  int pscd;               /* prior search continuation dsp     */
  int psfp;               /* prior search file ptr             */
  int opi[26];            /* cmnd options - integer            */
  char opc[26];           /* cmnd options - character          */
  char a1dt;              /* Data Type - Packed/Zoned/Binary   */
  char a1dc;              /* Data Code - Ascii/ABCDIC          */
  char a1sgn;             /* Data Sign to insert +/-           */
  char a2dt;              /* Data Type - Packed/Zoned/Binary   */
  char a2dc;              /* Data Code - Ascii/ABCDIC          */
  char a2sgn;             /* Data Sign to insert +/-           */
  /*Dec26/10 - a2dt,a2dc,a2sgn added for move numeric          */
};

/* note re pscd - op1 dsp prior match (for search continue)      */
/* cmd ss  - repeat search (from next record)                    */
/* cmd sss - repeat search (same record, incrmnt column)         */
/* cmd ssr - repeat search (same record, resetting to column 1)  */

/*eject*/
/*-------------------- command structures -----------------------*/
struct CA carg0;            /* cmd arg structure for clearing    */

struct CA cargs;            /* cmd args processing storage       */

struct CA sargs;            /* search args strorage              */
struct CA pargs;            /* print args storage                */
struct CA iargs;            /* print args storage                */
struct CA wargs;            /* write args storage                */
struct CA uargs;            /* update args storage               */
struct CA kargs;            /* check sequence args storage       */
struct CA targs;            /* tally args storage                */
struct CA vargs;            /* verify args storage               */
struct CA fargs;            /* find record# in varlth files      */
struct CA margs;            /* move char field/constant          */
struct CA nargs;            /* move Numeric field/value          */
struct CA aargs;            /* acumulate record field            */
struct CA xargs;            /* for acum crossfoot Feb26/11       */

/*eject*/
/*uvhdcob-------------------- output files -----------------------------*/
/*Feb05/09 - common functions openfileX & closefileX for P,I,W,V,D files*/
/*         - chg P/I/W/V/D cmds to open & close output file on each cmd */
/*         - cmd line option w1 to write 1 combined file vs separate    */
/*         - filename format as follows:                                */

/* $UVTMPDIR/inputfilename_yymmdd_hhmmssX               <-- X=P/I/W/V/D */
/* $UVTMPDIR/inputfilename_yymmdd_ <-- basefilename + time + X each open*/

char basename[128];             /* basefilename formatted at prgm init  */

/*------------------ output file for print command --------------------*/
/* print filename = $UVTMPDIR/inputfilename_yymmdd_hhmmssP             */

char pfname[128];              /* print output filename built here */
FILE *pfptr;                   /* output file for print command    */
int pfopn;                     /* switch to open file on 1st print */
int pfctr;                     /* print command counter            */

/*Aug13/11 - iprint command combined with print as option 'i' */

/* Iprint commands - modified depending on unix or DWIN               */
/*   - & depending on env-vars UVHDPRINT & UVHDPWIDE                  */
/*   - or you could modify source code here to 'lp' if desired        */
#ifdef DWIN
char prtcmd[30] = "uvlpr12";   /* iprint cmd string for system cmd    */
char prtcmdW[30] = "uvlpr12L"; /* iprint cmd Wide (Landscape?) i#l100 */
#else
char prtcmd[30] = "uvlp12";    /* iprint cmd string for system cmd    */
char prtcmdW[30] = "uvlp12L";  /* iprint cmd Wide (Landscape?) i#l100 */
#endif

char prtcmdfile[128];          /* iprint cmd string w file appended   */
char prtcmdWfile[128];         /* iprint Wide cmd with file appended  */

/*eject*/
/*uvhdcob----------- output file for write command --------------------*/
/* write filename = $UVTMPDIR/inputfilename.datetimeW                  */
char wfname[128];              /* write output filename built here     */
FILE *wfptr;                   /* output file for write command        */
int wfopn;                     /* switch to open file on 1st write     */
int wfctr;                     /* write command counter                */

char wrecb[RMAX+8];         /* record area for write command        */

char *wrecd = wrecb;        /* adrs for data, offset by optns z2,z4,n1 */

int wrhs;              /* record hdr size for Write records            */

int wrs1w;             /* recsize for write I/O, for RDWz2 = data + 2  */
                       /* for RDWz4 = data + 4                         */

int wrs1h;             /* recsize for RDW hdr, sames as wrs1w for RDWz2*/
                       /* - must add 4 for RDWz4                       */
short wrs1hs;          /* write size in short for union switch ends    */

int wrsn1;             /* length of recsize numerics inserted by n1 */
                       /* - set to 4 if k1, else 0                  */
int wrsn2;             /* length of recsize numerics inserted by n2 */
                       /* - set to 4 if k2, else 0                  */
int wrsn3;             /* wrsn1 + wrsn2 (4 or 0)                    */

char *wrecn1;          /* adrs for optn n1 numeric recsize insert at bgnrec*/
char *wrecn2;          /* adrs for optn n2 numeric recsize insert at endrec*/

/*------------------ output file for verify write ---------------------*/
/* filename = $UVTMPDIR/inputfilename.datetimeVW                       */
char vwfname[128];          /* verify write output filename built here */
FILE *vwfptr;               /* verify output file for write command    */
int vwfopn;                 /* verify switch to open file on 1st write */
int vwfctr;                 /* verify write records counter            */

/*------------------ output file for verify print ---------------------*/
/* filename = $UVTMPDIR/inputfilename.datetimeVW                       */
char vpfname[128];          /* verify print output filename built here */
FILE *vpfptr;               /* verify output file for print command    */
int vpfopn;                 /* verify switch to open file on 1st print */
int vpfctr;                 /* verify print records counter            */

/*eject*/
/*uvhdcob------------ file status structure ---------------------------*/
/* - to test for presence of 'tmp' sub-directory                       */
/* - will create if not present in current directory                   */
/*May03/11 - add $UVTMPDIR define subdir for print,write,drop,index,etc*/
struct stat tmpstat;           /* file stat structure - test tmp dir   */
char tmpdir[128];              /* $UVTMPDIR or tmp                     */
char mkdirtmp[100];            /* system("mkdir $UVTMPDIR");           */

/*--------------------------- update storage ---------------------------*/
/* work storage for updates - sample update commands follow             */
/*   u0(3),='ABC'    - change 1st 3 bytes of current record to 'ABC'    */
/*   u10(3),=x'0D0A' - change bytes 11 & 12 of current record to x'0D0A'*/

char recsav1[RMAX+8];            /* current record before any updates   */
char recsav2[RMAX+8];            /* current record before last update   */

UVi64 fplastup = -1;             /* fileptr of last record updated      */
                                 /* -1 for init purposes                */

UVi64 seekstat;                 /* I/O status for seeks                 */

int writestat;                /* I/O status for writes                */

UVi64 statstat;                 /* I/O status for stat                  */

int opstat;                    /* status returned by update & rollback*/

/*--------------------- check sequence field storage --------------------*/

char chksav1[128];               /* check sequence field storage         */
char chksav2[128];               /* check sequence field storage         */

int chksav1i;                    /* for option 'i' incrmnt i1,i10,etc    */
int chksav2i;

/*eject*/
/* trtprint.c - translate table - convert unprintable chars to periods   */
/*            - originally linked in from archive UVlib.a                */
/* 971107 - included here to make prgm self-contained for internet share */
/*Apr04/06 - changed unprintable char rep from period to carat 0x2E to 0x5E */
/*         - but did not like so changed back                               */

unsigned char trtprint[256] = {
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,
0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E,0x2E
};

/* trtprintE.c - translate table to translate EBCDIC to printable chars */
/*             - translate unprintables to EBCDIC period 0x4B           */
unsigned char trtprintE[256] = {
0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0x40,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
0x50,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
0x60,0x61,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
0x4B,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0x4B,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0x4B,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B
};

/*eject*/
/* ASCII to EBCDIC translation table  */
unsigned char asc2ebc[256] = {
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f,0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26,0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d,0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0x4a,0xe0,0x4f,0x5f,0x6d,
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xc0,0x6a,0xd0,0xa1,0x07,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x1c,0x1d,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xbc,
0xab,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xbb,0xac,0x40,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x40,0x9e,0xae,0x8c,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40
};

/* EBCDIC to ASCII translation table  */
unsigned char ebc2asc[256] = {
0x00,0x01,0x02,0x03,0x04,0x09,0x06,0x7f,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x08,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x0a,0x17,0x1b,0x28,0x29,0x2a,0x2b,0x2c,0x05,0x06,0x07,
0x30,0x31,0x16,0x33,0x34,0x35,0x36,0x04,0x38,0x39,0x3a,0x3b,0x14,0x15,0x3e,0x1a,
 ' ',0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49, '[', '.', '<', '(', '+', ']',
 '&',0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59, '!', '$', '*', ')', ';', '^',
 '-', '/',0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69, '|', ',', '%', '_', '>', '?',
0x70,0x71,0x72,0x73,0x74,0x76,0x77,0x78,0x79, '`', ':', '#', '@',0x27, '=', '"',
0x80, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90, 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0, '~', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
 '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',0xca,0xcb,0xcc,0xcd,0xce,0xcf,
 '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',0xda,0xdb,0xdc,0xdd,0xde,0xdf,
0x5c,0xe1, 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',0xea,0xeb,0xec,0xed,0xee,0xef,
 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',0xfa,0xfb,0xfc,0xfd,0xfe,0xff
};

/*eject*/
/* EBs2MFs - translation table - EBCDIC signs to Microfocus COBOL signs */
/*         - used by the 'zx' option of acum 'a 53(9zx)'                */
/* corrects for EBCDIC unpacked signs already translated to ASCII chars */
/* pos 0-9  {ABCDEFGHI 0x7B,0x41-0x49 convert to 0123456789 0x30-0x39   */
/* neg 0-9  }JKLMNOPQR 0x7D,0x4A-0x52 convert to pqrstuvwxy 0x70-0x79   */
unsigned char EBs2MFs[256] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
0x40,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x71,0x72,0x73,0x74,0x75,0x76,
0x77,0x78,0x79,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x30,0x7C,0x70,0x7E,0x7F,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
};

/*eject*/
/*uvhdcob------------- MF COBOL variable lth records --------------------*/
/* added 9911, option v (existing option v changed to option t)          */

char vfhdr[8192];        /* MF COBOL variable lth file hdr stored here   */
                         /*Dec2004 - increased to 8K for IDXFORMAT8      */

int vrmax;             /* max rcsz from file hdr bytes 54-57           */

int vrmin;             /* min rcsz from file hdr bytes 58-61           */

short vr4k;            /* indicator 1 if max rcsz > 4095, else 0       */

int vfhs;              /* file header size for IDXFORMAT8              */

int vfxtra;            /* vfhs-128 to read remainder of file header    */

int vrhs = 0;          /* rec hdr size = 4 if maxrcsz > 4095, else 2   */

union INTC             /* union used in getrecv                        */
{ int ii;
  short ss;
  char cc[4];
};

int vrsize;            /* current record size                         */
                       /* extracted from the 2 or 4 byte hdr          */

int vrslot;            /* current record slot (hdr+data+fill to mult4)*/

Uchar vrtyp;           /* current record type                         */
                       /* isolated from hdr zone only, digit cleared  */

int vfhs = 128;        /* file hdr size (128 bytes)                   */

/*Pre Nov2002 - vfhs used to calc fileptr from rec#, +recs, -recs       */
/*            - presuming Indexed files, no good for RSV seqntl files   */
/* Nov2002 - now change to presume RSV sequential files                 */
/*         - also presumes all recs minsize ??                          */
/*      IE - using random rec# probably wont work well for RSV/ISV files*/

/*Mar2003 - unions u1 & u2 moved here from switchb subfunction         */
/*        - was getting erroneous 'usage before def' msg from lcc-win32*/
union INTC u1;                 /* work area unions to switch ends      */
union INTC u2;
union INTC u3;
union INTC u4;
/*Jan14/11 - add u3,u4 for z8 write BDW = RDW+4 (on every record) */

/*eject*/
/*uvhdcob----------------------- RDW stuff -----------------------------*/

char rdwhdr[48];         /* work area to read 2, 4,or 8 byte header     */

int rdwhs = 0;           /* RDW header size from option z               */
/*Nov05/07 - variable length RDW option z verify z0,z2,z4,or z8         */
/* - now always assume recsize in 1st 2 bytes                           */
/*Sep09/08 - provide option z1 for little-end RDW                       */
/* z2=2bytehdr, z4=4bytehdr, z8=BDW/RDW 4+4, z0 deflt z4,               */
/* - remove prior z# considered lth of hdr                              */

/*Sep09/08 - use rdwhx = extra bytes for total recsize */
int rdwhx;             /* 2 for z2, 0 for z4 & z8    */
int rdwsize;           /* current record size                         */
                       /* extracted from the 2 or 4 byte hdr          */
int bdwsize;           /* current block size                          */
int rdwslot;           /* current record slot (hdr+data+fill to mult4)*/

int bdwrn;             /* rec# of last BDW (for rdwerr) */
UVi64 bdwfp;           /* fileptr of last */
char bdwsave[8];       /* last BDW/RDW    */
char bdwsavehex[20];   /* last BDW/RDW in hex */
char bdwcurhex[20];    /* current BDW/RDW in hex */

/*Apr27/11 - add BDW/RDW stats collected while building Index     */
/*         - bdwmin used to bypass BDW on later record get/search */
int  bdw1st;
int  bdwmin;
int  bdwmax;
int  bdwavg;
int  bdwcnt;
UVi64 bdwsum;
UVi64 bdwnext;     /* fileptr to next BDW (while building Index) */
char bdwmins[12]; /* min BDW string from loadindex() */

int  rdwmin;
int  rdwmax;
int  rdwavg;
UVi64 rdwsum;

/* vhxbits for data2vhx() report ERRs ib BDW/RDW prefixes */
/* - 0x01 + 0x02 if EBCDIC input file                     */
short vhxbits = 0x01;
int  indexbuildtime;             /* Indexing elapsed time */

/*Jun12/11 - save prior BDW/RDW, ensure bdwmin not last BDW in file */
UVi64 filesizeb;        /* filesize - 32768 ensure bdwmin not last */
int rdwsizep;           /* prior rdwsize for error report */
int bdwsizep;           /* prior bdwsize for error report */

/*eject*/
/*------------------------ find Index tables ---------------------------*/
/*Jul09/10 - Index tables for find cmd for faster access to spcfd rec#s */
/*         - tables of fileptrs & record#s to 1,2,3% etc of filesize    */
/*         - built by find option 'i' (command 'fi')                    */
/*Nov21/10 - Index built automatically for varlth files (RDW,text,IDX3/8)*/

UVi64 fifp[102]; /* table of fileptrs for 1%,2%,...100%     */
int firn[102];   /* table of record#s for 1%,2%,...100%     */
int fii;         /* index for table build & lookup          */
int fii1;        /* switch set 2 when Index build completed */

/* fifp[102] initialized/calculated as follows */
/* fifp[0]=0, fifp[1]=1% fsize, fifp[2]=2% fsize,..., fifp[100]=100% fisze  */
/* firn[0]=0, firn[1]=rec# at 1% filesize,..., firn[100]=lastrec# in file   */

/*----------------------- find Index file I/O --------------------------*/
/*Apr20/11 - find Index file I/O                                        */
/* findex() - function to build Index & save it OR load it if existing  */
/* findexload - called if Index file exists same filename & filesize    */
/* findexsave - called to write Index to $UVTMPDIR/uvhdindex_filename   */

/* Index file records are formatted as follows                  */
/* #01:uvhdindex_X--------filename--------X                     */
/* #02:filesize=999999,fileptr1=999900,options=z8               */
/* #03:IndexCreated=yymmdd_hhmmss,BuildTimeSeconds=999          */
/* #04:BDWmin=99,BDWmax=9999,BDWavg=999,Blocks=999              */
/* #05:RCSZmin=99,RCSZmax=9999,RCSZavg=999,Records=9999         */
/* #06:1=0,2=99,3=999,4=999,...etc...                           */
/* #07:10=9999,11=9999,...etc...                                */

char finame[180];    /* filename built here */
FILE *fiptr;         /* fileptr from fopen  */
int  fiopn;          /* file open switch    */
struct stat fstatI;  /* file status structure */

/* constants/variables used to write index */
int  firn1;          /* find index record# */
char fir1id[20] = "#01:uvhdindex_";
char fir2fs[20] = "#02:filesize=";
char firec[180];     /* area to build or read index records */

char filesizeIs[20]; /* filesize from #02:filesize=...      */
UVi64 filesizeI;     /* filesize converted to long int      */

char indexfile[128];   /* index filename for msg tmp/uvhdindex_... */
char indexcreated[20]; /* create date saved for msg */

/*eject*/
/*uvhdcob------------------- translate tables -------------------------*/

/* neutral translate table - generated at program init                 */
Uchar trtn[256];

/* table to translate unprintables to chracters or periods(carats?)   */
Uchar trtc[256];

/* trtn copied to trtc & modified depending on translate options       */
/* - unprintables to blanks or periods(carats)                         */
/* - except for LFs, CRs, FFs, Tabs                                    */
/* - depending on options c1, c2, c4, c8                               */
/*Jan26/09 - NOT USED in uvhdcob (yet) left in case                    */

/*---------------------------- unions ---------------------------------*/

/* unions to show decimal value on right for 2,4,8 byte binary fields */
union SHORTCC     
{ short ss;
  char cc[2];
};

union INTCC   
{ int ii;
  char cc[4];
};

/*Feb22/11 - show decimal value on right for 8 byte binary fields */
union LONGCC     
{ long long ll;
  char cc[8];
};

union SHORTCC usc;      /* to convert 2 byte binary to decimal  */
union INTCC   uic;      /* to convert 4 byte binary to decimal  */
union LONGCC  ulc;      /* to convert 8 byte binary to decimal  */

/*eject*/
/*----------------------- help screen pointer table --------------------*/
/* for showhelps function (allows user to enter desired screen#)        */

char **hsp[24] = {
help01,
help02,
help03,
help04,
help05,
help06,
help07,
help08,
help09,
help10,
help11,
help12,
help13,
help14,
help15,
help16,
help17,
help18,
help19,
help20,
help21,
help22
};

/*May27/10 - switch k0 to kill help prompts & k1 to restore */
int helpson = 0;        /* help prompts initially off */

/*eject*/
/*uvhdcob----------------------- verify data counters -------------------*/

int vcxt;           /* verify Character data error count        */
int vnxt;           /* verify Non-numeric data error count      */
int vpxt;           /* verify Packed data error count           */
int vaxt;           /* All errors count                         */
int vrxt;           /* total records with errors                */
int v1xt;           /* errors in current record                 */
int vzups;          /* switch to cause update by verify z1/z2/z4*/
int v1dsp;          /* save byte# 1st err in current record     */
int v2dsp;          /* save byte# 1st err in all recs verified  */
int v2num;          /* save rec# of 1st err in all recs verified*/

/*eject*/
/*Dec19/10 - for getop, putop1, etc to suport acum & move numeric    */
/*------------------ ascii/ebcdic sign/zone constants ---------------*/
Uchar signasczp = 0x30;              /* ascii zoned  positive sign   */
Uchar signasczn = 0x70;              /* ascii zoned neg Microfocus   */
Uchar signebczp = 0xf0;              /* ebcdic zoned  positive sign  */
Uchar signebczn = 0xd0;              /* ebcdic zoned  negative sign  */
 char signseppa = 0x2B;              /* ascii separate negative sign */
 char signseppe = 0x4E;              /* ebcdic separate negative sign*/
 char signsepna = 0x2D;              /* ascii separate negative sign */
 char signsepne = 0x60;              /* ebcdic separate negative sign*/
Uchar zeroasc   = 0x30;              /* ascii zero                   */
Uchar nineasc   = 0x39;              /* ascii nine                   */
Uchar zeroebc   = 0xf0;              /*  ebcdic zero                 */
Uchar nineebc   = 0xf9;              /*  ebcdic nine                 */

/*9905 - setup signs for positive packed fields, depending on:        */
/*       run optn s1/s2, instrn optn s1/s2, or last + sign input      */
/*9906 - instrn option s0/s1/s2 now overrides run option s0/s1/s2     */
/*     - see 'setsigns' subfunction                                   */
Uchar signpp1 = 0x0c;                /* ascii packed positive sign    */
Uchar signpp2 = 0x0f;                /* ascii packed positive nosign  */
Uchar signpn1 = 0x0d;                /* ascii packed negative sign    */
 char signsepp;                      /* ascii/ebcdic separate sign pos*/
 char signsepn;                      /* ascii/ebcdic separate sign neg*/

/* ascii/ebcdic codes for current instrn operand op1 or op2           */
/* - setup by setcodes function depending on opdc                     */
/* - used for digit selection, sign detection & insertion, zone fill  */
Uchar zero;                          /* ascii or ebcdic value stored  */
Uchar nine;
Uchar signzp;                        /* ascii/ebcdic sign zoned pos   */
Uchar signzn;                        /* ascii/ebcdic sign zoned neg   */

/*note - signpp set from signpp1/signpp2/signpplast & options s0/s1/s2*/
Uchar signpplast;                    /* last pos packed sign input    */
/*Dec26/10 - signpplast disabled */
Uchar signpp  = 0x0C;                /* packed pos sign for next putop1*/
Uchar signpn  = 0x0D;                /* ascii/ebcdic sign packed pos  */
                                     /* - neg pack sign never varies  */

/* sign indicator - all sign indications whether separate or zoned */
/* packed or unpacked are 1st detected & coded here as +/-         */
/* then tested & recoded on output to sepsign or zone in pkd/unpkd */
/* to allow flexibility converting input/output formats            */
char sign;                    /* sign byte '+' or '-'              */
                              /* indicator set by sep sign byte    */
                              /* or from zone/digit of units zn/pk */
Uchar signzone;               /* zoned  sign for current field     */
Uchar signpack;               /* packed sign for current field     */

/*eject*/
/*------------------- work areas for getop, putop, etc ----------------*/
char w1[256];
char w2[256];
char w3[256];
char w4[256];

/*--------------------------- constants ---------------------------------*/
/* areas init'd on program startup */
char Ablanks[64];     /* init'd to ASCII blanks  */
char Eblanks[64];     /* init'd to EBCDIC blanks */
char nulls[64];       /* init'd to nulls         */

/*eject*/
/*uvhdcob-------- declare functions - unique to this program ------------*/

int print1(void);
int printrec(FILE *fptr);

/* from uvhd */
int openfile(void);
int fileseek(char *emsg);
int getrec(short bits);
int getrecf(short bits);
int getrecv(short bits);
int getrect(short bits);
int getcbuf(void);
int switchb(char *vrhdr, short bits);
int switchx(char *vrhdr, short bits);

int chkrcsz(int recsiz0);
int calcrecs(int rszmap, int rszdflt);
int setlast1(int rszmap, int rszdflt);
int testlast1(int fhsize);
int check1(void);
int calcrsl(int rsiz, int fsiz);
int calcrsg(int rsiz, int fsiz);

int parse(void);

int write1(void);
int writerec(void);
int writerec2(void);
int update(void);
int move1(void);
int moven(void);
int back1(void);
int backall(void);

/* chk getlinr, filterchar,hexzone,hexdigit ? */
int getlinr(int lsize);
void filterchar(unsigned char *string, int lsize);
void hexzone(char *out, char *in, int lsize);
void hexdigit(char *out, char *in, int lsize);

int search1(void);
int search2(char *recd, struct CA *cap);
int search3(char *recd, struct CA *cap);
int search4(char *recd, struct CA *cap);
int search234(char *recd, struct CA *cap);
int search34(char *recd, struct CA *cap);
int tally1(void);

int showhelps(char **hsp[], int hsmax);
short printRV(char *warnmsg);

/*eject*/
int getdatetime(void);
int bad2hex(char *fdat2, char *fdat1, int flth2);
int badn2hex(char *fdat2, char *fdat1, int flth2);
int showdcmls(char *fdat2, char *fdat1, int flth1);

/*Jan27/09 - getting warn asngmnt makes ptr from int w/o cast      */
/*           on atol1 (5) & spcopy (2)                             */
/* - changed all 'UVint' to 'int' & some errs went away            */
/* - copied atol1 & spcopy into uvhdcob (renamed atol1a & spcopya) */
/*Dec21/10 - change uvhdcob atol1a/atol3a back to atol1/atol3      */
char *atol1(int *result, char *in, char stopc, int max, short bits);
int   atol2(char *str, char stopc, int max, short bits);
char *atol3(int *result, char *in, char *stops, int max, short bits);
char *spcopya(char *out, char *in, char stop, int max, short bits);

int verify1(void);
int verifyc(char * fdat1, int flth1, short bits);
int verifyn(char * fdat1, int flth1, short bits);
int verifyp(char * fdat1, int flth1, short bits);

/*Feb07/09 - openfileX etc copied from uvhd */
int openfileX(char *xfname, char *xfid, FILE **xfptr, int *xfopn, short bits);
int closefileX
   (char *xfname, char *xfid, FILE **xfptr, int *xfopn, int *xfctr, short bits);

/*Feb07/09 - function prototype declarations for uvhdcob.c           */
/* - for functions added to make uvhdcob.c self-contained (freeware) */
int uvfgets(char *area, int max);
int getlin0(FILE *fp, char *rec, int count, int stop, short bits);
int sncopy(char *out, char *in, int max, short bits);
int stncopy(char *out,char *in,char stopc,int max,short bits);
int stmcopy(char *out, char *in, char *stops, int max, short bits);
void errmsg(char *msg, char *inf1, char *inf2, int num, short bits);
int showhelp(char **helpmsgs, int max, short bits);
int searchcm(char *data, char *matchchars, int max1, int max2, short bits);
int uvedit(char *s1, int l1, int val, char *mask, short bits);
void cnvdttm(char *dttm, time_t unixtime);
int hex2data(char *out, char *in, char stopc, int max, short bits);
void data2hex(char *out, char *in, int max, short bits);
int sortops(char *opsu, char *opsc, int *opsi, short bits);
int sortops4(char*opsu,char*opsc,int*opsi,char**opsp,char*opsb,short bits);
int toascii2(Uchar *str, int max, short bits);
int toebcdic2(Uchar *str, int max, short bits);
int toprint2(Uchar *str, int max, Uchar *trt, short bits);
int sdscopy(char *out,char *in,int max,int *sds,char *stop,short bits);

/*eject*/
int upfileptr(int recsize1);
int setfileptr(UVi64 newfileptr);
int findex(void);
int findexsave(void);
int findexload(void);
int findrec(void);
int getrdwh(short bits);
int getrdwh2(short bits);
int getrdw(short bits);
int rdwerr(char *msg, short bits);
int putlin0(FILE *fp, char *rec, int count, int stop, short bits);
void data2vhx(char *chars,char *zons,char *digs,char *data,int lth
               ,char *ebc2asc, short bits);

int setlock(int fd, int locktype, char *fname);
void waitlock(int *waitacum, char *fname, char *msg);

/*Dec21/10 prototypes acum1 + getop,putop1,etc to suport acum & move numeric*/
int acum1(void);
void pack(char *out, char *in);
void unpack(char *out, char *in, short bits);
void tstsignp(char *wa, struct CA *carg);
void tstsignz(char *out, char *in, struct CA *carg);
void setsignp(char *wa);
void setsignz(char *out, char *in, int db1, char sgncd);
short bswap2(Uchar *ptr);
short bswap3b(Uchar *ptr);
short bswap3i(Uchar *ptr);
short bswap4(Uchar *ptr);
short bswap8(Uchar *ptr);
void setcodes(char code);
void setsigns(struct CA *carg);
UVi64 getop(char *recd, struct CA *carg, short bits);
void putop1(char *recd, struct CA *carg, UVi64 binarg);
int cnvbnf20(void);
int cnvbpf20(void);
int cnvbcf20(void);
int close1(void);
int testnp(char *data, int lth);
int testnb(char *data, int lth);
int testnn(char *data, int lth);
int testnc(char *data, int lth);
int lookmap(int recdsp);

/*eject*/
/**************************** main ************************************/
int main(int argc, char **argv)
{
int aa,bb,cc,dd,ee,ii,ll,mm,oo,rr,ss,tt;  /* misc indices, ctrs, etc */
char *pp;      /* see 1463,1464 spcopy warn asngmt makes ptr from int ? */
char *ppp;     /* try redefine pp as ppp ? */      

char ww[100];             /* misc work area */

getdatetime();            /* get current date & time & format */

/* store options from user preferences env-var $UVHDCOBROP first       */
/* - will later append any command line options (override UVHDCOBROP)  */
pp = getenv("UVHDCOBROP");
if (pp)                           /* if env-var UVHDCOBROP defined ?   */
  { strcpy(opsu,pp);
  }

/* get system date & time & convert to "yyyymmddhhmm" format          */
tmsecs = time(0);                 /* get time in secs since 1970      */
cnvdttm(today,tmsecs);            /* convert to "yyyymmddhhmm"        */
memcpy(todttm,today,8);           /* copy for 'yyyymmdd:hhmm' edit    */
todttm[8] = ':';                  /* insert ':' after yymmdd          */
memcpy(todttm+9,today+8,4);       /* append HHMM                      */
today[12] = '\0';                 /* drop seconds for date/time stamps*/

/* process command parameters:  "cmnd datafile cobmapfile options"    */
/* - store filenames & options if present                             */
/* - if filenames not entered - display "help" screen & quit          */
if ((argc < 3) || (argc > 4))          /* <<<<<< chg back to 3 when debugged*/
  { showhelps(hsp,21);         /* show help01 - help21 */
    /*Oct05/11 - show machine & H32/H64 after last help screen */
    printf("\nuvhd version=%s, machine=%s, H32/H64=%s\n\n"
            ,uvversion,machine,H32H64);
    exit(1);
  }

strcpy(fn1,argv[1]);                     /* store data filename        */
strcpy(fn2a,argv[2]);                    /* store cobmap filename      */
if (argc == 4)
  { strcat(opsu,argv[3]);
/*Apr21/09 - chg strcpy to strcat to preserve any UVHDCOBROP */
/*  printf("DEBUG2: argv3=%s\n",argv[3]); */
  }

/* generate neutral translate table     */
/*Jan26/09 - NOT USED, but left in case */
for (ii=0; ii < 256; ii++)
   { trtn[ii] = (Uchar) ii;
   }

/* init some areas at program startup */
memset(recb,' ',RMAX);     /* set recb to blanks */
memset(Ablanks,0x20,64);   /* to compare to ASCII blanks  */
memset(Eblanks,0x40,64);   /* to compare to EBCDIC blanks */

/*eject*/
/* determine copybookfile to use */
/* - arg2 as entered, or $RUNLIBS/arg2, or $RUNLIBS/maps/arg2 */

/* get RUNLIBS value */
pp = getenv("RUNLIBS");
if (pp)
  { strcpy(runlibs,pp);
  }

/* store 2nd & 3rd possible filenames for copybook */
strcpy(fn2b,runlibs);
strcat(fn2b,"/");
strcat(fn2b,fn2a);

strcpy(fn2c,runlibs);
strcat(fn2c,"/maps/");
strcat(fn2c,fn2a);

/* stat all 3 possibilities, test results & select 1st file present */
aa = stat(fn2a,&fn2astat);
bb = stat(fn2b,&fn2bstat);
cc = stat(fn2c,&fn2cstat);
if (aa >= 0)                     /* arg2 filename present ?   */
  { strcpy(fn2d,fn2a);
  }
else if (bb >= 0)                     /* arg2 filename present ?   */
  { strcpy(fn2d,fn2b);
  }
else if (cc >= 0)                     /* arg2 filename present ?   */
  { strcpy(fn2d,fn2c);
  }

/*eject*/
/*uvhdcob------------------- process options --------------------------*/
/* process options - sort into alpha position, store any letter prmtrs */
/*                   & convert any numeric prmtrs to integer           */
ss = sortops4(opsu,opsc,opsi,opsp,opsb,0x10);
if (ss < 0)
    errmsg("options invalid, must be alpha+numeric a1b2c300 etc",
            opsu,"",0,0x21);

/*Feb22/11 - test option i1/i2 (force switch binary) no/yes        */
/* - if i1/i2 not spcfd, default to i1/i2 no/yes depending LEM/BEM */
/* if (!opsi['i'-'a'])                   */
/*   { if (LEM) { opsi['i'-'a'] = 2; } } */
/*Aug13/11 - use option i for inhibit show 0/b flds, will use LEM */
/*           i1 = item occurs, i2 = group occurs, i4 = all fields */
/* - no longer need separate options for item,group,all */
/* ooioptn = opsi['i'-'a'];  */
/* goioptn = opsi['i'-'a'];  */
/* allioptn = opsi['i'-'a']; */

/*Dec24/10 - default option y to y1 (MF COBOL numric signs) */
/*Dec26/10 - OR to y2 if option 'a' for EBCDIC input file   */
if (!(opsc['y'-'a']))
  { if (opsc['a'-'a'])
      { opsi['y'-'a'] = 2;
      }
    else
      { opsi['y'-'a'] = 1;
      }
  }

/* setup max lines/screen from option 'm', or set default if m unspcfd */
linemax = opsi['m'-'a'];
if (linemax <= 0)
  { linemax = 18;          /*Sep02/11 - increase from 18 to 20 */
  }
/*Sep30/11 - change back to 18 (verify screen needs) */

/*Aug19/10 - add option k1 to set command help prompts on (same as cmd k1) */
if (opsi['k'-'a'] & 0x01)
  { helpson = 1;
  }

/* store any option  to execute 1 command & quit           */
/*ex: uvhdcob file cobmap x=p99  <-- print all recs & quit */
/*Dec27/10 - chg current optn o to optn j                  */
if (opsp['j'-'a'])
  { strcpy(cmd1s,opsp['j'-'a']);
  }

/*Dec07/10 - store parse EBCDIC constant type default if optn a   */
/*         - store Ebcdic blank for move/updt clear excess op1 lth*/
if (opsc['a'-'a'])
  { strcpy(AEC,"=e");
    AEB = 0x40;
  }

/* calc length of smso & rmso (in case user modifies stringa)          */
smsol = strlen(smso);
rmsol = strlen(rmso);

/*eject*/
/* create filenames for print & write commands (in case needed)        */
/* print filename = $UVTMPDIR/inputfilename_yymmdd_hhmmssP             */
/* write filename = $UVTMPDIR/inputfilename_yymmdd_hhmmssW             */
/* drop filename  = $UVTMPDIR/inputfilename_yymmdd_hhmmssD             */

/* 1st extract root filename from input filename (removing prefix dirs)*/
strcpy(fn1b,fn1);                 /* presume no prefix directories     */
pp = strrchr(fn1,'/');            /* find last '/' (if any)            */
if (pp)
  { strcpy(fn1b,pp+1);            /* copy root filename after last '/' */
  }

/*Feb05/09 - common functions openfileX & closefileX for P,I,W,V,D files*/
/*         - chg P/I/W/V/D cmds to open & close output file on each cmd */
/*         - cmd line option w1 to write 1 combined file vs separate    */
/*         - filename format as follows:                                */
/* $UVTMPDIR/inputfilename_yymmdd_hhmmssX               <-- X=P/I/W/V/D */
/* $UVTMPDIR/inputfilename_yymmdd_ <-- basefilename + time + X each open*/

/* create basefilename now at prgrm init & when files opened on each cmd*/
/* - will copy to pfname,ifname,wfname,etc & append time + ID P/I/W/V/D */

/*May03/11 - provide $UVTMPDIR define subdir for print,write,drop,index,etc*/
strcpy(tmpdir,"tmp");          /* presume UVTMPDIR not specified */
pp = getenv("UVTMPDIR");
if (pp)
  { if (pp[0])
      { strcpy(tmpdir,pp);
      }
  }
/*May03/11 - create tmpdir at program init if not already present */
/* create tmp dir if not already present                             */
ss = stat(tmpdir,&tmpstat);
if (ss < 0)
  { sprintf(mkdirtmp,"mkdir %s",tmpdir);
    system(mkdirtmp);
  }

/*eject*/
/* create basefilename for P,I,W,V,A,C,D tmp files */
strcpy(basename,tmpdir);
strcat(basename,slashs);
strcat(basename,fn1b);
strcat(basename,"_");
strcat(basename,date6);
strcat(basename,"_");

/* create filename for Find Index file for findexsave() & findexload() */
strcpy(finame,tmpdir);         /* $UVTMPDIR or tmp              */
strcat(finame,"/uvhdindex_");  /* append Find Index prefix name */
strcat(finame,fn1b);           /* append uvhd input datafile    */

/*Jun12/07 - optn 'n' multi-recs/scrn fix restore fileptr to 1st on screen */
/*         - commands other than browse, rec#, byte# (write, print, etc)   */
/*         - not working try init cmd to blank (see test at end screen)    */
opcmd[0] = ' ';

/* setup iprint command default command to uvlp12       */
/* - override if export UVHDCOBPRINT=lp or uvlp12L, etc */
pp = getenv("UVHDCOBPRINT");
if (pp)
  { strcpy(prtcmd,pp);
  }

/* setup iprint cmd Wide/Landscape, default to uvlp12L          */
/* - override if export UVHDCOBPWIDE=lp or uvlp12L, etc         */
/* - does not apply to uvhdcob (only uvhd with wide line option */
pp = getenv("UVHDCOBPWIDE");
if (pp)
  { strcpy(prtcmdW,pp);
  }

/*eject*/
/*uvhdcob-------------------- open files ------------------------------*/
/* call subfunction to open file (also used by truncate command)       */
openfile();                   /* open file, store filesize, etc        */

/*May25/10 - major changes to getrec(), see dscrptns at begin getrec() */
fileptr1 = filesize;   /* init fileptr1, set (filesize-recsize) at EOF */
recnum1 = 1;           /* init record# for display */

fp2 = fopen(fn2d,"rb");         /* open cobmap file                */
if (fp2 == (FILE*)0)
  { errmsg("cant open cobmap file",fn2d,"",0,0x20);
  }

/* also get status of filename.idx, to test presence                     */
/* - will later add 1 to rcsz, if not spcfd via option 'r' on cmd line   */
strcpy(fn1i,fn1);
pp = strrchr(fn1i,'.');          /* find rightmost '.'       */
if (pp)
  { *pp = '\0';                  /* terminate to remove .dat */
    strcat(fn1i,".idx");         /* append .idx              */
    opstat = stat(fn1i,&fs1i);   /* will test status later   */
  }

/* save suffix, if '.dat' we will add 1 to mapsize */
pp = strrchr(fn1,'.');          /* find rightmost '.' */
if (pp)
  { strcpy(fn1x,pp);
  }

/*eject*/
/*Mar19/09 - if RCSZ=..... not found on 2nd line cobmap, errmsg/exit */
ll = getlin0(fp2,maprec,128,'\n',0x569);
ll = getlin0(fp2,maprec,128,'\n',0x569);

/* scan for RCSZ= & store following value in rcs */
pp = strstr(maprec,"RCSZ=");
if (!pp)
  { errmsg("RCSZ=... NOT found on 2nd line cobmap",fn2d,"",0,0x20);
  }
rszmap = atol2(pp+5,' ',5,0x01);

/*Feb24/11 - add option g# recsize extra bytes (for LF or CR/LF etc) */
/* if (opsi['g'-'a'])             */
/*   { rszmap += opsi['g'-'a']; } */
/* else                           */
/*Aug04/11 - option 'g' changed to group occurs (dont need old option g) */
    /* add 1 if ISAM file (if matching filename.idx present) */
    /* or if filename.dat suffix ? (filename.idx better)     */
    if (fs1i.st_size)
      { rszmap++;
      }
    else if (strcmp(fn1x,".dat") == 0)
      { rszmap++;
      }

/* allow option 'r' to override RCSZ= in cobmap                       */
if (opsi['r'-'a'])
  { rszmap = opsi['r'-'a'];
  }

/*May28/11 - store search progress message interval record count */
/*         - from option p default 1 million                     */
if (opsi['p'-'a'])
  { pmsgcnt = opsi['p'-'a'];
  }
else
  { pmsgcnt = 1000000;
  }

/*eject*/
/*uvhdcob------------------ read/store cobmap table ----------------------*/
/* read cobmap file recs, convert to MAPREC structs, store in table */
/* begin loop to get maprecs, reformat, store in table              */
while (1)
{
memset(maprec,' ',128);
ll = getlin0(fp2,maprec,128,'\n',0x569);
if (ll <= 0)
  { break;
  }
if (mti >= MAPMAX)
  { errmsg("cobmap table full",maprec,"",mti,0x21);
  }

maprw = maprz;     /* clear work structure */
                   /*Aug03/11 - moved up here to avoid dup */

/* if cobmap *TYPE def, reformat & store in type table                 */
/* *TYPE=0(1),='N','name-record'  <-- data records with 'N' in byte 0  */
/*                                                                     */
/*May20/10 - allow TYPE by record-size (for RDW, IDX, text)            */
/*         - identify alt format by maprec.lvl[0] == 'R' (vs 'T')      */
/* TYPE=99:999,'recname'    <-- alternate format for ID by recsize     */

if ((memcmp(maprec,"*TYPE=",6) == 0) || (memcmp(maprec,"*type=",6) == 0))
  { sncopy(maprw.des,maprec,60,0x03);
    /* store TYPE format T/R in 1st byte */
    if (strchr(maprec,':'))
      { maprw.lvl[0] = 'R';        /* identify type by Record-Size */
        ppp = atol1(&maprw.bgn,maprec+6,':',5,0x05);
        ppp = atol1(&maprw.end,ppp,',',5,0x05);
        ppp = spcopya(maprw.fnm,ppp+1,'\'',30,0x03);
        printf("%s \n",maprec);
      }
    else
      { maprw.lvl[0] = 'T';        /* identify type by record Type codes */
        ppp = atol1(&maprw.bgn,maprec+6,'(',4,0x05);
        ppp = atol1(&maprw.lth,ppp,')',2,0x05);
        maprw.cc[0] = *(ppp+1);

        /*Nov21/10 - allow Type Coding 'X' hex constants (default C char) */
        if (*(ppp+2) == '\'')      /* if type coding not specified */
          { maprw.tc[0] = 'c';     /* - default 'c' character      */
            ppp = spcopya(maprw.typ,ppp+3,'\'',15,0x07);
            ppp = spcopya(maprw.fnm,ppp+2,'\'',30,0x03);
          }
        else
          { maprw.tc[0] = *(ppp+2); /* store type coding specified */
            ppp = spcopya(maprw.typ,ppp+4,'\'',15,0x07);
            ppp = spcopya(maprw.fnm,ppp+2,'\'',30,0x03);
          }

/*eject*/
        /*9905 - display TYPE's as stored (user reminder multi type file) */
        printf("%s: bgn=%d,lth=%d,typ=%s,fnm=%s\n",
                maprw.des,maprw.bgn,maprw.lth,maprw.typ,maprw.fnm);
        /* validate condition code = ! < >                                 */
        cc = searchcm(maprw.cc,"=!<>",1,4,0x03);
        if (cc < 0)
           errmsg("*TYPE=dsp(lth),='RT',fldname <-ERR condition not =!<>"\
                    ,maprec,"",0,0x11);
        if (*ppp != '\'')
           errmsg("*TYPE=dsp(lth),c'RT?','fieldname' <-- format err ?"
                   ,maprec,"",0,0x21);

        /*Nov21/10 - lowercase type coding & convert type data to true hex*/
        maprw.tc[0] = tolower(maprw.tc[0]);
        if (maprw.tc[0] == 'x')
          { strcpy(w1,maprw.typ);      /* copy out to w/a */
            hex2data(maprw.typ,w1,'\0',16,0x03);
          }
        /*Apr04/11 - translate *TYPE codes to EBCDIC if option 'a' on cmd line*/
        /*         - do not translate *TYPEs coded in hex                     */
        else if (opsc['a'-'a'])
          { toebcdic2(maprw.typ,16,0x00);
          }
      }
    typtbl[tti++] = maprw;             /* store in type table & up index*/
    continue;                          /* return to get next line       */
  }

/*eject*/
/* *TYPE tested/stored in typtbl on prior page                      */
/* NOW test for level# lines & store in maptbl                      */
/* scan for level# - 1st 2 non-blank bytes                          */
for (ii=0; ii < 60; ii++)
  { if (maprec[ii] == ' ')
       continue;
    memcpy(ww,&maprec[ii],2);
    break;
  }

/*Aug03/11 - store *BGNOCCURS & *ENDOCCURS */
/**BGNOCCURSM:c-p:00012*00010=00120:00120-00239:1: */
/*Aug25/11 - *BGNOCCURS modified to add depending on field start,length,type*/
/*          1         2         3         4         5         6         7   */
/*01234567890123456789012345678901234567890123456789012345678901234567890   */
/**BGNOCCURSM:c-p:00024*00010=00240:00010-00249:1:00008:02pns               */
if ((memcmp(maprec,"*BGNOCC",7) == 0) || (memcmp(maprec,"*ENDOCC",7) == 0))
  { sncopy(maprw.des,maprec,60,0x03);  
    maprw.gocmax = atol2(maprec+16,'*',5,0x01); /* store occurs count   */
    maprw.goclth = atol2(maprec+22,'=',5,0x01); /* store group length   */
    maprw.gocnest = atol2(maprec+46,':',1,0x01); /* store nest level    */
    maprw.godps = atol2(maprec+48,':',5,0x01);  /* store DPO start byte */ 
    maprw.godpl = atol2(maprec+54,'~',2,0x01);  /* store DPO length     */
    sncopy(maprw.godpt,maprec+56,3,0x03);       /* store DPO type p/b/n */
    
    memcpy(maprw.lvl,"00",2);  /* prevent bypass no level# */
    maprw.lth = 1;             /* prevent bypass no length */
    /* store *BGN/ENDOCCURS in cobmap table, up index,& return to get next*/
    maptbl[mti] = maprw;         /* store in table & up index for next*/
    mti++;                       /* up cobmap table index for next   */
    continue;
  }

/* NOT *BGNOCCURS or *ENDOCCURS */
/* bypass any lines not starting with level#                        */
if (isdigit(ww[0]) && isdigit(ww[1]))
  { ; }
else
  { continue; }

/*eject*/
/* reformat cobmap record into MAPREC struct work rec prior to tbl store*/
memcpy(maprw.lvl,ww,2);

/* bypass lvl#, scan to next signif byte, store fldnm til blank/period*/
ii += 2;                    /* bypass level#                          */
for ( ; ii < 60; ii++)
  { if (maprec[ii] == ' ')
       continue;
    stmcopy(maprw.fnm,&maprec[ii],". ",30,0x03);
    break;
  }
/* store fld typ from byte 75 of cobmap record (new cobmap1 layout 9905)*/
stncopy(maprw.typ,&maprec[75],'\n',3,0x03);

/* scan for pic & store dscrptn until byte 59 of cobmap record        */
pp = strstr(maprec," pic ");
if (pp)
  { dd = (pp - maprec);               /* calc dsplcmnt to " pic "     */
    ll = (60 - dd);                   /* calc lth of dscrptn string   */
    if (ll > 0)
       sncopy(maprw.des,pp,ll,0x03);  /* store dscrptn in workrec     */
  }

/*Mar20/10 - store indicator if redefines present                     */
/*         - to inhibit verify on redefined fields                    */
if (strstr(maprec," redefines "))
  { maprw.rdf = 'r';
  }

/*eject*/
/*Dec27/10 - add option to show occurs o1 deflt, o2 all, o4 1st/1st err*/
/*        -  init occurs 1 in case no occurs for current field         */
maprw.occurs = 1;             
pp = strstr(maprec," occurs ");
if (pp)
  { oo = atol2(pp+8,'~',5,0x03);   /*May24/11 - chg 3 to 5 allow 0020 */
    maprw.occurs = oo;             /* store occurs value in maptblrec */
  }

/* convert fld lth, bgn, end dsplcmnts to integer                     */
/* - updated to new cobmap1 layout 990510                             */
maprw.bgn = atol2(maprec+60,'~',5,0x01);
maprw.end = atol2(maprec+65,'~',5,0x01);
maprw.lth = atol2(maprec+70,'~',5,0x01);


/* store current cobmap line in cobmap table if level# & non *comment */
if ((isdigit(maprw.lvl[0])) && (isdigit(maprw.lvl[1])) && (maprec[0] != '*'))
  { maptbl[mti] = maprw;         /* store in table & up index for next*/
    mti++;                       /* up cobmap table index for next   */
  }
/* else neither - continue while loop until break at cobmap file EOF */
}

/*eject*/
/*uvhdcob------------ end storing cobmap table -----------------------*/
/* end of cobmap file - save table entry count                        */
mtimax = mti;                    /* save cobmap table entry count     */
ttimax = tti;                    /* save cobmap TYPE table entry count*/

/* need to fix: mtibgntyp/mtiendtyp fields in typtbl                    */
/* for each entry in typtbl:                                            */
/* mtibgntyp - search maptbl for matching fieldname                     */
/*   onmatch - store maptbl index in mtibgntyp of current typtbl entry  */
/*                                                                      */
/* mtiendtyp - init to mtimax-1 in case nofind next typtbl fieldname    */
/*           - using fieldname of next typtbl entry                     */
/*             (*type's must be defined in sequence of start fieldnames)*/
/*           - find matching entry in maptbl & store its index -1       */

for (tt=0; tt < ttimax; tt++)
  { strcpy(ww,typtbl[tt].fnm);         /* save typ fldnam in case nofind */
    cc=0;                              /* reset found switch             */
    for (mm=0; mm < mtimax; mm++)
      { if (strcmp(typtbl[tt].fnm,maptbl[mm].fnm) == 0)
          { typtbl[tt].mtibgntyp = mm;
            cc++;                      /* set found switch               */
          }
      }

    /* display errmsg if type fieldnmae not found in maptbl              */
    if (cc == 0)
      { printf("*TYPE fieldname \'%s\' nofind in cobmap (enter=continue)",ww);
        uvfgets(ww,80);
      }

    /* now find/store mtiendtyp, using fieldname from next typtbl entry  */
    /* - must search down typtbl to next fieldname different from current*/
    /* - to allow multi data type defs for same record definition        */
    typtbl[tt].mtiendtyp = mtimax-1;     /* in case nomatch & last entry */
    for (ss=tt+1; ss < ttimax; ss++)
      { if (strcmp(typtbl[ss].fnm,typtbl[tt].fnm) != 0)
          { break;
          }
      }
    if (typtbl[ss].fnm[0])    /*Aug23/11 add [0] if any folwng *type */
      { for (mm=0; mm < mtimax; mm++)
          { if (strcmp(typtbl[ss].fnm,maptbl[mm].fnm) == 0)
              { typtbl[tt].mtiendtyp = mm-1;
              }
          }
      }

     /* debug 991018 & 001026                                            */
if (opsi['d'-'a'])
  {printf("debug typtbl: tt#=%d typdata=%s typfnm=%s mtibgn=%d mtiend=%d\n"
   ,tt,typtbl[tt].typ,typtbl[tt].fnm,typtbl[tt].mtibgntyp,typtbl[tt].mtiendtyp);
  }

 }

/*eject*/
/*uvhdcob------------------- uvhdcob inits ---------------------------*/
/*Jan29/09 - init all recsizes to map RCSZ in case used before inited */
/*Mar19/09 - if rszmap not stored, default to 256 to prevent core dump*/
if (rszmap < 1)
  { rszmap = 256;
  }

/*Jun04/10 - calc rszo from optn r or dflt 256 or rszmap if FIXED */
rszo = opsi['r'-'a'];
if (rszo <1 || rszo > RMAX)
  { rszo = RDFLT;
  }
/* calcs for variable length text records (option 't') */
chkrcsz(rszo);

/* store record data address = base adrs for fixed                    */
recd = recb;                   /* presume fixed recs (same address)   */

/* setup rszop in case of exit to uvhd                                 */
sprintf(rszop,"r%d",rszmap);


/*eject*/
/*Dec2004 - test option 'v' Micro Focus COBOL IDXFORMAT3/8 records     */
/*Jan26/09 - option 'x' IDXFORMAT8 combined with option 'v' IDXFORMAT3 */
if (opsc['v'-'a'])
  { ftype = 'v';
    /* v options: v1=filehdr,v2=deleted,v4=active data,v8=all (dflt=v5)*/
    /* - default to v5 if not explicit                                 */
    if (opsi['v'-'a'] == 0)
        opsi['v'-'a'] = 5;

/* - read file prefix (1st 128 bytes) to get max rcsz, min rcsz, etc   */
/* - will read remainder of file header later, depending on header size*/
/* - verify file is IDXFORMAT_ (1st 4 bits 0x30)                       */
/* - store max rcsz, min rcsz, file header size                        */

    rsz1 = read(fd1,vfhdr,128);          /* read 1st 128 of file       */

    /* verify file hdr rec valid                                       */
    if ((vfhdr[0] & 0xF0) == 0x30)
      { ;
      }
    else
      { errmsg("file header invalid (1st 4 bits not 0x30)",fn1,"",0,0x40);
      }
    /* store max rcsz, min rcsz                                       */
    vrmax = switchb(vfhdr+54,1);        /* store max rcsz             */
    vrmin = switchb(vfhdr+58,1);        /* store min rcsz             */

    /* store rec hdr size vrhs=4 if macrcsz > 4095, else vrhs=2       */
    /* store indicator vr4k = 1 if maxrcsz > 4095, else vr4k = 0      */
    /*Mar19/08 - uxcopy rcs=4095 creates 4 byte rechdr, rcs=4094 2 bytes*/
    /* - so change test below from (vrmax > 4095) to (vrmax >= 4095)  */
    if (vrmax >= 4095)
      { vrhs = 4;
        vr4k = 1;
        wrhs = 4;
      }
    else
      { vrhs = 2;
        vr4k = 0;
        wrhs = 2;
      }

    /* store record data adrs depending on prefix size */
    recd = recb + vrhs;

/*eject*/
    /* call switchb to calc slot size of file header record            */
    switchb(vfhdr,vr4k);                   /* calc slsot size of header*/
    vfhs = vrslot;                         /* save file header size    */

    /* call subfunctn to check rcsz & calc number of records in file   */
    /* set rcsz = min rcsz for ISAM IDXFORMAT3/8                       */
    /*Jun20/07 - changed to max recsize, varlth files often all max    */
    rszo = vrmax;
    chkrcsz(rszo);

    /* reset ptr = 0 in case filehdr rec display desired (option v1)   */
    fileptr = 0;

    /* read any remaining size of file header (128 read above)         */
    vfxtra = (vrslot - 128);               /* calc size yet to be read */
    if (vfxtra > 0)
      { rsz1 = read(fd1,vfhdr+128,vfxtra); /* read remainder of header */
      }
  }

/*eject*/
/*Jul02/07 - store write record hdr size for file type z         */
/*Nov05/07 - save RDW rechdrsize from option z & verify 0,2,4,8  */
/* - optn z value is extra bytes reqd to reach begin next rec    */
/*Sep09/08 - provide option z1 for little-end RDW                */
/* z2=2bytehdr, z4=4bytehdr, z8=8bytehdr, z0 deflt z4,           */
/*May19/10 - change optn z8 to BDW/RDW, bypass BDW in getrdw1()  */
/*         - BDW/RDW 4+4, BDW bypasswd, else like z4             */
/* - remove prior z# considered lth of hdr                       */
else if (opsc['z'-'a'])
  { ftype = 'z';
    if (opsi['z'-'a'] == 0)
      { opsi['z'-'a'] = 4;
      } 
    /* validate option z & set rdwhs = RDW hdr size             */
    /*Sep09/08 - also set rdwhx = extra bytes for total recsize */
    if (opsi['z'-'a'] & 0x02)
      { rdwhs = 2; 
        rdwhx = 2; 
      }
    else if (opsi['z'-'a'] & 0x04)
      { rdwhs = 4; 
        rdwhx = 0; 
      }
    else if (opsi['z'-'a'] & 0x08)
      { rdwhs = 4;                 /*May17/10 - chg from 8 to 4 */
        rdwhx = 0; 
      }
    /*May17/10 - change optn z8 to BDW/RDW, bypass BDW in getrdw1() */
    /*         - BDW/RDW 4+4, BDW bypasswd, else like z4            */
    else
      { errmsg("valid option z=z2,z4,z8(big-end) or z3,z5,z9(little-end)"
               ,opsu,"",0,0x21);
      }

    /* store record data adrs depending on prefix size */
    recd = recb + rdwhs;

    wrhs = 2;   /* wrhs used to offset translates etc */
  }

/*eject*/
else if (opsc['t'-'a'])
  { ftype = 't';
  }
else
  { ftype = 'f';
    /*Jun04/10 - set rszo=rszmap for FIXLTH only (dflt RDFLT above)      */
    rszo = rszmap; 
    /* calcs for fixed lth records only                                   */
    /* call subfunctn to check rcsz & calc number of records in file      */
    /* - also called by command 'R' (change rcsz w/o quit & cmd line optn */
    chkrcsz(rszo);

    /* test option for first record to be displayed                   */
    /*Jan10/11 - option f# changed to b# rec# begin display           */
    /*         - because optn f0 now used to inhibit find index build */
    /* calc fileptr using option f value & spcfd rcsz                 */
    fileptr = opsi['b'-'a'] - 1;   /* option f rec# -1 for 0 relative */
    if (fileptr < 0)
      { fileptr = 0;
      }
    fileptr *= rszo;               /* calc initial ptr = rec# * rszo   */
    /* could allow begin display optn for all types by using findrec() */

    /*May25/10 - for fixed length we can set ptr to last rec at prgm init  */
    /*         - to cause EOF msg on 1st time displayed                    */
    fileptr1 = (filesize - rszo);
  }

/*Oct08/11 - edit fileptr1 for printf's %ld or %lld for 64/32bit HP gcc */
sprintf(fpedit1e,E64,fileptr1);

/*Jun01/10 - calc recsize to clear at begin each rec */
rszox = (rszo + 256); /*May21/10 - recsize to clear at begin each rec */
rszoy = (rszo + 128); /*May22/10 - bufsize to read at begin each get  */
rsz1 = rszo;
rsz2 = rszo;
rsz1p = rszo;

/*eject*/
/*Apr29/11 - simplify f1 dflt build varlth, f0 no build, f2 force build  */
if ((ftype != 'f') && (!(opsc['f'-'a'])))
  { opsc['f'-'a'] = 'f';     /* default f1 build index for varlth */
    opsi['f'-'a'] = 1;
  }
if (opsi['f'-'a'] & 0x01)    /* build index ? (varlth default) */
  { findex();                /* - will force rebuild if f2(f3) */
  }

/*May03/11 - fix 'f0' (inhibit build index), set fii1=3 vs fii1=2 if Index */
/*         - so getrdw won't assume Index, so findrec won't assume Index*/
if ((opsc['f'-'a']) && (opsi['f'-'a'] == 0))
  { fii1 = 3;
  }

fileptr = 0;       /* restore fileptr to begin file       */
recnum1 = 1;       /* init rec# for 1st rec in file       */
upnext = 0;        /* inhibit pre-increment to get 1st rec*/

/*May28/11 - search op max check based on max recsz not current recsize*/
rcsmax = rszo;
if ((ftype != 'f') && (rdwmax))
  { rcsmax = rdwmax;
  }

/*eject*/
/*uvhdcob------------------- begin record -----------------------------*/
/* get next sequential record - or depending on fileptr                */

bgnrec:

rsz1 = getrec(0);                     /* get next record              */

if (rsz1 <= 0)                        /* error or EOF ?            */
  { /*Nov11/07 - set fileptr1 back to filesize(EOF)                */
    /* - to reread last record after empty prompt at endscreen     */
    /* - see logic in getcalc1 (before get) & getcalc2 (after get) */
    /* fileptr1 = filesize; Nov11/07 - to cause reread last record */
    /*May19/11 - disable above (not in uvhd)                       */
    /*Jan29/09 - confusion, I thought fileptr1 was begin last record ? */
    goto endscreen;
  }

recdmatch = 0;   /* reset search matched field dsplcmnt */
recdmatchb = 0;  /* reset copy for bold insert test     */
mtimatch = 0;    /* reset maptbl index to matched field */         

/* return point to display found record on search */
bgnsmatch:

/*Sep03/11 - add subrtn lookmap to find maptbl index for matched field */
/*         - to show search match field on 1st screen of long records  */
/*         - search match stores recdmatch, else 0                     */
if (recdmatch)
  { ; /* mtimatch = lookmap(recdmatch); Sep03/11 move to search ? */
  }

screenctr = 0;            /* init screen ctr for current record */
fldctr = 1;               /* reset field counter for new record */

/* output screen header - filenames, rec count, cur rec#, dates, etc  */
printf(" \n");      /* write blank line to separate from prior screen */

/*Jun05/10 - show datafilename,copybookname,date,options only at begin file*/
if (fileptr <= 0)
  { printf("now=%s uvhdcob %s %s\n",todttm,fn1,opsu);
    printf("version=%s copybook=%s \n",uvversion,fn2d);
  }
printf("rec#=%d rcount=%d rsize=%d fsize=%s fptr=%s\n"
       ,recnum1,rcount,rsz1,fsedit,fpedit1);

/* output field titles: rec#, fieldname|*deleted*,bgn end typ,field-data*/
/*Dec24/10 - inhibit field titles if EOF (rsize 0) */
if (rsz1 > 0)
  { printf("rec#%8d %9s occurs  bgn end typ",recnum1,fnmflag);
    printf("<------ data (hex if typ=p/b) ----->\n");
  }

/* extra space if option s2                                             */
if (opsi['s'-'a'] & 0x02)
  {  printf("\n");
     linectr++;
  }

/*eject*/
/*uvhdcob---------------- test record *TYPE ----------------------------*/
/**TYPE=0(1),='N','name-record'  <-- data records with 'N' in byte 0    */
/* if *TYPE table entries stored from begining of cobmap                */
/* - test current data record to *TYPE defs for match                   */
/* - if match, advance up cobmap table for matching fieldname           */
/*   to determine 1st cobmap field to be displayed                      */

/*Jan29/09 - allow record type testing for EBCDIC input                 */
/*         - copy 1st 256 bytes to alt area for testing (max 256)       */
/*         - translate to ASCII if input is EBCDIC                      */
/*Apr04/11 - disable, *TYPE codes now trnsltd to EBCDIC if optn 'a' */
/*         - but not if coded in hex     */
/* memcpy(recda,recd,256);               */
/* if (opsc['a'-'a'])                    */
/*   { toascii2((Uchar*)recda,256,0x00); */
/*   }                                   */

/* init mtibgn = 0 & mtiend = mtimax, assuming no TYPE's present        */
mtibgn = 0;
/* Oct00 - getting extra field blank 0 0 bgn end at end single types    */
/*       - try change: mtiend=mtimax to: mtiend=mtimax-1;               */
mtiend = mtimax-1;

/*eject*/
/* test R/T by code OR (May20/10) by rec-size (RDW,IDX,text) */
if (ttimax)
  { /* set mtibgn/end to bgn/end of 1st type def, in case of nomatch    */
    /* ie - if nomatch, default display to 1st type defined             */
    mtibgn = typtbl[0].mtibgntyp;
    mtiend = typtbl[0].mtiendtyp;

    /* search typtbl for match to current data record                  */
    for (tti=0; tti < ttimax; tti++)
      { typrw = typtbl[tti];          /* move current tbl entry to w/s */

        /*May20/10 - allow TYPE by record-size (for RDW, IDX, text)        */
        /*         - identify alt format by maprec.lvl[0] == 'R' (vs 'T')  */
        /* *TYPE=0(1),='X','recname' <-- original format ID by recType code*/
        /* *TYPE=99:999,'recname'    <-- alternate format ID by Recsize    */
        if (typrw.lvl[0] == 'R')
          { if ((rsz1 >= typrw.bgn) && (rsz1 <= typrw.end))
              { mtibgn = typrw.mtibgntyp;
                mtiend = typrw.mtiendtyp;
                break;
              }
          }
        else
          { /*Apr04/05 - disabled recda, type codes now EBCDIC if 'a' */
            /* cc = memcmp(recda+typrw.bgn,typrw.typ,typrw.lth);      */
               cc = memcmp(recd+typrw.bgn,typrw.typ,typrw.lth);
            if (((typrw.cc[0] == '=') && (cc == 0))
                || ((typrw.cc[0] == '!') && (cc != 0))
                || ((typrw.cc[0] == '<') && (cc < 0))
                || ((typrw.cc[0] == '>') && (cc > 0)))
              { /* RT match - store mtir index for bgn/end display         */
                mtibgn = typrw.mtibgntyp;
                mtiend = typrw.mtiendtyp;
                break;
              }
          }
      }

   if (tti >= ttimax)
     { errmsg("data rec type NOmatch to cobmap *TYPEs - use 1st cobmapdef"
              ,typrw.des,"",0,0x111);
     }
  }

/*eject*/
/* current data record has been matched to an entry in record type table */
/*        - or the mandatory unidentified entry at the end of copybookmap*/
/* mtibgn - points to 1st cobmap entry for identified type               */
/* mtiend - points to 1st cobmap entry for identified type               */
/* mtir   - pointer incremented from mtibgn to mtiend                    */
/*          to display cobmap & data fields in current record type       */

mtir = mtibgn;        /* init mtir to mtibgn, 1st field to display     */
mtib = 0;             /* init mtib 0 in case of partial rec redef      */

/* mtib/mtir used to show base(key) fields till we reach redef type    */
/* store dsp of 1st signif redef fld by advance mtir to 1st with lth   */
while ((mtir < mtimax) && (maptbl[mtir].lth == 0))
  { mtir++;
  }
mtir1dsp = maptbl[mtir].bgn;   /* store dsp of 1st redef fld with lth  */

/* 991018 - print debug info                                            */
   if (opsi['d'-'a'])
     { printf("debug testRT: mtibgn=%d mtiend=%d mtimax=%d mtir=%d dsp=%d\n"
        ,mtibgn,mtiend,mtimax,mtir,mtir1dsp);
     }

/*Aug06/11 - init all item occurs controls (not just ooii) */
oonn=0; ooii = 0; ooff=0; ooee=0; oozz=0;

/*Aug03/11 - init group occurs control fields */
/*Sep26/11 - allow nested group occurs 2 levels only */
/*Sep26/11 - clear using grp occurs zero structure */
goc1 = goc0;
goc2 = goc0;
godpb=0; godpl2=0; goffcor1=0; goffcor2=0; 
/*Aug26/11 - clear total record offset for depending on corrections */

/*eject*/
/*uvhdcob-------------------begin screen-------------------------------*/
bgnscreen:

/* Oct00 - getting all fields displayed for multi type files at EOF    */
/*       - try test for fileptr >= filesize here at bgnscreen          */
if (fileptr >= filesize)
   goto endscreen;

screenctr++;                 /* count screens for current record */
linectr = 0;                 /* init screen line counter         */

/*uvhdcob---------------- begin line -----------------------------------*/
bgnline:
recdend=0;  /*Sep02/11 ensure end field reset for null reply EOS/EOR test*/
/* begin each field format for display(printf)                           */
/* fieldname--------occurs->  bgn end typ<----data (hex if typ=p/b)--->  */
/*        30                     +11        +1      +36            = 78  */
/* current field depends on mtir index into cobmap MAPREC maptbl         */
/* - move current entry to work area for easy access                     */
/* - retrieve data from current record depending on cobmap dsplcmnt & lth*/

/* allow for partial redef record types which omit base(key) fields       */
/* - mtir index points to 1st field in current type (if any)              */
/* - mtib index (init 0) used to display base/key flds til dsp => mtir1dsp*/
/* - mtir1dsp (dsp of 1st redef fld with length) stored above             */
/*Aug13/11 - remove code to display base fields to partial redef records  */
/* - see old solution in versions prior to Aug03/2011                     */
/* - old code used mtibi/mtiri 1/0 or 0/1 to inc base or redef (kludgy)   */
/* - recode use mtir only from 0 base & chg mtir to redef after base fld cnt*/

/* get field from record base(key) until dsp => 1st redef field          */
/* - 1st bypass any 0 lth fields in base record                          */
/*Aug13/11 - remove code to display base fields to partial redef records  */
/* get field from redef record (only rec if no redef types present)  */
/* 1st bypass any 0 lth fields in redef record                       */
while ((maptbl[mtir].lth == 0) && (mtir < mtiend))
  { mtir++;
  }
maprw = maptbl[mtir];        /* store redef/rec field to be displayed*/

/* display 36 bytes max per field, 18 bytes if packed/binary (36 chars)  */
flth1 = maprw.lth;               /* presume fld lth = actual             */
if (flth1 > 36)
    flth1 = 36;                  /* field data retrieve 36 bytes max     */
flth2 = flth1;                   /* presume display lth same as retrieve */

/* if packed/binary - display lth 2 * field length max 36 bytes          */
if ((maprw.typ[0] == 'p') || (maprw.typ[0] == 'b'))
  { flth2 *= 2;                  /* hex display lth = 2 * fldlth         */
    if (flth2 > 36)
        flth2 = 36;              /* p/b display lth 36 bytes max         */
  }

/*eject*/
/*Aug03/11 - test for *BGNOCCURS & store/init Grp OCCurs controls */
/*Aug04/11 - store option g max group occurs desired */
/*Sep26/11 - allow nested group occurs (2 levels only) */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest == 1))
  { goc1.max = maprw.gocmax;   /* occurs count */
    goc1.max1 = goc1.max;      /* save orig to edit in case odo 1 */
    goc1.lth = maprw.goclth;   /* occurs group set total length */
    goc1.ctr = 0;              /* init index for 1st set        */
    goc1.end = opsi['g'-'a'];  /* store group end dsired from optn g */
    /*Aug25/11 - get depending on count if specified */
    /*         - to override max count on *BGNOCCURS */
    if (maprw.godpl)          /* dpo count from *BGNOCCURS on table load ? */
      { godpl2 = maprw.godpl; /* store fld lth in shorter symbol */
        memset(godpc,'\0',12);
        memcpy(godpc,recd+maprw.godps,godpl2);
        /* test dpo data type: packed, binary, numeric */
        /* if packed - retrieve right adjusted into zero filled work area   */
        /*      - then unpack & convert to common format (binary int)       */
        if (maprw.godpt[0] == 'p')             /* dpo count field packed ?  */
          { memset(w2,'\0',21);                /* null fill packed retrieve */
            memcpy(&w2[20-godpl2],godpc,godpl2);
            unpack(w3,w2,0x01);                /* unpack signed (ascii zones)*/
            godpb = atoi(w3);                  /* convert to integer         */
          }
        else if ((maprw.godpt[0] == ' ') && (maprw.godpt[1] == 'n'))
          { godpb = atol2(godpc,'~',8,0x01);
          }
        else /* assume binary 2,4,or 1 */
          { if (godpl2 == 2)                     /* binary short ?         */
              { memcpy((Uchar*)&godpb2,godpc,2); /* retrieve to short w/a  */
                if (LEM)
                  { bswap2((Uchar*)&godpb2);     /* switch big/little ends */
                  }
                godpb = godpb2;                  /* store in common 32 bit int*/
              }
            else if (godpl2 == 4)
              { memcpy((Uchar*)&godpb,godpc,4);  /* assume 4 byte int  */
                if (LEM)
                  { bswap4((Uchar*)&godpb);      /* switch big/little ends */
                  }
              }
            else /*Sep01/11 - assume 1 byte binary pic x */
              { godpb = godpc[0];
              }
          }
        /* validate depending on count retrieved from dpo field */
        if ((godpb > goc1.max) || (godpb < 0))
          { errmsg("occurs depending on field retrieved > max(to) or negative"
                   ,maprw.des,"",0,0x21);
          }
        /* - replace *BGNOCCURS count (max assumed)    */
        goc1.max = godpb;         /* replace max assumed with dpo actual */
      }

/*eject*/
    /*Aug21/11 - convert occurs options g99/o99 to g99999/o99999 */
    if (goc1.end == 99)
      { goc1.end = 99999;
      }
    if (goc1.end > goc1.max)
      { goc1.end = goc1.max;
      }
    if (goc1.end < 1)
      { goc1.end = 1;
      }
    goc1.mti = mtir;         /* save index to *BGNOCCURS for next loop */
    fldctr1 = fldctr;        /* save field ctr of 1st field in group occurs */
    goto nextfield;          /* go increment maptbl index to next field */
  }

/*Aug03/11 - test for *ENDOCCURS */
/* - increment grpoccurs ctr & reset to 1st field in group */
/* - if max occurs, clear grpoccurs controls & continue to next field */
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest == 1))
  { goc1.ctr++;               /* increment grp occurs ctr */
    if (goc1.ctr >= goc1.end) /* end count ?              */
      { /*Aug26/11 - calc record dsplcmnt offset for folwng fields */
        /* - significant only when depending on count < occurs to max */
        if (maprw.godpl)
          { goffcor1 = ((maprw.gocmax-godpb) * goc1.lth);
            goffcor2 += goffcor1;
          }
        goc1 = goc0;    /* clear GOC1 structure */
        godpb=0; 
        /*Sep26/11 - not sure about godpb (in structure or not ?)  */
        goto nextfield; /* go increment maptbl index to next field */
      }
    else
      { mtir = goc1.mti;  /* reset maptbl index to *BGNOCCURS */
        /*Aug04/11 - restore saved fieldctr on 1st field of group occurs*/
        fldctr = fldctr1;
        goto nextfield; /* go increment maptbl index to next field */
      }
  }

/*eject*/
/*Sep26/11 - add 2nd level nested group occurs */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest == 2))
  { goc2.max = maprw.gocmax;   /* occurs count */
    goc2.max1 = goc1.max;      /* save orig to edit in case odo 1 */
    goc2.lth = maprw.goclth;   /* occurs group set total length   */
    goc2.ctr = 0;              /* init index for 1st set          */
    goc2.end = opsi['g'-'a'];  /* same optn as goc level 1 */
    if (goc2.end > goc2.max)
      { goc2.end = goc2.max;
      }
 /* goc2.end = goc2.max;   might show all occurrences of level 2 */
    goc2.mti = mtir;      /* save index to *BGNOCCURS for next loop */
    fldctr2 = fldctr;     /* save field ctr of 1st field in group occurs */
    goto nextfield;       /* go increment maptbl index to next field */
  }

/*Sep26/11 - add 2nd level nested group occurs */
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest == 2))
  { goc2.ctr++;               /* increment grp occurs ctr */
    if (goc2.ctr >= goc2.end) /* end count ?              */
      { /*Aug26/11 - calc record dsplcmnt offset for folwng fields */
        /* - significant only when depending on count < occurs to max */
        if (maprw.godpl)
          { /*Sep27/11 - godpb N/A to 2nd level nested occurs */
            /* goffcor1 = ((maprw.gocmax-godpb) * goc2.lth); */
            goffcor1 = ((maprw.gocmax) * goc2.lth); 
            goffcor2 += goffcor1; 
          }
        goc2 = goc0;    /* clear GOC2 structure */
        goto nextfield; /* go increment maptbl index to next field */
      }
    else
      { mtir = goc2.mti;  /* reset maptbl index to *BGNOCCURS */
        /*Aug04/11 - restore saved fieldctr on 1st field of group occurs*/
        fldctr = fldctr2;
        goto nextfield; /* go increment maptbl index to next field */
      }
  }

/*Sep27/11 - errmsg if group occurs nested > 2 */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest > 2))
  { errmsg("group occurs nested > 2 levels unsupported",maprw.des,"",0,0x11);
  }
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest > 2))
  { errmsg("group occurs nested > 2 levels unsupported",maprw.des,"",0,0x11);
  }

/*eject*/
/*Aug03/11 - calc group occurs offset (0 if *BGNOCCURS not stored) */
goc1.off = (goc1.lth * goc1.ctr);
goc2.off = (goc2.lth * goc2.ctr);
/*Sep26/11 - not sure about offset calc for 2nd level nested occurs */
goctoff = (goc1.off + goc2.off);
/*         - try add together in goctoff & use that below           */

/* get occurs value from current maptbl rec */
oonn = maprw.occurs;   

/*Aug04/11 - store item occurs end count from option 'o' */
ooee = opsi['o'-'a'];
/*Aug21/11 - convert occurs options g99/o99 to g99999/o99999 */
if (ooee == 99)
  { ooee = 99999;
  }
if (ooee > oonn)
  { ooee = oonn;
  }
if (ooee < 1)
  { ooee = 1;
  }

/* calc occurs offset = (current occurs index * field length) */
ooff = (ooii * maprw.lth);

/* retrieve data from record, depending on cobmap dsplcmnt & occurs index*/
/* init retrieve area to all blanks                                      */
/* after data insert, scan back form right & insert null after nonblank  */
memset(fdat1,' ',50);               

/*Aug03/11 - calc group occurs offset above (as well as item occurs offset) */
/*Aug26/11 - calc total record offset including dpo correction occurs < max */
recdoff = (maprw.bgn-goffcor2+goctoff+ooff);
if ((maprw.bgn-goffcor2) < 0)
  { errmsg("occurs depending on field correction error",maprw.des,"",0,0x21);
  }
/*Sep02/11 - calc end field dsplcmnt for null reply EOS/EOR test */
recdend = (maprw.bgn-goffcor2+goctoff+ooff+maprw.lth+rdwhs);
/*Aug22/11 - test end record when occurs depending on & varlth records */
if (recdoff >= rsz1)
  { mtir = mtiend+1;   /* to force end screen */
    goto endscreen;
  }
sncopy(fdat1,recd+recdoff,flth1,0x00);  /* retrieve record field data */

/* copy data to display area - in case not binary/packed              */
/* (if binary/packed fdat2 will be overwritten with hexcodes          */
memcpy(fdat2,fdat1,50); 
/* ensure printable chars - translate any unprintables to '.' periods */
/* - can't do here if EBCDIC, but toascii2 0x04 will do below         */

/*Feb25/11 - clear hex for bad fields > 9 bytes on 2nd line */
memset(fdat4,'\0',40);               

/*eject*/
/* if packed - convert to horizontal hex display */
/* - verify & flag on right if bad digits/sign   */
if (maprw.typ[0] == 'p') 
  { data2hex(fdat2,fdat1,flth2,0x00);
    /*Jan10/11 - optn x1/x2/x4 inhibit validity check num/pack/char fields*/
    if (!(opsi['x'-'a'] & 0x02) || (opcmd[0] == 'v'))
      { ss = verifyp(fdat1,flth1,0x00);
        if (ss)
          { strcpy(fdat2+30,"<-BadP");
          }
      }
    sigval = testnp(fdat1,flth1); /*test inhibit display zero occurs fields*/
  }
else if (maprw.typ[0] == 'b') 
  { /* if binary - convert to horizontal hex display */
    /*           - show decimal value on right side  */
    data2hex(fdat2,fdat1,flth2,0x00);
    showdcmls(fdat2,fdat1,flth1);
    sigval = testnb(fdat1,flth1); /*test inhibit display zero occurs fields*/
  }
else if (maprw.typ[1] == 'n') 
  { /* if numeric data, test option 'a' translate EBCDIC to ASCII      */
    /* - bit 0x04 converts non-printable EBCDIC chasr to periods       */
    if (opsc['a'-'a'])                /* option 'a' (EBCDIC to ASCII)  */
      { toascii2((Uchar*)fdat2,flth1,0x04); /* translate EBCDIC to ASCII*/
      }
    /* replace unprintables with '.'s*/
    toprint2((Uchar*)fdat2,flth1,trtprint,0x00); 
    /* check chardata (in fdat1) for nonnumerics & show hex on right   */
    /* - will store fdat2 to print, will test fdat1 for nonnumerics    */
    /*Jan10/11 - optn x1/x2/x4 inhibit validity check num/pack/char fields*/
    if (!(opsi['x'-'a'] & 0x01) || (opcmd[0] == 'v'))
      { badn2hex(fdat2,fdat1,flth1);
      }
    sigval = testnn(fdat2,flth1); /*test inhibit display zero occurs fields*/
  }
else
  { /* if char data, test option 'a' translate EBCDIC to ASCII display */
    /* - bit 0x04 converts non-printable EBCDIC chasr to periods       */
    if (opsc['a'-'a'])                /* option 'a' (EBCDIC to ASCII)  */
      { toascii2((Uchar*)fdat2,flth1,0x04); /* translate EBCDIC to ASCII*/
      }
    toprint2((Uchar*)fdat2,flth1,trtprint,0x00); 
    /* check chardata (in fdat1) for unprintables & show hex on right  */
    /* - will store fdat2 to print, will test fdat1 for unprintables   */
    /*Jan10/11 - optn x1/x2/x4 inhibit validity check num/pack/char fields*/
    if (!(opsi['x'-'a'] & 0x04) || (opcmd[0] == 'v'))
      { bad2hex(fdat2,fdat1,flth1);
      }
    sigval = testnc(fdat2,flth1); /*test inhibit display zero occurs fields*/
  }

/*eject*/
/*Sep04/11 - calc record data begin/end */
/* - use on screen for begin/end (+1 below if option c1) */
bb = (maprw.bgn + goctoff + ooff - goffcor2);
ee = (maprw.end + goctoff + ooff - goffcor2);

/*Sep03/11 - add subrtn lookmap to find maptbl index for matched field */
/*         - to show search match field on 1st screen of long records  */
/*Sep04/11 - show search match on 1st screen problem fix for occurs    */
/*         - change maptbl index to data dsplcmnt corrected for occurs */
if ((recdmatch) && (linectr >= 16))
/*{ if (mtir < mtimatch) */
  { if (bb < recdmatch)
      { goto nextfield;
      }
    else
      { /* printf("\n"); space between 1st 15 & match field */
        /* linectr++;    disabled when bold added */
        recdmatch = 0;     /* reset field bypass */
      }
  }

/*Aug13/11 - test option i4 to inhibit display of ALL 0/blank fields */
if (opsi['i'-'a'] & 0x04)
  { if (!sigval)
      { goto nextfield;   /* go increment maptbl index to next field */
      }
  }

/*Aug04/11 - test option to bypass zero/blank occurs fields after 1st  */
/*         - if option v1+ coded on last g/o cmd for group/item occurs */
/*Aug13/11 - occurs optn v1 chgd to optn 'i', can set via cmd 'i'      */
if ((goc1.ctr > 0) && (opsi['i'-'a'] & 0x02))
  { if (!sigval)
      { goto nextfield; /* go increment maptbl index to next field */
      }
  }
if ((ooii > 0) && (opsi['i'-'a'] & 0x01))
  { if (!sigval)
      { goto nextfield; /* go increment maptbl index to next field */
      }
  }

/* zero suppress dsplcmnt & length for display          */
/*Feb24/11 - change optn 'g' (0/1 relative) to optn 'c' */
if (opsi['c'-'a'] & 0x01)
  { uvedit(zbgn,4,bb+1,"zzz9",0x02);
    uvedit(zend,4,ee+1,"zzz9",0x02);
  }
else
  { uvedit(zbgn,4,bb,"zzz9",0x02);
    uvedit(zend,4,ee,"zzz9",0x02);
  }
uvedit(zlth,4,maprw.lth,"zzz9",0x02);

/*eject*/
/*Dec27/10 - removed option 'n' inhibit seq# field on left of screen */
memset(fldnam,' ',30);
sprintf(ww,"%03d",fldctr);
memcpy(fldnam,ww,3);
sncopy(fldnam+4,maprw.fnm,30,0x01);

/* insert occurs counters: currentoccurs/maxoccurs       */
/*Sep27/11 - prioritized: item, grouplevel2, grouplevel1 */
if (oonn > 1)
  { sprintf(ww," %d/%d ",ooii+1,oonn);
    ll = strlen(ww);
    bb = 30 - ll;
    memcpy(fldnam+bb,ww,ll);
  }
else if (goc2.max > 1)
  { sprintf(ww," %d/%d ",goc2.ctr+1,goc2.max);
    ll = strlen(ww);
    bb = 30 - ll;
    memcpy(fldnam+bb,ww,ll);
  } 
else if (goc1.max1 > 1)
  { sprintf(ww," %d/%d ",goc1.ctr+1,goc1.max);
    ll = strlen(ww);
    bb = 30 - ll;
    memcpy(fldnam+bb,ww,ll);
  } 

fldnam[30] = '\0';      /* set fieldname length = 30 */

/*eject*/
/*Dec28/10 - insert 'Bad@ 1234' if verify stored err dsplmcnt beyond occurs*/
/* - if current field ocurs & not showing all occurrences                  */
/* - do not override any errmsg already stored for current record          */
if ((v2dsp) && ((fdat2+30)[0] == ' ')
            && (maprw.occurs > 1) && (opsi['o'-'a'] < 2))
  { oozz = (maprw.bgn + (maprw.occurs * maprw.lth));
    if ((v2dsp >= maprw.bgn) && (v2dsp <= oozz))
      { sprintf(w4,"Bad@ %04d ->",v2dsp);
        strcpy(fdat2+24,w4);
        v2dsp = 0; 
      }
  }
/*Dec28/10 - tried clear v2dsp here (strange results when abcdef used) */
/* v2dsp = 0; */

/* now scan back from right & insert null after last non-blank */
for (ii=40; ii > 1; ii--)
  { if (fdat2[ii] != ' ')
      { break;
      }
  }
fdat2[ii+1] = '\0';         /* insert null after last non-blank */

/*Sep03/11 - insert bold control codes if search match field */
/*Sep04/11 - fix bold test dsplcmnt to include occurs corrections */
if ((recdmatchb) && ((recdmatchb >= bb) && (recdmatchb <= ee)))
  { strcpy(fdat2b,bold1);
    strcat(fdat2b,fdat2);
    strcat(fdat2b,bold2);
  }
else
  { strcpy(fdat2b,fdat2);
  }

/*eject*/
/* display currentline: <--fieldname occurs->  bgn end typ<---data--->  */
/*Oct13/10 - insert space between bgn/end (John Faulhaber IBM)          */
printf("%-30s%4s %4s%3s %s\n",fldnam,zbgn,zend,maprw.typ,fdat2b);

/*Feb25/11 - show hex for bad fields > 9 bytes on 2nd line                 */
if (fdat4[0])
  { printf("%-43s%s\n"," ",fdat4);
    linectr++;                     /* incrmnt ctr for extra line */
  }
linectr++;                                        /* increment line ctr */

/*Aug06/11 - nextfield: increment maptbl index here (vs bgnline) */
/*         - unless displaying item occurs                       */
/*         - jump here if current field display inhibited        */
nextfield:

/* increment occurs index for next occurs (if any) */
ooii++;

/* if last occurs for this field - increment maptbl index for next field*/
if (ooii >= ooee)
  { mtir++;              /* increment maptbl index to next field */
    ooii = 0;            /* reset occurs index for next field    */
    ooee = 0;            /*Aug17/11 also occurs end fix bug loop */
  }

/*Aug04/11 - increment field ctr - on 1st occurrence of item occurs */
/*         - also on group occurs & on non-occurs since ooii=0      */
/*Aug13/11 - move here to seq# fields inhibited by optn 'i' 0/blank */
if ((ooii < 1) && (memcmp(maprw.des,"*BGNOCC",7))
               && (memcmp(maprw.des,"*ENDOCC",7)))
  { fldctr++;
  }

if ((mtir > mtiend) || (linectr >= linemax))
  { goto endscreen;
  }

/*Sep02/11 - test last field in record for occurs depending on */
/* recdend = (maprw.bgn-goffcor2+goctoff+ooff+maprw.lth+rdwhs); prior calc*/
if (recdend >= rsz1)
  { goto endscreen;
  }

goto bgnline;

/*Aug13/11 - remove code to display base fields to partial redef records  */
/* - see old solution in versions prior to Aug03/2011                     */
/* - old code used mtibi/mtiri 1/0 or 0/1 to inc base or redef (kludgy)   */
/* - recode use mtir only from 0 base & chg mtir to redef after base fld cnt*/

/* test for display end via mtiend, initially set to end of cobmap table*/
/* but TYPE's will have set to last cobmap tbl entry for current type   */
/* or end display if screen full, linemax reached                       */

/*eject*/
/*uvhdcob--------------- end of current screen -------------------------*/
endscreen:
/* return point for some error conditions                               */
reprompt:

/* print any stored opmsg1 & opmsg2 & clear to prevent repeat            */
/* msgs such as search found locations stored in subrtns & stored       */
/* - for display after the relevant screen is displayed above           */
if ((opmsg1[0]) || (opmsg2[0]) || (opmsg3[0]))
  { if (opmsg1[0])
      { printf("%s",opmsg1);
        opmsg1[0] = '\0';
      }
    if (opmsg2[0])
      { printf("%s",opmsg2);
        opmsg2[0] = '\0';
      }
    if (opmsg3[0])
      { printf("%s",opmsg3);
        opmsg3[0] = '\0';
      }
    /*Dec23/10 - opmsg3 added for verify continue prompts     */
    /* - generate divider line to empahsize preceding errmsgs */
    /*Dec24/10 - inhibit if EOF (rsize 0)                     */
  /* if (rsz1 > 0)  <-- disabled ? */
        printf("-----------------------------------------------------------\n");
  }

/* warning msg if recsize not divisible evenly into filesize - if Fixed */
if ((filesize > filesiz0) && ((opsi['e'-'a'] & 0x01) == 0) && (ftype == 'f'))
  { filextra2 = filextra;        /* prevent warning if UVi64 long long*/
    sprintf(warnmsg1,"filesize NOT multiple of recsize, %d bytes remain\n"
                     ,filextra2);
    printRV(warnmsg1);           /* display msg in reverse video */
  }

/*eject*/
/* prompt operator for next command             */
/*Jan27/09 - minimze prompt until End of Record */
if (mtir >= mtiend)
  { printf("rec#=%d rcount=%d rsize=%d fsize=%s fptr=%s\n"
            ,recnum1,rcount,rsz1,fsedit,fpedit1);
  }

/* For Fixed length - display more info if filesize not multiple of recsize */
/*                  - if on 1st record in file unless inhibited by option e2*/
if ((filesize > filesiz0) && (fileptr == 0) && (screenctr < 2)
                          && ((opsi['e'-'a'] & 0x02) == 0) && (ftype == 'f'))
  { ll = calcrsl(rsz1,filesize);        /* calc next multiple < recsize */
    rr = calcrsg(rsz1,filesize);        /* calc next multiple > recsize */
    printRV("If Variable (IDXFORMAT3/8,RDW), quit/restart w option v or z");
    sprintf(warnmsg1
    ,"\nIf Fixed length records, change recsize now via command 'R' (R%d current)",rsz1);
    printRV(warnmsg1);
    sprintf(warnmsg1
    ,"\nnext evenly divisible record sizes lower/higher are --> R%d/R%d"
    ,ll,rr);
    printRV(warnmsg1);
    printRV("\nOR you may continue (ignoring these warnings) --> ");
  }
else
  { /*Jan27/09 - minimze prompt until End of Record */
    /*Dec24/10 - but not if EOF (rsize 0)           */
    if ((mtir < mtiend) && (rsz1 > 0))
      { printf("--- continue to EOR --> "); 
      }
    else
      { /*May31/10 - test switch k0 kill help prompts or k1 restore */
        if (helpson)
          { printf(
"null=next,r#=rec,s=search,u=update,x=undo,p=print,w=write,t=tally");
            printf("\n,v=verify,c=chkseq#,t=tally,e=exit to uvhd");
            printf("\n,q=quit,k0=helpoff,k1=helpon,?=HelpScreens --> ");
          }
        else
          { printf("k1=HelpPrompts,?=HelpScreens --> ");
          }
      }
  }

/*eject*/
/* wait for op command - return point (vs reprompt) if return value 2 */
/* - following transfer search args to write,print,tally,drop  */
getopcmd:

memset(opcmd,'\0',80);             /* clear any prior command            */
fgets(opcmd,80,stdin);             /* wait for operator reply            */

/* convert any LineFeed in fgets reply to null */
ll = strlen(opcmd);
if ((ll > 0) && (opcmd[ll-1] == '\n'))
  { opcmd[ll-1] = '\0';
  }

ss = parse();                      /* parse oprtr reply                  */
                                   /* validate & store cmd args          */
if (ss <= 0)                       /* command valid status ?             */
    goto reprompt;

/*eject*/
/*-------- analyze operator response & perform indicated action -------- */

if ((opcmd[0] == 'q') || (opcmd[0] == ':') || (opcmd[0] == 0x1B))
  { goto endprgm;
  }

if (memcmp(opcmd,"help",4) == 0)
  { showhelps(hsp,21);         /* show help01 - help21 */
    goto endscreen;
  }

/* test for search cmd 1st, to reset search continue col on any other cmd*/
if (opcmd[0] == 's')               /* search for pattern ?             */
  { /* upnext = 1;  Jun01/10 - chg to upnext = 0 */ 
    upnext = 0;       /* inhibit getrec() advance nextrec */
    ss = search1();
    if (ss <= 0)
      { errmsg("    - reset fileptr to BOF(r0) & retry(ss) ?","","",0,0x00);
        goto reprompt;
      }
    else
      { upnext = 0;       /* inhibit getrec() advance nextrec */
        goto bgnsmatch;   /* go display record with found search pattern */
      }
  }

/* reset search continue column# - on any cmd other than search repeat*/
sargs.pscd = 0;                        /* reset search continue col#  */

/* verify packed & character data fields */
if (opcmd[0] == 'v')         /* verify data ? */
  { upnext = 0;              /* inhibit getrec() advance nextrec */
    ss = verify1();
    if (ss)                  /* if any errors found ? */
      { upnext = 0;          /* inhibit getrec() advance nextrec */
        goto bgnsmatch;      /* go display record with errors */
      }
    else
      { upnext = 0;          /* inhibit getrec() advance nextrec */
        goto bgnsmatch;      /* else go display last record searched or EOFR*/
      }
  }

/* if Null reply - advance to next record, or next screen if rsize>320*/
if (opcmd[0] <= ' ')                   /* null reply ?                */
  { /*Sep02/11 - fix extra fields on RDW ODO fields, try +rdwhs */
 /* if ((rii >= rsz1) || (mtir > mtiend)) <-- disabled Sep02/11 */
    if ((recdend >= rsz1) || (mtir > mtiend)) /* enabled Sep02/11*/
    /*Jan25/09 - uvhd had if (rii >= rsz1) & uvhdcob if (mtir > mtiend) ? */
      { /* fileptr += rsz1;  May31/10 replace w upnext/getrec */
        upnext = 1;             /* set getrec() advance to nextrec  */
        /*Note - above works for varlth as well as fixlth           */
        /*     - since last getrec stored rsz1 correct for all types*/
        goto bgnrec;
      }
    else
        goto bgnscreen;
  }

/*eject*/
/*Nov12/07 - user enter a cmd (vs ' ' null entry) */

/* store rsz2 to be used for following fileptr calcs from rec#     */
/* fixed files - use rszo from r optn on cmd line                  */
/* variable files - use last valid recsize (might be prior to EOF) */
if (ftype == 'f')
  { rsz2 = rszo;       /* fixed files - use rszo r optn cmd line   */
  }
else
  { rsz2 = rsz1p;      /* variable files - use last valid recsize  */
  }

if (opcmd[0] == 'r')               /* r# (goto specific record) ? */
  { /* subtract 1 from oprtrs 1 relative entry, verify > 0, recalc ptr*/
    cmn--;
    if (cmn <= 0)
      { cmn = 0;                   /* correct any oprtr confusion   */
        recnum1 = 1;               /* set recnum1 (for varlth files)*/
        fileptr = 0;               /* reset fileptr to BOF          */
      }
    else
      { /*Nov11/07 - calc new file ptr & goto display record            */
        /*Jun01/10 - setfileptr() ensures fileptr never > filesize      */
        setfileptr(cmn * rsz2);    /* set new ptr, ensure not > filesize*/
        /*Dec08/10 - setfileptr now calcs recnum1 for fixlth files      */
      }
    upnext = 0;                    /* inhibit getrec() advance nextrec  */
    /*Jul11/10 - if varlth, prompt to use find f# */
    if (ftype != 'f')
     { strcpy(opmsg1,"for VarLth files, use find find f# (r# for FixLth)\n");
     }
    goto bgnrec;
  }

else if (opcmd[0] == 'b')          /* b# goto specific byte#            */
  { setfileptr(cmn);               /* set new ptr, ensure not > filesize*/
    /*Dec08/10 - setfileptr now calcs recnum1 for fixlth files          */
    upnext = 0;                    /* inhibit getrec() advance nextrec  */
    goto bgnrec;
  }

/*eject*/
else if (opcmd[0] == '+')         /* +# (forward #recs)      */
  { upnext = 0;            /*May25/10 - inhibit fileptr updt in getrec */
    if (cmn <= 1)
      { cmn = 1;                  /* default value to 1      */
      }
    /*Nov22/10 - convert +/- cmds to 'f' find for varlth files         */
    if (ftype == 'f')
      { /*Jun02/10 - upfileptr() ensures fileptr never > filesize      */
        /*Jun02/10 - use rsz2 all types - see code *cmntd out below    */
        upfileptr(cmn * rsz2);        /* up ptr, ensure not > filesize */
        /*Dec08/10 - upfileptr now calcs recnum1 for fixlth files      */
        goto bgnrec; 
      }
    else
      { /*Nov22/10 - calc rec# for find cmd */
        /* - need to subtract 1 from entered value ? */
        /* cargs.cmv = (recnum1 + cmn - 1); */
        /*Mar13/11 - change above to following */
        cargs.cmv = (recnum1 + cmn);
        ss = findrec();
        if (ss <= 0)
          { goto reprompt;
          }
        goto bgnrec;
      }
  } 

/*Apr01/07 - calc recnum1 for getrecv/getrecz (+= above & -= below) */
else if (opcmd[0] == '-')               /* -# (back #recs)         */
  { upnext = 0;            /*May25/10 - inhibit fileptr updt in getrec */
    if (cmn <= 1)
      { cmn = 1;                        /* default value to 1      */
      }
    /*Nov22/10 - convert +/- cmds to 'f' find for varlth files */
    if (ftype == 'f')
      { upfileptr(-(cmn * rsz2));     /* up ptr, ensure not > filesize */
        /*dec08/10 - must be negative of course */
        /*Dec08/10 - upfileptr now calcs recnum1 for fixlth files      */
        goto bgnrec; 
      }
    else
      { /*Nov22/10 - calc rec# for find cmd */
        /* - need to add 1 to entered value ? */
        /* cargs.cmv = (recnum1 - (cmn + 1)); <-- change as follows Mar13/11*/
        cargs.cmv = (recnum1 - cmn);
        /*Mar13/11 - but if EOF, use (rcount + 1 - cmn) */
        if (fileptr >= filesize)
          { cargs.cmv = (rcount + 1 - cmn);
          }
        ss = findrec();
        if (ss <= 0)
          { goto reprompt;
          }
        goto bgnrec;
      }
  }
    /*Nov22/10 - replaced uvhdcob +/- coding with coding from uvhd */

/*eject*/
/*May24/10 - 'f' find specified rec# for varlth recs (RDW,LST,IDXf3/8) */
else if (opcmd[0] == 'f') 
  { ss = findrec();
    if (ss <= 0)
      { goto reprompt;
      }
    upnext = 0;      /* inhibit up fileptr/recnum1 to show correct record*/
    goto bgnrec;
  }

if (opcmd[0] == 'p')           /* print formatted recs to a file ?   */
  { ss = print1();             /* uvhd.c arg1 was lszo n/a uvhdcob.c */
    if (ss <= 0)
      { errmsg("    - reset fileptr to BOF(r0) & retry(pp) ?","","",0,0x00);
        goto reprompt;
      }
    else if (ss == 2)
      { goto getopcmd;
      }
    else
      { goto bgnrec;
      }
  }

/*Aug13/11 - iprint command combined with print as option 'i'   */
/*Aug13/11 - 'i' cmd now used to set 'i' options                */
/* - chg occurs optn 'v' to optn 'i', allow cmd 'i' to set optn 'i' */
/* - new options to inhibit display of zero/blank fields */
/* i1 = item occurs, i2 = group occurs, i4 = all fields*/
else if (opcmd[0] == 'i')          /* iprint formatted recs to a file ? */
  { opsi['i'-'a'] = cargs.opi['i'-'a'];
    goto bgnrec;
  }

else if (opcmd[0] == 'w')        /*  write unformatted recs to a file ? */
  { ss = write1();
    if (ss <= 0)
      { errmsg("    - reset fileptr to BOF(r0) & retry(ww) ?","","",0,0x00);
        goto reprompt;
      }
    else if (ss == 2)
      { goto getopcmd;
      }
    else
      { goto bgnrec;
      }
  }

/*eject*/
else if (opcmd[0] == 'c')        /*  check sequence to EOF (or seq err)  */
  { ss = check1();
    if (ss <= 0)
      { goto reprompt;
      }
    else
      { goto bgnrec;
      }
  }
else if (opcmd[0] == 'u')           /* update current record ?   */
  { opstat = update();
    if (opstat <= 0)
        goto reprompt;
    else
        goto bgnrec;
  }
/*Dec06/10 - add move field/constant command */
else if (opcmd[0] == 'm')                 /* move field/constant ? */
  { opstat = move1();
    if (opstat <= 0)
        goto reprompt;
    else
        goto bgnrec;
  }
/*Dec26/10 - add move Numeric command */
else if (opcmd[0] == 'n')                 /* move numeric ? */
  { opstat = moven();
    if (opstat <= 0)
        goto reprompt;
    else
        goto bgnrec;
  }
/* x = rollback last update, Jun12/07 disallow if option n multi recs/scrn*/
/*Dec24/10 - remove option n (uvhd only) */
else if (opcmd[0] == 'x')
  { opstat = back1();
    if (opstat <= 0)
        goto reprompt;
    else
        goto bgnrec;
  }
/* X = rollback all updates */
else if (opcmd[0] == 'X') 
  { opstat = backall();
    if (opstat <= 0)
        goto reprompt;
    else
        goto bgnrec;
  }

else if (opcmd[0] == 'R')               /* change Rcsz (w/o quit reenter)  */
  { rszo = cmn;                         /* store new rcsz                  */
    chkrcsz(rszo);                      /* validate & calc new recs in file*/
    goto bgnrec;                        /* go redisplay current record     */
  }

/*eject*/
else if (opcmd[0] == 't')               /* tally (count) records ? */
  { ss = tally1();
    if (ss == 2)
      { goto getopcmd;
      }
    if (ss <= 0)
      { goto reprompt;
      }
    goto bgnrec;                        /* go redisplay current record */
  }
else if (opcmd[0] == 'a')               /* acum record fields ? */
  { opstat = acum1();
    if (opstat == 2)
      { goto getopcmd;
      }
    goto bgnrec;                        /* go redisplay current record     */
  }

/*Jan25/09 - 'e' uvhdcob = Exit to uvhd */
/* (in uvhd e=enum since t=translate, in uvhdcob t=tally) */
/*Jun05/10 - chg exit cmd optn 'b' to fileptr(byte#) vs 1st rec# to display*/
/*Jan10/11 - chg to optn b from f0 now used to inhibit build Find index   */
else if (opcmd[0] == 'e')             /* exit to uvhd                     */
  { strcpy(exitcmd,"uvhd ");
    strcat(exitcmd,fn1);              /* append datafilename              */
    strcat(exitcmd," ");
    /*Aug23/11 - pass only filetype option z4/z8 or v */
    sncopy(w1,opsu,2,0x03);           /* isolate 1st 2 chars of options   */
    if ((w1[0] == 'z') || (w1[0] == 'v'))
      { strcat(exitcmd,w1);           /* + filetype optns on uvhdcob cmd  */
      }
    strcat(exitcmd,rszop);            /* + rcsz option from cobmap RCSZ=  */
    sprintf(firstop,"b%ld",fileptr);  /* + optn b byte# of 1st rec display*/
    strcat(exitcmd,firstop);
    strcat(exitcmd,opcmd+1);          /* + any options on exit cmd (u)    */
    system(exitcmd);
    upnext = 0;                       /* inhibit getrec() advance nextrec */
    goto bgnrec;
  }

/*May27/10 - add commands k0 to kill help prompts & k1 to restore */
else if (opcmd[0] == 'k')
  { if (opcmd[1] == '0')
      { helpson = 0;
      }
    else 
      { helpson = 1;
      }
    upnext = 0;       /* ensure no record advance */
    goto bgnrec;      /* return to redisplay current record */
  }

/*eject*/
/*Dec27/10 - new cmd o2+ to show no of item occurs fields to display */
else if (opcmd[0] == 'o')
  { opsi['o'-'a'] = cargs.opi['o'-'a'];
    upnext = 0;       /* ensure no record advance */
    /*Aug04/11 - add option v1+ to inhibit zero/blank occurs fields after 1st*/
    /*Aug13/11 - chg optn 'v' to optn 'i', allow cmd 'i' to set optn 'i' */
    opsi['i'-'a'] = cargs.opi['i'-'a'];
    goto bgnrec;      /* return to redisplay current record */
  }

/*Dec27/10 - new cmd g2+ to show no of item occurs fields to display */
/*         - add option v1+ to inhibit zero/blank occurs fields after 1st*/
else if (opcmd[0] == 'g')
  { opsi['g'-'a'] = cargs.opi['g'-'a'];
    upnext = 0;       /* ensure no record advance */
    /*Aug13/11 - chg optn 'v' to optn 'i', allow cmd 'i' to set optn 'i' */
    opsi['i'-'a'] = cargs.opi['i'-'a'];
    goto bgnrec;      /* return to redisplay current record */
  }

else if (opcmd[0] == 'l')     /* close files ? */
  { opstat = close1();
    goto reprompt;
  }

else
  { showhelps(hsp,21);        /* show help01 - help21 */
    goto endscreen;
  }

/*eject*/
/*uvhdcob----------------- end of program ------------------------*/
endprgm:

close(fd1);                              /* close input file      */

/* close output files - if open */
/*Feb05/09 - most output files now opened & closed on each command       */
/* - but write has option w1 on cmd line to combine all writes to 1 file */
/*Dec29/10 - cmd 'l' added to close files as desired, so close most here */
/*         - bits 0x00 cause no error if not open                        */

closefileX(wfname,"W",&wfptr,&wfopn,&wfctr,0x00); 
closefileX(pfname,"P",&pfptr,&pfopn,&pfctr,0x00);
closefileX(vwfname,"VW",&vwfptr,&vwfopn,&vwfctr,0x00); 
closefileX(vpfname,"VP",&vpfptr,&vpfopn,&vpfctr,0x00); 

printf("** quit request - program ended **\n");

return(0);
}

/*eject*/
/*============================ subrtns =============================*/

/*uvhd---------------------- chkrcsz ---------------------------------*/
/* call subfunctn to check rcsz & calc number of records in file      */
/* - called on program entry (check rcsz entered on cmd line r option)*/
/* - also called by command 'R' (change rcsz w/o quit & cmd line optn */
/* - no errmsgs if variable text of indexed file                      */

int chkrcsz(int recsiz0)
{
/* inhibit errmsgs if variable length records */
/* - option 't' (text) 'v' (IDXf3/IDXF8) 'z' (RDW) */
if ((ftype == 'v') || (ftype == 'z') || (ftype == 't'))
  { /* calculate items for variable length records */
    /*Nov11/07 - default recsize to 256 if < 1 or > RMAX */
    if (recsiz0 < 1 || recsiz0 > RMAX)
      { recsiz0 = RDFLT;
      }

    /* calc recs in file, etc - based on 256 for text or varlth files */
    /* - will recalc on every record based on current recsize         */
    calcrecs(recsiz0,rszo);          /* calc recs in file, etc */
  }
else
  { /* chkrcsz for fixed length records */
    /*Nov11/07 - remove errmsg if recsize invalid */
    /* - default recsize to option r defltd to 256 at pgm init for fixlth*/
    if (recsiz0 < 1 || recsiz0 > RMAX)
      { recsiz0 = rszo;
      }

    calcrecs(recsiz0,rszo);          /* calc recs in file, etc */

    /* warning if rcsz does not divide evenly into filesize for FixedLth */
    if ((remndr != 0) && (ftype == 'f'))
      { printf("WARNING: rcsz does not divide evenly into filesize\n");
      }
  }

return(1);
}

/*eject*/
/*uvhd------------------------- calcrecs -----------------------------*/
/*Nov11/07 - calculate records in file, based on current recsize      */
/* - vs prior method calc only at begin program based on optn 'r'     */
/* - if recsize invalid, default to arg2                              */

int calcrecs(int recsiz1, int rsxdflt)
{
/*May27/10 - test switch (set at EOF) inhibit calc rcount for hdgs */
/*Jun03/10 - inhibit for varlth files, allow for Fixed lth         */
if ((rcountx) && (ftype != 'f'))
  { return(0);
  }

/* if recsiz1 <= 0, default to 256 to prevent divide errors */
if (recsiz1 < 1)
  { recsiz1 = rsxdflt;
  }

/* calculate records in file & any remainder                      */
frecsc = (filesize / recsiz1);
rcount = frecsc;                /* for printing printf %d         */
remndr = (filesize % recsiz1);
filextra = remndr;              /* same as remndr - not sure why ? */

/* calculate filesize evenly divisible by rcsz (but <)             */
/* - to prevent fileptr getting off record boundaries at EOF -recs */
filesiz0 = frecsc * recsiz1;

return(1);
}

/*eject*/
/*uvhdcob--------------------- upfileptr ---------------------------*/
/*Jun01/10 - up fileptr by record size & ensure never > filesize    */
/*         - if filesize exceeded, return 1, else 0                 */

int upfileptr(int recsize1)
{
fileptr += recsize1;
if (fileptr > filesize)
  { fileptr = filesize;
    return(1);
  }
if (ftype == 'f')
  { recnum1 = ((fileptr / rszo) +1);
  }
return(0);
}

/*uvhdcob--------------------- setfileptr -------------------------*/
/*Jun01/10 - set fileptr to new value & ensure never > filesize    */
/*         - if filesize exceeded, return 1, else 0                */

int setfileptr(UVi64 newfileptr)
{
fileptr = newfileptr;
if (fileptr > filesize)
  { fileptr = filesize;
    return(1);
  }
if (ftype == 'f')
  { recnum1 = ((fileptr / rszo) +1);
  }
return(0);
}

/*eject*/
/*uvhd------------------------ getrec ------------------------------*/
/* get next record (return record length)                           */
/* - calls subfunction getrecf or getrecv                           */
/* - getrecf used for fixed record size                             */
/* - getrect used for text variable lth to CR/LF option 't'         */
/* - getrecv used for option 'v' IDXFORMAT3 variable indexed        */
/* - getrecx used for option 'v' IDXFORMAT8 fixed ISAM files > 2 gig*/
/*Feb05/09 - combine getrev & getrecx as getrecv using getrecx code */

int getrec(short bits)
{
int rs1;

/*May19/11 - save fileptr of prior get, used to save fileptr last rec in file*/
fileptrp = fileptr;

/*May25/10 - major changes to getrec(), add following:                   */
/* int rsz1p;      Prior Record Size - saved at end getrec()             */
/* - used to incrmnt fileptr at begin next getrec for varlth (not fixed) */
/* fileptr/recnum1 now incremented at begin getrec()                     */
/* - inhibited if upnext==0 (set 0 at bgn prgm & reposition cmds r#/b#   */
/* - upnext=1 at end getrec() assuming browse follows                    */

/*Jun01/10 - ensure fileptr never > filesize */
if (fileptr >= filesize)
  { fileptr = filesize;     /* set fileptr to filesize - recsize */
    /*Nov21/10 - Index built automatically at startup for varlth files*/
    /* - findex uses 'getrec(1)' vs 'getrec(0)' to inhibit EOF prompt */
    if (bits & 0x01) { ; }
    else 
      { strcpy(opmsg2,
        "EOF, enter -1 to see last record, or 1 return to Begin File\n");
      }

    rcountx = 1;            /*Jun02/10 inhibit subsequent calcrecs     */
    eof1++;                 /* count times reached EOF                 */
    if (eof1 == 1)          /*Jun02/10 - 1st time at EOF ?             */
      { rcount = recnum1;   /*    ifso - store records in file         */
      }
    /*Jun03/10 - at EOF -1 msg shows recnum1 1 less than last record */
    /* - try setting to (recs in file +1), so -1 will calc correctly */
    /*Mar13/11 - disable, rcount 1 too high for varlth RDW files     */
    /* recnum1 = (rcount + 1); */
  }

/*eject*/
/* if fileptr already >= filesize & fileptr < filesize           */
/* - set fileptr back to fileptr1, to redisplay last rec in file */
/*May19/11 - fileptr1 stored by findex if var, at prgm init if fix */
else if (upnext)
  { upfileptr(rsz1p);     /* up by Prior RecSize, ensure not > filesize */
    /* if fileptr now >= filesize                                       */
    /* - set fileptr = (filesize - prior recsize) to redisplay last rec */
    /* - store EOF msg & return to display/prompt                       */
    if (fileptr >= filesize)
      { /* fileptr1 = (filesize - rsz1p); */
        /*May19/11 - fileptr1 stored by findex if var, init if fix */
        /*Nov21/10 - Index built automatically at startup for varlth files*/
        /* - findex uses 'getrec(1)' vs 'getrec(0)' to inhibit EOF prompt */
        if (bits & 0x01) { ; }
        else 
          { strcpy(opmsg2,
            "EOF, enter -1 to see last record, or 1 return to Begin File\n");
          }
   
        rcountx = 1;            /*Jun02/10 inhibit subsequent calcrecs     */
        eof1++;                 /* count times reached EOF                 */
        if (eof1 == 1)          /*Jun02/10 - 1st time at EOF ?             */
          { rcount = recnum1;   /*    ifso - store records in file         */
          }
        /*Jun03/10 - at EOF -1 msg shows recnum1 1 less than last record */
        /* - try setting to (recs in file +1), so -1 will calc correctly */
        /*Mar13/11 - disable, rcount 1 too high for varlth RDW files     */
        /* recnum1 = (rcount + 1); */
        return(0);
      }
    else
      { /*Dec07/10 - incrmnt rec number only if variable length       */
        /*         - fixlth recnum1 calculated in setfileptr/upfileptr*/
        if (ftype != 'f')
          { recnum1++;        /* up recnum1 for varlth */
          }
      }
  }

rii = 0;                  /* init rec index for getlinr subfunction */

/* clear record area - for text records variable length             */
/* - so search commands wont find data from longer records          */
/* - clear recb to blanks (vs nulls) lth rszo+256 before each getrec */
memset(recb,' ',rcsmax);
/*Jun14/11 - chg rszox to rcsmax = rszo(fixlth) or rdwmax(varlth) */

/*eject*/
/* test file type option & call appropriate subfunction */
if (ftype == 't')
  { rs1 = getrect(bits);
  }
else if (ftype == 'v')
  { rs1 = getrecv(bits);
  }
else if (ftype == 'z')
  { rs1 = getrdw(bits);
  }
else
  { rs1 = getrecf(bits);
  }

/*May25/10 - set switch to updt fileptr at begin next getrec          */
upnext = 1;    /* set switch to updt fileptr at begin next getrec     */

if (ftype == 'f')
  { calcrecs(rszo,RDFLT);  /* calcrecs based on fixed recsize */
  }
else
  { calcrecs(rs1,RDFLT); /* calcrecs based on latest recsize*/
  }

/*Jun01/10 - save recsize as prior recsize for next getrec/fileptr updt*/
if (rs1 > 0)
  { rsz2p = rsz1p; /*Nov21/10 - save recsize 2 recs back for -1 varlth */
    rsz1p = rs1;   /* save current recsize for next getrec fileptr update*/
  }

/*Oct08/11 - edit fileptr for printf's %ld or %lld for 64/32bit HP gcc */
sprintf(fpedit1,E64,fileptr);

return (rs1);
}

/*eject*/
/*uvhd------------------------ getrecf ------------------------------*/
/* get next record (return record length)                            */
/* - record size from option 'r' on cmd line (default 256)           */
/* - getrecf used for fixed record size                              */

int getrecf(short bits)
{
int ii;
int rs1;
Uchar uc;

fileseek("getrecf");               /* seek to current fileptr position */
rs1 = 0;                           /* reset read size                  */

/*May2001 - fopen,fread,fseek change to open/open64,read,lseek/lseek64*/
rs1 = read(fd1,recb,rszo);      /* get fixed size records           */

/*  remainder = (filesize % rszo); */
/*Mar01/03 - remndr garbage on print ? should not need to recalc if fixed*/
if (rs1 < 0)
    rs1 = 0;

/* set switch 1 if any bytes < 0x20 or > 0x7E, except \n \r \t \f      */
/* to determine print mode, also depends on option 'h'                 */
/* h0 = auto determine, h1 = force chars only, h2 = force hex display  */
/* allow hex chars in last 2 bytes of record for CR/LF at end text recs*/
/* Feb20/03 - scan only to 3rd last byte (dont check for x'0D' or x'0A'*/
xchar = 0;
for (ii=0; ii < rs1-2; ii++)
  { uc = recb[ii];
    if ( uc >= ' ' && uc <= '~')
       continue;
    xchar = 1;
    break;
  }

return(rs1);
}

/*eject*/
/*uvhd------------------------ getrect ------------------------------*/
/* get next record (return record length)                            */
/* - record size from option 'r' on cmd line (default 256)           */
/* - getrect used for text variable lth to LF (option 't')           */

int getrect(short bits)
{
int cc,ii;
int rs1;
Uchar uc;

fileseek("getrect"); 

rs1 = 0;      /* reset read size                               */
bufn = 0;     /* force buffer fill at begin each text read     */ 
/*May20/10 - change buf read 8000 bytes at begin program       */
/*           and when empty in getcbuf()                       */
/*May22/10 - set bufn=0 each get & set buf rdsize rcszo+128    */
/*         - for reset rec#, need to force reread after seek   */
/*         - ensure rs1 count includes LF,                     */
/*           so fileptr += rcsz OK for fileseek at next getrec */

while (rs1 <= rszoy)
  { cc = getcbuf();           /* get next char via buffered read  */
    if (cc == EOF)
      { return(-1);
      }

    recb[rs1++] = (char) cc;

    if (cc == '\n')          /* text rec terminated by LF x'0A' ? */
      {
       /* recb[rs1-1] = ' ';  <-- see notes below */ 
          break;
      }
    /*May21/10 - blank LF in rec area */
    /*Aug17/10 - comment out "blank LF" */
    /* - I think I blanked in case of write out fixed length records     */
    /* - but, misleading since you see no LFs on text read back with uvhd*/
    /* - so, cmt out & blank if/when any Write cmd issued OK ??          */
  }

/*eject*/
if (rs1 < 0)
  { rs1 = 0;
  }

/* set switch 1 if any bytes < 0x20 or > 0x7E, except \n \r \t \f      */
/* to determine print mode, also depends on option 'h'                 */
/* h0 = auto determine, h1 = force chars only, h2 = force hex display  */
/* allow hex chars in last 2 bytes of record for CR/LF at end text recs*/
/* Feb20/03 - scan only to 3rd last byte (dont check for x'0D' or x'0A'*/
xchar = 0;
for (ii=0; ii < rs1-2; ii++)
  { uc = recb[ii];
    if ( uc >= ' ' && uc <= '~')
       continue;
    xchar = 1;
    break;
  }

return(rs1);
}

/*eject*/
/*uvhd------------------------- getcbuf ------------------------------*/
/* get 1 byte at a time from a text file (includes LineFeeds)         */
/* - returns 1 character (unsigned) or EOF (-1) at end of file        */
/*May20/10 - change buf read 8000 bytes at begin program & when empty */
/*         - was initing bufn=0 on each getrect & reading only rszo   */
/*May22/10 - set bufn=0 each get & set buf rdsize rcszo+128           */
/*         - so reset rec# works, need to force reread after seek     */

int getcbuf(void)
{
/* static char bufa[RMAX];         ** buffer read area            */
/* static char *bufp = bufa;       ** buffer pointer to next char */
/* static int bufn = 0;            ** buffer bytes remaining      */
/*May2001 - bufa,bufp,bufn  moved to global storage               */
/*may21/10 - modify getcbuf, clear bufa before read 8000          */

if (bufn == 0)
  { memset(bufa,' ',rszoy);
    bufn = read(fd1,bufa,rszoy);
    bufp = bufa;
  }

bufn--;                         /* decrement bytes remaining */

if (bufn >= 0)
  { return (unsigned char) *bufp++;
  }
else
  { return EOF;
  }
}

/*eject*/
/*uvhd------------------------- getrecv -------------------------------*/
/* get next IDXFORMAT8 length record (Micro Focus COBOL)               */
/*Feb05/09 - combine getrev & getrecx as getrecv using getrecx code    */
/* - called from getrec when option 'v' specified                      */
/* - fileptr should point to the 2 or 4 byte hdr of next record        */
/* - if fileptr < file header size, set fileptr = 0                    */
/* - read record header 2 bytes (or 4 bytes if max rcsz >= 4095)       */
/* - calc record size & slot size (hdr+data+fill to 4 byte boundary)   */
/* - reseek to begin rec hdr (to include hdr in display)               */
/* - test rec display optn v1,v2,v4,v8: filehdr, deleted, data, all    */
/*   (default v5 = filehdr + data recs)                                */

int getrecv(short bits)
{
int rs1;                /* record size to be returned              */
char vrhdr[8];          /* work area to read 2 or 4 byte header    */
int ii;
char cc;

/* return point to read next rec if bypassing deleted recs or system recs*/
reread:

/* read record header (2 or 4 bytes) to get record size               */
/* May2001: fseek changed to call fileseek (largefiles lseek/lseek64) */
/*          fread changed to read (since no fseek64)                  */
fileseek("getrecv");
rs1 = read(fd1,vrhdr,vrhs);        /* get record headr 2 or 4 bytes   */
if (rs1 <= 0)
  { return (rs1);
  }

switchx(vrhdr,vr4k);               /* calc & store rcsz,slotsz,& rectype*/
/* switchx stores vrsize & vrslot & applies max & min rules           */
/* switchx return value used only for min & max at file open          */

/* reseek to begin rec hdr & read record to be displayed slot size    */
/* May2001: fseek changed to call fileseek (largefiles lseek/lseek64) */
fileseek("getrecv");
rs1 = read(fd1,recb,vrslot);      /* get rechdr + data + any fill     */
if (rs1 <= 0)
  { return (rs1);
  }

/*eject*/
/* verify record type x'10' thru x'80'                              */
/* - if invalid we must have gone 'off the rails'                   */
/* - 'off the rails' displays partrecs or rereads til EOF reached   */
/* - try scanning to next data type record header x'40' 1st nibble  */
if ((vrtyp < 0x10) || (vrtyp > 0x80))
  { for (ii = vrhs; ii < vrslot; ii++)
      { cc = recb[ii] & 0xF0;     /* isolate 1st nibble             */
        if (cc == 0x40)           /* if possible data rec           */
          { fileptr += ii;        /* set fileptr to possible data rec*/
            goto reread;
          }
      }
  }

/* test rec display optn v1,v2,v4,v8: filehdr, deleted, data, all    */
if ((vrtyp == 0x30) && (opsi['v'-'a'] & 0x01) && (fileptr < vfhs))
  { goto process;
  }
else if ((vrtyp == 0x20) && (opsi['v'-'a'] & 0x02))
  { goto process;
  }
else if ((vrtyp == 0x40) && (opsi['v'-'a'] & 0x04))
  { goto process;
  }
/* sysrec (not filehdr) or other record - bypass unless option v8 (all) */
else if (opsi['v'-'a'] & 0x08)
  { goto process;
  }
else
  { /* current record not desired - bypass, return to get next         */
    fileptr += rs1;
    goto reread;
  }

/* record selected for process/display by calling mainline         */
process:
xchar = 1;      /* set switch to display record in hexadecimal   */

return (rs1);
}

/*eject*/
/*--------------------------- getrdw --------------------------------*/
/*Apr27/11 - get BDW/RDW record (code rewriten April 27/2011)        */
/* - common to initial build Index & mainline program get records    */
/* - build Index calculated bdmin to assist BDW bypass on get/search */

int getrdw(short bits)
{
int rs1;
xchar = 1;     /* force hex display for RDW files */

/* process depending on initial building Index OR get/search for data records*/
if (fii1 < 2)
  { /* collect stats, calc bdwmin to assist bypass BDW on get/search   */
    /* - can read headers only, OMIT reading data records to save time */
    rdwsize = getrdwh(0);          /* get BDW/RDW header */
    if (rdwsize <= 0)
      { return(0);
      }

    /* process depending on z2,z4,z8 */
    if (opsi['z'-'a'] & 0x02)
      { rdwsize += 2;         /* z2 hdrsize NOT included in RDWsize */
        /* fileptr += rdwsize; <--Apr27/11 fileptr incrmnt in getrec() */
      }
    else if (opsi['z'-'a'] & 0x04)
      { ;
        /* fileptr += rdwsize; <--Apr27/11 fileptr incrmnt in getrec() */
      }

/*eject*/
    else 
      { /* z8 BDW - special processing if initial build index */
        /* collect stats, calc bdwmin to assist bypass BDW on get/search*/
        if ((fileptr == 0) || (fileptr == bdwnext))
          { bdwsize = rdwsize;
            bdwnext = (fileptr + bdwsize);
            bdwsum += bdwsize;
            bdwcnt++;              /* count BDWs to calc avg at EOF */
            /*May04/11 - save info for rdwerr() reporting */
            bdwfp   = fileptr;
            bdwrn   = recnum1;
            memcpy(bdwsave,rdwhdr,8);
            /* save BDW min/max */
            if (bdwmin == 0)
              { bdwmin = bdwsize;
              }
            /*Jun12/06 - ensure BDWmin not saved from last block in file */
            /* if ((bdwmin > bdwsize) && (fileptr < filesizeb)) */
            /*Jun15/06 - fix Jun12 save bdwmin if > bdwsize & bdwmin > rdwmax */
            if ((bdwmin > bdwsize) && (bdwmin > rdwmax))
              { bdwmin = bdwsize;
              }
            if (bdwmin > bdwsize)
              { bdwmin = bdwsize;
              }
            if (bdwmax < bdwsize)
              { bdwmax = bdwsize;
              }

            rdwsize = getrdwh2(0);     /* convert RDW to binary */
            /* - getrdwh2 uses bytes 5-8 already read by getrdwh above*/
        
            if (rdwsize <= 0)
              { return(0);
              }
            if (rdwsize > bdwsize)
              { rdwerr("ERR: RDWsize > BDWsize (on Index build phase)",0x20);
              }
            fileptr += 4;            /* bypass BDW */
          }
        else
          { /* z8 BDW on build index, BUT not at BDW */
            /* - up file ptr by size of current record */
            /* - can OMIT reading data on Index build to save time */
            ;
            /* fileptr += rdwsize; <--Apr27/11 fileptr incrmnt in getrec() */
          }
       }

/*eject*/
    rdwsum += rdwsize;
    if (rdwmin == 0)
      { rdwmin = rdwsize;
      }
    if (rdwmin > rdwsize)
      { rdwmin = rdwsize;
      }
    if (rdwmax < rdwsize)
      { rdwmax = rdwsize;
      }
    return(rdwsize);
  }

/*eject*/
else
  { /* get or find search for data records (vs initial build index) */
    rdwsizep = rdwsize;         /* save prior RDW size */
    rdwsize = getrdwh(0);       /* get BDW/RDW header */
    if (rdwsize <= 0)
      { return(0);
      }

    fileseek("getrdw");    /* set fileptr from fileptr long int */

    /* process depending on z2,z4,z8 */
    if (opsi['z'-'a'] & 0x02)
      { rdwsize += 2;                 /* z2 hdrsize NOT included in RDWsize*/
        rs1 = read(fd1,recb,rdwsize);
      }
    else if (opsi['z'-'a'] & 0x04)
      { rs1 = read(fd1,recb,rdwsize); /* z4/z8 hdrsize INCLUDED in RDWsize */
      }
    else
      { /* z8 BDW NOT building Index - get data record           */
        /* bypass BDW, identified by:                            */
        /* - bdwsize >= bdwmin (caluclated on index build phase) */
        /* - followed by RDW < BDW & 7th/8th bytes null          */
        if ((rdwsize >= bdwmin) && (rdwhdr[6] == '\0') && (rdwhdr[7] == '\0'))
          { /*May04/11 - save info for rdwerr() reporting */
            bdwfp   = fileptr;
            bdwrn   = recnum1;
            memcpy(bdwsave,rdwhdr,8);
            bdwsizep = bdwsize;        /* save prior BDW size   */
            bdwsize = rdwsize;         /* save current BDW size */
            fileptr += 4;          /* bypass BDW */
            rdwsize = getrdwh(0);
            if (rdwsize <= 0)
              { return(0);
              }
          }
        /* get RDW record (either 1st in BDW or subsequent) */
        fileseek("getrdw"); 
        rs1 = read(fd1,recb,rdwsize);
        if (rdwsize <= 0)
          { return(0);
          }
      }
  }
return(rs1);
}

/*eject*/
/*uvhd------------------------- getrdwh -------------------------------*/
/* get RDW/BDW header (8 bytes)                                        */
/* - variable length RDW option z verified z2,z4,or z8                 */
/* - called from getrec when option 'z' specified                      */
/* - fileptr should point to the header/prefix of next record          */
/* - read record header 4 bytes & store recsize/slotsize               */
/* - recsize in hdr includes 4 bytes + data size                       */
/* - reseek to begin rec hdr (to include hdr in display)               */
/*Apr26/11 - rewritten to improve BDW detect/bypass                    */

int getrdwh(short bits)
{
int rs1;              /* record size to be returned */

fileseek("getrdw");
rs1 = read(fd1,rdwhdr,40); /*Apr27/10 - get 40 bytes for rdwerr() */
/*Mar05/11 - add EOF test here in getrdw1 as well as getrdw */
if (rs1 <= 0)
  { return (rs1);
  }

/* verify BDW/RDW z8/z4 prefix - bytes 3 & 4 must be nulls (except z2) */
if (opsi['z'-'a'] & 0x0C) 
  { if ((rdwhdr[2] == '\0') && (rdwhdr[3] == '\0'))
      { ; }
    else
      { rdwerr("Invalid BDW/RDW prefix (bytes 3 & 4 not null)",0x20);
      }
  }

/* if BDW(z8) at begin file - verify 1st RDW (bytes 7&8 null */
if ((fileptr == 0) && (opsi['z'-'a'] & 0x08))
  { if ((rdwhdr[6] == '\0') && (rdwhdr[7] == '\0'))
      { ; }
    else
      { rdwerr("z8 at begin file, bytes 7 & 8 not null, try z4",0x20);
      }
  }

/*eject*/
/* convert the BDW/RDW recsize to binary            */
/* z2=2bytehdr, z4=4bytehdr, z8=BDW/RDW 4+4         */
/* - assume big-end unless option z1 for little-end */
memset(u1.cc,'\0',4);            /* clear work area union      */
if (opsi['z'-'a'] & 0x01)
  { memcpy(u1.cc,rdwhdr,2);      /* store little-end recsize on left*/
    /* switch little-end to Big-end if AIX,HP,SUN,etc (vs Intel)    */
#if (BEM)
    u2.cc[0] = u1.cc[3];
    u2.cc[1] = u1.cc[2];
    u2.cc[2] = u1.cc[1];
    u2.cc[3] = u1.cc[0];
#else
    memcpy(u2.cc,u1.cc,4);
#endif
  }
else
  { memcpy(u1.cc+2,rdwhdr,2);    /* store big-end recsize on right*/
/* switch big-end to little-end if INTEL or SCO (not SUN, HP, etc)*/
#if (LEM)
    u2.cc[0] = u1.cc[3];
    u2.cc[1] = u1.cc[2];
    u2.cc[2] = u1.cc[1];
    u2.cc[3] = u1.cc[0];
#else
    memcpy(u2.cc,u1.cc,4);
#endif
  }

/* verify BDW/RDW prefix size */
if ((u2.ii < 8) || (u2.ii > 32768))
  { rdwerr("Invalid BDW/RDW recsize < 8 or > 32768",0x20);
  }

return (u2.ii);
}

/*eject*/
/*---------------------------- getrdwh2 ---------------------------------*/
/*Apr27/11 - convert RDW recsize to binary depending big-end/little-end  */
/* - getrdwh has read 20 bytes & proven BDW in 1st 4                     */
/* - now convert RDW recsize to binary from bytes 5-8 (no need to reread)*/

int getrdwh2(short bits)
{
int rs1;              /* record size to be returned */

/* convert the RDW recsize to binary                */
/* - assume big-end unless option z1 for little-end */
memset(u1.cc,'\0',4);            /* clear work area union       */
if (opsi['z'-'a'] & 0x01)
  { memcpy(u1.cc,rdwhdr+4,2);    /* recsize bytes 5&6 to left   */
    /* switch little-end to Big-end if AIX,HP,SUN,etc (vs Intel)*/
#if (BEM)
    u2.cc[0] = u1.cc[3];
    u2.cc[1] = u1.cc[2];
    u2.cc[2] = u1.cc[1];
    u2.cc[3] = u1.cc[0];
#else
    memcpy(u2.cc,u1.cc,4);
#endif
  }
else
  { memcpy(u1.cc+2,rdwhdr+4,2);    /* recsize bytes 5&6 to right  */
/* switch big-end to little-end if INTEL or SCO (not SUN, HP, etc)  */
#if (LEM)
    u2.cc[0] = u1.cc[3];
    u2.cc[1] = u1.cc[2];
    u2.cc[2] = u1.cc[1];
    u2.cc[3] = u1.cc[0];
#else
    memcpy(u2.cc,u1.cc,4);
#endif
  }

/* verify BDW/RDW prefix size */
if ((u2.ii < 8) || (u2.ii > 32768))
  { rdwerr("Invalid RDW recsize < 8 or > 32768",0x20);
  }

return (u2.ii);
}

/*eject*/
/*------------------------------ rdwerr -------------------------------*/
/*Apr27/11 - report BDW/RDW record prefix error                        */
/* - display callers errmsg + recnumber + fileptr                      */
/* - display 1st 20 bytes of record (read by getrdwh)                  */

int rdwerr(char *msg, short bits)
{
printf("%s\n",msg);
printf("ERR in RDW=%d at rec#=%d, fileptr=%ld, filesize=%ld\n",
        rdwsize, recnum1, fileptr, filesize);
if (opsi['z'-'a'] & 0x08)
  { printf("prior BDW=%d saved from rec#=%d, fileptr=%ld\n",
        bdwsize, bdwrn, bdwfp);
    data2hex(bdwsavehex,bdwsave,16,0x02);
    printf("prior BDW/RDW(hex)=%s\n",bdwsavehex);
  }

/*Jun12/11 NOTE - rdwsize/bdwsize reported could be prior vs current */

/*May07/11 - show current BDW/RDW in horizontal hex (match prior BDW) */
data2hex(bdwcurhex,rdwhdr,16,0x02);
printf("current BDW/RDW(hex)=%s\n",bdwcurhex);

printf("1st 40 bytes shown below in vertical hexadecimal\n");
data2vhx(w1,w2,w3,rdwhdr,40,ebc2asc,vhxbits);
printf("%s\n",w1);
printf("%s\n",w2);
printf("%s\n",w3);
exit(99);
return(0);
}

/*eject*/
/*uvhdcob---------------------- getlinr ------------------------------*/
/* get data for next display line (from record buffer)                */
/* - 64 bytes max, or 'lszo' if option 'l' spcfd                      */
/* - or less at EOR or EOF                                            */
/* - return number of bytes copied or 0 at EOR/EOF                    */

int getlinr(int lsize)
{
lii = 0;                               /* reset line index            */

rii1 = rii;                            /* save rec index b4 new segment*/

if (rii >= rsz1)                       /* EOR/EOF already reached ?   */
    return(0);

while ((lii < lsize) && (rii < rsz1))
  { linr[lii++] = recd[rii++];
  }

return(lii);
}

/*eject*/
/*uvhdcob---------------------filterchar-------------------------------*/
/* subrtn to convert non-display characters to periods                 */
/*Dec24/10 - removed optn c1 to disable default nondisplay to periods  */
void filterchar(unsigned char *ch, int lsize)
{
int i;
for (i=0; i < lsize; i++)
  {  if ((ch[i] < ' ') || ((ch[i] > 0x7e)))
         ch[i] = '.';
  }
}
/*Feb2003 - LMAX changed to lsize when LMAX increased to 1024      */
/*        - lsize now passed as argument (for screen & print diff) */
/*        - in filterchar, hexzone,& hexdigit                      */

/*uvhdcob-------------------- hexzone ------------------------------*/
/* convert zones of char string to hex display                      */
void hexzone(char *hexzo, char *hexch, int lsize)
{
intU z;
int i;
for (i=0; i < lsize; i++)
  { z = (intU)(hexch[i] >> 4);
    z = z & 0x0f;
    if (z < 10)
        hexzo[i] = (char)(z + 0x30);
    else
        hexzo[i] = (char)(z + 0x37);
  }
hexzo[i] = '\0';
}

/*uvhd---------------------- hexdigit ------------------------------*/
/* convert ddigits of char string for hex display                   */
void hexdigit(char *hd,char *hc, int lsize)
{
intU d;
int i;
for (i=0; i < lsize; i++)
  { d = (intU)(hc[i] & 0x0f);
    if (d < 10)
        hd[i] = (char)(d + 0x30);
    else
        hd[i] = (char)(d + 0x37);
  }
hd[i] = '\0';
}

/*eject*/
/*uvhd--------------------------- parse --------------------------------*/
/* parse the command entered (in reply to prompt)                       */
/* - return 1 OK, 0 if errors discovered                                */
/*                                                                      */
/* type1 - 1 char command + optional numeric value                      */
/* r100                     - goto & display record #100                */
/*                                                                      */
/* type2 - cmd + op1,op2                                                */
/* s 0(20),='ABC'             - search for ABC within 1st 20 bytes      */
/* s 0(3),!'ABC'              - search for NOT ABC in cols 1-3          */
/*                              <!> search lth must match if lth > 1    */
/* p 0(3),>'800'              - print records with > 800 in 1st 3 bytes */
/* u 0(3),='ABC'              - update cols 1-3 of current rec w ABC    */
/*                                                                      */
/* s ='ABC'                   - search for ABC anywhere in entire record*/
/*                            - op1 dflts to 0(rcsz) if omitted         */
/*                                                                      */
/* provide 6 operands for commands (search, write, etc)                 */
/* - cmd + op1,op2,op3,op4,op5,op6 (allow 3 conditions in 3 diff fields)*/
/*                                                                      */
/* s 0(40),='ABC',40(40),='XYZ' - search for ABC in 1-40 & XYZ in 41-80 */
/*                                                                      */
/* s 0(1),='1',40(1),='A'   - search for 1 in byte 0 & A in byte 40     */
/* s 0(1),'1',&40(1),'A'    - same ('=' and '&' are the defaults)       */
/* s 0(1),'1',|40(1),'A'    - search for 1 in byte 0 OR A in byte 40    */
/*                                                                      */
/* s 0(80),<x'20',0(80),>x'7E' - search for non printable chars in 1-80 */
/*                                                                      */
/* s 0(1),'1',|,'2'         - op3 omitted defaults to op1 search area   */
/*                          - must specify OR (|) for = conditions      */
/* s 0(1),>'1',,<'9'        - search for 2-8 in byte 0 (range search)   */
/*                                                                      */
/*Dec06/10 - add move field/constant command */
/* m  35(30),90(12)         - move tel# & clear extra op1 lth           */
/* m  50(30),'Dec 06/2010'  - move constant & clear extra lth           */

int parse(void)
{
int sdi;                   /* dsplcmnt for sdscopy function           */
int ss;                    /* status of various cmnds                 */
char *pp,*qq;              /* ptrs returned by subfuns (atol1,etc)    */
int ee;                    /* end op1 (dsp + lth)                     */
int ii,jj;                 /* misc index                              */
char a3ccs[4];             /* save | or & from op4 for op3 and/or     */
char a5ccs[4];             /* save | or & from op6 for op5 and/or     */
char arg2ctx = '\0';       /* op2 constant type explicit c/e/x        */
char arg4ctx = '\0';       /* op4 constant type explicit c/e/x        */
char arg6ctx = '\0';       /* op6 constant type explicit c/e/x        */

/*Dec19/10 - add fields for DataType & DataCode carg.a1dt carg.a1dc   */
char c1,c2;
char dt1;     /* DataType (c/z/p/f) default c, store from 120(5p) etc */
char dc1;     /* DataCode (a/e) default a, store from 54(8ze) etc     */
char dt2;     /*Dec26/10 - add for op2 on move numeric                */ 
char dc2;

/*eject*/
/* clear argument storage from prior commands */
memset(cms,'\0',80);   memset(args,'\0',80);
memset(arg1a,'\0',80); memset(arg1b,'\0',80); memset(arg1c,'\0',80);
memset(arg2a,'\0',80); memset(arg2b,'\0',80); memset(arg2c,'\0',80);
memset(arg3a,'\0',80); memset(arg3b,'\0',80); memset(arg3c,'\0',80);
memset(arg4a,'\0',80); memset(arg4b,'\0',80); memset(arg4c,'\0',80);
memset(arg5a,'\0',80); memset(arg5b,'\0',80); memset(arg5c,'\0',80);
memset(arg6a,'\0',80); memset(arg6b,'\0',80); memset(arg6c,'\0',80);
memset(a3ccs,'\0',4);  memset(a5ccs,'\0',4);
arg1d = 0; arg1l = 0; 
arg2d = 0; arg2l = 0;
arg3d = 0; arg3l = 0; 
           arg4l = 0;
arg5d = 0; arg5l = 0; 
           arg6l = 0;
op1dflt = 0;
/*Dec19/10 - add fields for DataType & DataCode carg.a1dt carg.a1dc   */
dt1 = 'c';               /* default DataType 'c' Character */
dc1 = 'a';               /* default DataCode 'a' Ascii     */
dt2 = 'c';               /*Dec26/10 ad for op2 move numeric*/ 
dc2 = 'a';           

/*Feb26/11 - if cmd line option 'a', chg default to EBCDIC */
if (opsc['a'-'a'])
  { dc1 = 'e';           
    dc2 = 'e';           
  }

/*Jan21/09 - if no cmd entered - return now */
if (opcmd[0] <= ' ')
  { return(1);
  }

/* if opcmd 1st byte numeric - default to the 'r' (rec#) command       */
if (isdigit(opcmd[0]))
  { strcpy(opcmd2,opcmd);               /* copy cmd to alt w/s         */
    /*Nov22/10 - OR default to 'f' find for variable length files      */
    if (ftype == 'f')
      { opcmd[0] = 'r';                 /* insert 'r' command          */
      }
    else
      { opcmd[0] = 'f';                 /* insert 'f' command          */
      }
    strcpy(opcmd+1,opcmd2);             /* append original cmd string  */
  }

/* separate command & arguments assuming: cmd op1,op2,op3,op4          */
/* s 0(40),='ABC',40(40),='XYZ'    - search ABC in 1-40 & XYZ in 41-80 */
sdscopy(cms,opcmd,80,&sdi,"~~ ~",0x1032);
sdscopy(args,opcmd,80,&sdi,"~~~~",0x2032);
strcpy(cops,cms);                          /* cmd+options               */

/*Nov09/07 - return now if cmd 'q' (quit) */
if (cops[0] == 'q')
  { return(9);        /* return > 0 to avoid reprompt */
  }

/*eject*/
/* errchk - space after cmnd & prior to arguments                       */
/*        - should be no ( ) , ' " in cmnd string                       */
ss = searchcm(cms,"(),\'\"",20,5,0x03);
if (ss >= 0)
  { errmsg("command format - no space between cmd & args","","",0,0x10);
    return(0);
  }

/* process cmd options, 1st cnvrt non lower cmds - to prevent sortops err*/
if (cops[0] == '+') cops[0] = 'z';
if (cops[0] == '-') cops[0] = 'z';
if (cops[0] == '?') cops[0] = 'z';
if (cops[0] == ':') cops[0] = 'z';
if (cops[0] == 'X') cops[0] = 'z';
if (cops[0] == 'R') cops[0] = 'z';

/* sort/store options, but not if 2nd byte '=' (transfer last search cmd)*/
if (cops[1] != '=')
  { ss = sortops(cops,copsc,copsi,0x10);
    if (ss < 0)
       return(0);
  }

/* store any numeric value appended to the command                    */
/* - using option for cmd letter to avoid any option numeric values   */
/* cmn = copsi[cops[0] - 'a']; Jun05/10 does not allow > 2 gig        */

/*Jun05/10 - allow numeric values > 2 gig on cmds such as b2200000000 */
/* extract numeric digits until non-numeric encountered               */
memset(copsn,'\0',24);
ii=1; jj=0;
/*Dec06/10 - allow count on repeat cmd (uu99, mm99, etc) */
if (cops[1] == cops[0])
  { ii = 2;
  }
while (ii < 24)
  { if (!(isdigit(cops[ii])))
      { break;
      }
    copsn[jj++] = cops[ii++];
  }
/* cmn = strtol(copsn,(char**)0,10); May19/11*/
/* cmn = atol(copsn); Oct04/11 chg back for gcc 32 bit HP Itanium */
/*Oct04/11 - note May19/11 'strtol' should have been 'strtoll'    */
cmn = strtoll(copsn,(char**)0,10); 
/*Dec06/10 - convert 99 to 999,999,999 */
/*Jan10/11 - but not if find cmd       */
if ((cmn == 99) && (opcmd[0] != 'f'))
  { cmn = 999999999;
  }

/* separate args based on commas ie:  0(20),'ABC',40(20),'XYZ'        */
sdscopy(arg1a,args,80,&sdi,"~~,~",0x1012);
sdscopy(arg2a,args,80,&sdi,"~~,~",0x2012);
sdscopy(arg3a,args,80,&sdi,"~~,~",0x2012);
sdscopy(arg4a,args,80,&sdi,"~~,~",0x2012);
sdscopy(arg5a,args,80,&sdi,"~~,~",0x2012);
sdscopy(arg6a,args,80,&sdi,"~~~~",0x2002);

/*eject*/
/* allow op1 dsp(lth) to be omitted - default to 0(rcsz) entire record */
/* - if quote found in 1st 3 bytes of op1, assume op1 omitted          */
if (memchr(arg1a,'\'',3))
  { strcpy(arg6a,arg5a);               /* shift op5 to op6, etc        */
    strcpy(arg5a,arg4a);
    strcpy(arg4a,arg3a);
    strcpy(arg3a,arg2a);
    strcpy(arg2a,arg1a);
    sprintf(arg1a,"0(%d)",rszo);       /* default op1 to 0(rcsz)       */
    /*Jun04/10 - chg above from rsz1 to rszo for varlth files          */
    op1dflt = 1;                       /* store indicator for scan/rep */
  }
/* allow op3 dsp(lth) to be omitted - default to op1 dsp(lth)          */
/* - if quote found in 1st 3 bytes of op3, assume op3 omitted          */
if (memchr(arg3a,'\'',3))
  { strcpy(arg6a,arg5a);               /* shift op5 to op6, etc        */
    strcpy(arg5a,arg4a);
    strcpy(arg4a,arg3a);
    strcpy(arg3a,arg1a);               /* default op3 to op1 dsp(lth)  */
  }
/* allow op5 dsp(lth) to be omitted - default to op3 dsp(lth)          */
/* - if quote found in 1st 3 bytes of op5, assume op5 omitted          */
if (memchr(arg5a,'\'',3))
  { strcpy(arg6a,arg5a);               /* shift op5 to op6             */
    strcpy(arg5a,arg3a);               /* default op5 to op3 dsp(lth)  */
  }

/* error check - arg1 (if coded), must include '('                   */
if ((arg1a[0]) && (strchr(arg1a,'(') == 0))
  { errmsg("command format - no '(' in arg1","","",0,0x10);
    return(0);
  }

/* default op3 same as op1 - if op3 omitted or only '|'              */
/* s 0(40),='ABC',|0(40),='XYZ'  - search ABC in 1-40 OR XYZ in 1-40 */
/* s 0(40),='ABC',|,='XYZ'       - same by default                   */
if (arg4a[0])
  { if (arg3a[0] < '0')
        strcpy(arg3a,arg1a);
    else if ((arg3a[0] == '|') && (arg3a[1] < '0'))
        strcat(arg3a,arg1a);
  }

/* default op5 same as op3 - if op5 omitted or only '|'              */
/* s 10(3),='AAA',|20(3),>'BBB',|30(3),<'CCC'                        */
/* s 10(3),='AAA',|,>'BBB',|,<'CCC'                                  */
if (arg6a[0])
  { if (arg5a[0] < '0')
        strcpy(arg5a,arg3a);
    else if ((arg5a[0] == '|') && (arg5a[1] < '0'))
        strcat(arg5a,arg3a);
  }

/*eject*/
/* process arg1 - into displacement & length */
strcpy(arg1b,arg1a);
pp = atol1(&arg1d,arg1b,'(',6,0x05);
qq = atol1(&arg1l,pp,')',6,0x01);

/*Dec19/10 - retrieve DataType & DataCode for getop, acum1, etc */
/* a 120(5p), a 54(9ze), a 0(4bs), etc                          */
/* retrieve 1 or 2 alpha codes preceding ')' closing length     */
c1 = *(qq-1);
c2 = *(qq-2);
if ((isalpha(c1)) && (isalpha(c2)))
  { dt1 = c2;
    dc1 = c1;
  }
else if (isalpha(c1))
  { dt1 = c1;
  }

/*eject*/
/*Dec06/10 - allow op2 dsp(lth) for new move instrn */
if (arg2a[0])                   /* if op2 specified */
  { /* assume constant if single quote found, else assume dsp(lth) */
    if (strchr(arg2a,'\'')) 
      { /* standardize op2 constant in arg2b, default omitted condtn/type*/
        /*Dec07/10 - AEC constant type default ASCII=c or optn a EBCDIC=e*/ 
        memcpy(arg2b,AEC,2);          /* setup dflts for condition & type*/
        ii = 0;
        if ((arg2a[ii] == '=') || (arg2a[ii] == '!') ||
            (arg2a[ii] == '<') || (arg2a[ii] == '>'))
          { arg2b[0] = arg2a[ii++];
          }
        if ((arg2a[ii] == 'x') || (arg2a[ii] == 'X') ||
            (arg2a[ii] == 'c') || (arg2a[ii] == 'C') ||
            (arg2a[ii] == 'e') || (arg2a[ii] == 'E'))
          { arg2ctx = arg2a[ii];        /* save for explicit test below */
            arg2b[1] = arg2a[ii++];
          }
        strcpy(&arg2b[2],&arg2a[ii]);   /* copy op2 constant '...data...' */
    
        /* error check - arg2b must now include quote in 3rd byte         */
        if (arg2b[2] != '\'')
          { errmsg("arg2 constant condition/type/open-quote invalid"
                   ,"","",0,0x10);
            return(0);
          }
        /* process arg2 - strip quotes & cnvrt any hex rep to true hex */
        if ((arg2b[1] == 'x') || (arg2b[1] == 'X'))
          { arg2l = hex2data(arg2c,&arg2b[3],'\'',80,0x03);
          }
        else
          { arg2l = stncopy(arg2c,&arg2b[3],'\'',80,0x03);
            /* test const type 'e' convert ASCII to EBCDIC (cmd line optn a)*/
            /* Dec2002 - assume EBCDIC e'---' if optn 'a' spcfd on cmd line */
            /* if ((arg2b[1] == 'e') || (arg2b[1] == 'E') || (opsc['a'-'a'])) */
            /*Dec07/10 - remove optn a test here - constant type set above */
            if ((arg2b[1] == 'e') || (arg2b[1] == 'E'))
              { toebcdic2((Uchar*)arg2c,arg2l,0x00); /* cnvrt ASCII to EBCDIC*/
              }
          }
      }
/*eject*/
    else
      { /*Dec06/10 - assume dsp(lth) since no 'quote found in op2  */
        /*         - allow op2 (lth) optional                      */
        /*Dec26/10 - allow 18 bytes for op2 value (op2 lth omitted)*/
        pp = atol3(&arg2d,arg2a,"(, ",18,0x01);
        if (*pp == '(')
          { qq = atol3(&arg2l,pp+1,"), ",6,0x01);
          }
        /* if op2 lth omitted default to op1 lth */
        /*Dec26/10 - but not if move Numeric     */
        if (cops[0] == 'n')
          { ;
          }
        else if (arg2l == 0)
          { arg2l = arg1l;
          }
        /*Dec26/10 - retrieve op2 Type&Code for getop, acum1, etc  */
        /* retrieve 1 or 2 alpha codes preceding ')' closing length*/
        c1 = *(qq-1);
        c2 = *(qq-2);
        if ((isalpha(c1)) && (isalpha(c2)))
          { dt2 = c2;
            dc2 = c1;
          }
        else if (isalpha(c1))
          { dt2 = c1;
          }
      }
  }

/*eject*/
/* standardize op4 constant in arg4b by defaulting omitted condtn/type*/
if (arg4a[0])                   /* if op4 constant specified         */
  { /*Dec07/10 - AEC constant type default ASCII=c or optn a EBCDIC=e*/ 
    memcpy(arg4b,AEC,2);       /* setup dflts for condition & type   */
    ii = 0;
    if ((arg4a[ii] == '|') || (arg4a[ii] == '&'))
      { a3ccs[0] = arg4a[ii++]; /* save |/& AND/OR indicator */
      }
    if ((arg4a[ii] == '=') || (arg4a[ii] == '!') ||
        (arg4a[ii] == '<') || (arg4a[ii] == '>'))
      { arg4b[0] = arg4a[ii++];
      }
    if ((arg4a[ii] == 'x') || (arg4a[ii] == 'X') ||
        (arg4a[ii] == 'c') || (arg4a[ii] == 'C') ||
        (arg4a[ii] == 'e') || (arg4a[ii] == 'E'))
      { arg4ctx = arg4a[ii];        /* save for explicit test below */
        arg4b[1] = arg4a[ii++];
      }
    strcpy(&arg4b[2],&arg4a[ii]);   /* copy op4 constant '...data...' */

    /* error check - arg4b must now include quote in 3rd byte         */
    if (arg4b[2] != '\'')
      { errmsg("arg4 constant condition/type/open-quote invalid","","",0,0x10);
        return(0);
      }
  }

/* process arg3 - into displacement & length                          */
strcpy(arg3b,arg3a);
pp = atol1(&arg3d,arg3b,'(',6,0x05);
     atol1(&arg3l,pp,')',6,0x01);

/* process arg4 - strip quotes & cnvrt any hex rep to true hex        */
if ((arg4b[1] == 'x') || (arg4b[1] == 'X'))
  { arg4l = hex2data(arg4c,&arg4b[3],'\'',80,0x03);
  }
else
  { arg4l = stncopy(arg4c,&arg4b[3],'\'',80,0x03);
    /* test constant type 'e' convert ASCII to EBCDIC (for cmd line optn a)*/
    /* Dec2002 - assume EBCDIC e'---' if option 'a' spcfd on cmd line      */
    /*Dec07/10 - remove optn a test here - constant type set above */
    if ((arg4b[1] == 'e') || (arg4b[1] == 'E'))
      { toebcdic2((Uchar*)arg4c,arg4l,0x00);      /* cnvrt ASCII to EBCDIC */
      }
  }

/*eject*/
/* standardize op6 constant in arg6b by defaulting omitted condtn/type*/
if (arg6a[0])                  /* if op6 constant specified          */
  { /*Dec07/10 - AEC constant type default ASCII=c or optn a EBCDIC=e*/ 
    memcpy(arg6b,AEC,2);       /* setup dflts for condition & type   */
    ii = 0;
    if ((arg6a[ii] == '|') || (arg6a[ii] == '&'))
      { a5ccs[0] = arg6a[ii++]; /* save |/& AND/OR indicator */
      }
    if ((arg6a[ii] == '=') || (arg6a[ii] == '!') ||
        (arg6a[ii] == '<') || (arg6a[ii] == '>'))
      { arg6b[0] = arg6a[ii++];
      }
    if ((arg6a[ii] == 'x') || (arg6a[ii] == 'X') ||
        (arg6a[ii] == 'c') || (arg6a[ii] == 'C') ||
        (arg6a[ii] == 'e') || (arg6a[ii] == 'E'))
      { arg6ctx = arg6a[ii];        /* save for explicit test below */
        arg6b[1] = arg6a[ii++];
      }
    strcpy(&arg6b[2],&arg6a[ii]);   /* copy op6 constant '...data...' */

    /* error check - arg6b must now include quote in 3rd byte         */
    if (arg6b[2] != '\'')
      { errmsg("arg6 constant condition/type/open-quote invalid","","",0,0x10);
        return(0);
      }
  }

/* process arg5 - into displacement & length                          */
strcpy(arg5b,arg5a);
pp = atol1(&arg5d,arg5b,'(',6,0x05);
     atol1(&arg5l,pp,')',6,0x01);

/* process arg6 - strip quotes & cnvrt any hex rep to true hex        */
if ((arg6b[1] == 'x') || (arg6b[1] == 'X'))
  { arg6l = hex2data(arg6c,&arg6b[3],'\'',80,0x03);
  }
else
  { arg6l = stncopy(arg6c,&arg6b[3],'\'',80,0x03);
    /* test constant type 'e' convert ASCII to EBCDIC (for cmd line optn a)*/
    /* Dec2002 - assume EBCDIC e'---' if option 'a' spcfd on cmd line      */
    /*Dec07/10 - remove optn a test here - constant type set above */
    if ((arg6b[1] == 'e') || (arg6b[1] == 'E'))
      { toebcdic2((Uchar*)arg6c,arg6l,0x00);      /* cnvrt ASCII to EBCDIC */
      }
  }

/*Dec2002 - if option 'g1' on cmd line for 1 relative (vs 0 relative)  */
/*        - subtract 1 from dsplcmnts (force 0 if would be negative)   */
/*Aug16/06 - option changed to 'g' from 'z' (now RDW varlth filetype*/
if (opsi['c'-'a'] & 0x01)
  { arg1d--;
    arg3d--;
    arg5d--;
    if (arg1d < 0) arg1d = 0;
    if (arg3d < 0) arg3d = 0;
    if (arg5d < 0) arg5d = 0;
  }

/*eject*/
/* store results in a structure, for easy move depending on s,p,w,u   */
cargs = carg0;                        /* clear any prior data         */
strcpy(cargs.cmd,opcmd);
strcpy(cargs.cmc,cms);
cargs.cmv = cmn;
memcpy(cargs.a2c,arg2c,arg2l);
memcpy(cargs.a4c,arg4c,arg4l);
memcpy(cargs.a6c,arg6c,arg6l);
memcpy(cargs.a1cc,arg1b,3);
memcpy(cargs.a2cc,arg2b,3);
memcpy(cargs.a3cc,arg3b,3);
memcpy(cargs.a4cc,arg4b,3);
memcpy(cargs.a5cc,arg5b,3);
memcpy(cargs.a6cc,arg6b,3);

/* extract command options (dropping command & count) */
/* ex: if cms="t999999c15" then cmo="c15"             */
for (ii=1,jj=0; cms[ii]; ii++)
  { if (cms[ii] == cms[0])
        continue;
    if (!(isdigit(cms[ii])))
        break;
  }
while(cms[ii])
  { cargs.cmo[jj++] = cms[ii++];
  }

/* store any &/| AND/OR ccs saved from op4 for op3 or from op6 for op5 */
if (a3ccs[0])
    memcpy(cargs.a3cc,a3ccs,3);
if (a5ccs[0])
    memcpy(cargs.a5cc,a5ccs,3);
cargs.a1d = arg1d;
cargs.a1l = arg1l;
cargs.a2d = arg2d;   /*Dec06/10 for move instrn */
cargs.a2l = arg2l;
cargs.a3d = arg3d;
cargs.a3l = arg3l;
cargs.a4l = arg4l;
cargs.a5d = arg5d;
cargs.a5l = arg5l;
cargs.a6l = arg6l;

/*Dec19/10 - store DataType & DataCode for getop, acum1, etc */
cargs.a1dt = dt1;
cargs.a1dc = dc1;
cargs.a2dt = dt2;
cargs.a2dc = dc2;

/*eject*/
memcpy((char*)cargs.opi,(char*)copsi,104);
memcpy(cargs.opc,copsc,26);
cargs.op1dflt = op1dflt;
/*May16/08 - store indicator op1 dfltd to 0(rsz1)          */
/* - used by scan/rep to set op1lth = rsz1 for each record */
/*Jun04/10 - chg above from rsz1 to rszo for varlth files  */

/*Jun02/10 - chk op1 dsp+lth not > recsize                 */
/* - only if lth spcfd & recsize > 0                       */
/* - could be 0 at EOF when enter 0/1 return to BOF        */
/*Jun04/10 - chg recsize from rsz1 to rszo for varlth files*/
/*May28/11 - search op max check based on max recsz not current recsize */
/*Jun14/11 - fix ERR dsp+lth > rcsz for varlth recs when lth dflt maxsize  */
/*         - just check dsp not> rcsz (ignore lth)                         */
ee = cargs.a1d + cargs.a1l;
if ((cargs.a1l) && (rcsmax) && (cargs.a1d > rcsmax))
  { errmsg("op1 start-byte > rcsz","","",0,0x10);
    return(0);
  }

/* errcheck >!< compares,                                              */
/* if search pattern multibyte, search area lth must = pattern lth     */
if ((cargs.a2cc[0] == '>') || (cargs.a2cc[0] == '<') || (cargs.a2cc[0] == '!'))
 { if ((cargs.a2l > 1) && (cargs.a1l != cargs.a2l))
  { errmsg("compare <!> multi-byte pattern, search area lth must = pattern lth"
            ,"","",0,0x10);
    return(0);
  }
 }

return(1);
}

/*eject*/
/*uvhdcob--------------------- search1 --------------------------------*/
/* search for a data pattern - forward or backward (via sb or ssb)     */
/*Jun01/10 - backward search removed                                   */
/*                                                                     */
/* s 0(20),'ABC',20(20),'XYZ'   - search for ABC within 1st 20 bytes   */
/*                                & XYZ in bytes 20-39                 */
/* ss                           - repeat previous search               */
/*                                                                     */
/* - set fileptr to 1st byte of record containing pattern & return 1   */
/* - if nofind set fileptr to last rec in file & return 0              */

int search1(void)
{
int rr;            /* max records search ctr             */
int mm,nn,oo;      /* field1,2,3 search find/nofind 0+/- */
int mmd,nnd,ood;   /* srch1,2,3 dsplcmnt in rec or file  */
int match;         /* match results of 3 conditions 0/1  */
int nth;           /* search for nth occurrence (optn n) */

rr = 0;            /* reset max search ctr             */
nth = 0;           /* reset nth occurrence match ctr   */

/* upnext = 1;  Jun01/10 - chg to upnext = 0 */ 
upnext = 0;    /* inhibit getrec() advance nextrec */

/* test for new search or repeat previous search                     */
/* note re pscd - op1 dsp prior match (for search continue)          */
/* cmd ss  - repeat search (from next record)                        */
/* cmd sss - repeat search (same record, incrmnt column)             */

if (cms[1] == 's')                  /* repeat search ?               */
  { if (cms[2] == 's')              /* repeat samerec incrementing col*/
      { sargs.pscd += 1;            /* yes - incrmnt dsp start       */
        upnext = 0;                 /* inhibit getrec() advance nextrec */
      }
    else
      { /* fileptr += rsz1;  May31/10 replace w upnext/getrec */
        rsz1 = getrec(0);             /* get next record        */
        /*Jun02/10 - chg gg back to rsz1 */
        sargs.pscd = 0;             /* ensure dsp extra clear */
      }
  }
else
  { /* store new search args - but 1st verify (cargs here, sargs below)*/
    if ((cargs.a1l <= 0) || (cargs.a2l <= 0))
      { errmsg("search args invalid",cargs.cmd,"",0,0x10);
        return(0);
      }
    sargs = cargs;                  /* store new search args         */
  }

/*eject*/
/* verify search args - op1 lth & op2 constant lth > 0 ?             */
if ((sargs.a1l <= 0) || (sargs.a2l <= 0))
  { errmsg("search args invalid",sargs.cmd,"",0,0x10);
    return(0);
  }

pmsgctr = 0;             /* init search progress msg counter */

/* search for pattern (char or hex) until found or EOF                */
while (1)
  { rsz1 = getrec(0);             /* get next record */
    if (rsz1 <= 0)                /* EOF ?           */
      { /* fileptr = filesiz0; Jun01/10 - chg to filesize */
        fileptr = filesize;
        printf("EOF w nomatch to: %s - reset BOF (r0) & repeat(ss) ?\n"
               ,sargs.cmd);
        return(0);
      }

    /*Aug07/08 - updt search arg1 lth with current recsize if op1 lth default*/
    if (op1dflt)
      { sargs.a1l = rsz1;
      }

    /*May28/11 - test search progress message interval record count  */
    pmsgctr++;               /* increment search msg interval counter*/
    if (pmsgctr >= pmsgcnt)
      { printf("%s at rec# %d of %d\n",sargs.cmd,recnum1,rcount);
        pmsgctr = 0;        /* reset ctr for next msg */
      }

/*eject*/
    /* search for patterns - char strings or hex patterns              */
    /*May2003 - 3 possible conditions = < > & AND/OR possible relations*/
    /*note - might have used 'search234' function to do this           */
    /*     - BUT we need to capture the dsplcmnts for reporting        */
    /*       (from returns of separate search2, search3,& search4)     */

    mm = search2(recd,&sargs);       /* 9701 search = > < !            */

    /* search for op4 pattern if specified                             */
    if (sargs.a4l)
      { nn = search3(recd,&sargs);  /* search for match on op4 constant*/
      }
    else
      { nn = 32767;                 /* force match if op4 omitted      */
      }
    /*Feb2003 - 32767 used so will not attempt BOLD when no op4 pattern*/

    /* search for op6 pattern if specified                             */
    if (sargs.a6l)
      { oo = search4(recd,&sargs);  /* search for match on op4 constant*/
      }
    else
      { oo = 32767;                 /* force match if op4 omitted      */
      }

    /* test results of 3 searches depending on conditions vs AND/ORs possible*/
    /*May2003 - op4/op5 added to allow 3rd condition, also allowing AND/OR   */

    match = 0;  /* presume no-match */
    if ((sargs.a3cc[0] != '|') && (sargs.a5cc[0] != '|'))
      { if ((mm >= 0) && (nn >= 0) && (oo >= 0))
            match = 1;
      }
    else if ((sargs.a3cc[0] != '|') && (sargs.a5cc[0] == '|'))
      { if ((mm >= 0) && ((nn >= 0) || (oo >= 0)))
            match = 1;
      }
    else if ((sargs.a3cc[0] == '|') && (sargs.a5cc[0] != '|'))
      { if ((mm >= 0) || ((nn >= 0) && (oo >= 0)))
            match = 1;
      }
    else if ((sargs.a3cc[0] == '|') && (sargs.a5cc[0] == '|'))
      { if ((mm >= 0) || (nn >= 0) || (oo >= 0))
            match = 1;
      }

/*eject*/
/* test result of all 3 possible search conditions & possible AND/ORs  */
/* if match - store fileptr & match dsp for possible ss following      */
/*          - store match found msg & break search loop                */
/*          - opmsg1 will be displayed after found screen displayed     */
/* nomatch  - clear prior search match dsplcmnt & increment            */
/*          - advance fileptr to next record & repeat search loop      */
    if (match)
      { sargs.psfp = fileptr;
        sargs.pscd = mm;

        /* show found pattern as dsplcmnt in rec or file depending optn d2*/
        /*Dec24/10 - delete this option for uvhdcob */
        mmd = mm;
        nnd = nn;
        ood = oo;

        /*Aug22/10 - test optn g1 to report dsplcmnts 1 rel vs 0 rel */
        /*Feb24/11 - change optn 'g' (0/1 relative) to optn 'c'      */
        if (opsi['c'-'a'] & 0x01)
          { mmd++;
            nnd++;
            ood++;
          }

        /* if 3 search fields, report all 3 found dsplcmnts          */
        if (sargs.a6l)
          { sprintf(opmsg1,"found--> %s <--1st at %d, 2nd at %d, 3rd at %d\n",
                           sargs.cmd,mmd,nnd,ood);
          }
        /* if 2 search fields, report both found dsplcmnts           */
        else if (sargs.a4l)
          { sprintf(opmsg1,"found--> %s <--1st at byte# %d & 2nd at byte %d\n",
                           sargs.cmd,mmd,nnd);
          }
        else
          { sprintf(opmsg1,"found--> %s <--at byte# %d of rec# %d\n"
                         ,sargs.cmd,mmd,recnum1);
          }

/*eject*/
        /* ensure 1st screen display will include found pattern          */
        recdmatch = mmd;        /*Sep03/11 store dsplcmnt matching field */
        recdmatchb = recdmatch; /*Sep03/11 2nd copy for bold insert test */
        /* at bgnsmatch: recdmatch used to lookup maptbl index match field*/
        /* after 1st 15, fields bypassed until match dsplcmnt field reached*/
        mtimatch = lookmap(recdmatch);  /*Sep03/11 - lookup here for debug*/

        /* break while(1) loop on match & return +1              */
        /* But continue if option 'n' search < nth occurrence    */
        nth++;             /* increment search match occurrence# */
        if (nth >= sargs.opi['n'-'a'])
          { break;  
          }
        else
          { /* fileptr += rsz1;  May31/10 replace w upnext/getrec */
            continue;
          }
      }

/*eject*/
    /*May31/10 backward search removed */
    else /* nomatch */
      { /* fileptr += rsz1;  May31/10 replace w upnext/getrec */
        sargs.pscd = 0;                /* ensure dsp extra clear        */
        rr++;                          /* count records searched        */
        if ((sargs.cmv) && (rr >= sargs.cmv))
          { sprintf(opmsg1,"NOfind--> %s within limit spcfd\n",sargs.cmd);
            break;
          }
        continue;
      }
  }
return(1);
}

/*eject*/
/*uvhdcob-------------------- search2 --------------------------------*/
/* search a record for a match, as specified in the CA structure      */
/* - see the CA structure defined earlier in this program             */
/* - defines search start, length, pattern data, length,& cc = > < !  */
/* if match   - return dsplcmnt to matching data                      */
/* if nomatch - return -1                                             */

int search2(char *recd, struct CA *cap)
{
int ii,jj,kk;                  /* misc indices                       */
int bb = cap->a1d;             /* dsplcmnt in rec to begin search    */
int ee = cap->a1d+cap->a1l;    /* dsplcmnt in rec to end search      */
int ll = cap->a2l;             /* length of search pattern           */

/* to allow search continuation within same record (see search1 rtn)  */
/* - use prior search dsplcmnt (+1) if specified                      */
if (cap->pscd)
  { bb = cap->pscd;
  }

/* use different search rtns, depending on search condition > < = !    */
/*  & depending on search pattern length - 1 byte or multi-bytes       */
/*  <!> 1 byte compares    - will compare to each byte of search area  */
/* <!> multi-byte compares - search area length must = pattern length  */
/*                        - will compare corresponding bytes           */
if (cap->a2cc[0] == '>')
 { if (ll == 1)
    { for (ii=bb; ii < ee; ii++)
        { if ((Uchar) recd[ii] > (Uchar) cap->a2c[0])
              return(ii);
        }
    }
   else
    { if (memcmp(&recd[bb],&(cap->a2c[0]),ll) > 0)
              return(bb);
    }
 }

else if (cap->a2cc[0] == '<')
 { if (ll == 1)
    { for (ii=bb; ii < ee; ii++)
        { if ((Uchar) recd[ii] < (Uchar) cap->a2c[0])
              return(ii);
        }
    }
   else
    { if (memcmp(&recd[bb],&(cap->a2c[0]),ll) < 0)
              return(bb);
    }
 }

/*eject*/
else if (cap->a2cc[0] == '!')
 { if (ll == 1)
     { /*Mar2003 - sep logic for != search in 1 byte OR multi-byte fields    */
       if (cap->a1l == 1)
         { for (ii=bb; ii < ee; ii++)
             { if ((Uchar) recd[ii] != (Uchar) cap->a2c[0])
                   return(ii);
             }
         }
       else
         { /*Mar2003 - Multi-byte field search for != 1 byte pattern        */
           /* count&save dsp of any matches, at end return dsp to last match*/
            { for (ii=bb,jj=0,kk=0; ii < ee; ii++)
                { if ((Uchar) recd[ii] == (Uchar) cap->a2c[0])
                    { kk++;               /* count matches                  */
                      jj = ii;            /* save dsp to last == in field   */
                    }
                }
              if (kk == 0)                /* if No matches in field         */
                  return(bb);             /* return dsp to 1st byte of field*/
              /*  return(jj); return dsp to last == Mar2003 Bad logic fixed */
            }
         }
     }
   else
     { if (memcmp(&recd[bb],&(cap->a2c[0]),ll) != 0)
           return(bb);
     }
 }

else       /* must be = condition */
 { for (ii=bb; ii < ee; ii++)
     { for (jj=ii,kk=0; jj < ee; jj++,kk++)
         { if (recd[jj] != cap->a2c[kk])
               break;
           if (kk >= (ll-1))
               return(ii);
         }
     }
 }
  return(-1);
}

/*eject*/
/*uvhdcob-------------------- search3 --------------------------------*/
/* search record for match to op4 constant, as specified in CA struct */
/* - see the CA structure defined earlier in this program             */
/* - defines search start, length, pattern data, length,& cc = > < !  */
/* if match   - return dsplcmnt to matching data                      */
/* if nomatch - return -1                                             */

int search3(char *recd, struct CA *cap)
{
int ii,jj,kk;                  /* misc indices                       */
int bb = cap->a3d;             /* dsplcmnt in rec to begin search    */
int ee = cap->a3d+cap->a3l;    /* dsplcmnt in rec to end search      */
int ll = cap->a4l;             /* length of search pattern           */


/* use different search rtns, depending on search condition > < = !    */
/*  & depending on search pattern length - 1 byte or multi-bytes       */
/*  <!> 1 byte compares    - will compare to each byte of search area  */
/* <!> multi-byte compares - search area length must = pattern length  */
/*                        - will compare corresponding bytes           */
if (cap->a4cc[0] == '>')
 { if (ll == 1)
    { for (ii=bb; ii < ee; ii++)
        { if ((Uchar) recd[ii] > (Uchar) cap->a4c[0])
              return(ii);
        }
    }
   else
    { if (memcmp(&recd[bb],&(cap->a4c[0]),ll) > 0)
              return(bb);
    }
 }

else if (cap->a4cc[0] == '<')
 { if (ll == 1)
    { for (ii=bb; ii < ee; ii++)
        { if ((Uchar) recd[ii] < (Uchar) cap->a4c[0])
              return(ii);
        }
    }
   else
    { if (memcmp(&recd[bb],&(cap->a4c[0]),ll) < 0)
              return(bb);
    }
 }

/*eject*/
else if (cap->a4cc[0] == '!')
 { if (ll == 1)
     { /*Mar2003 - sep logic for != search in 1 byte OR multi-byte fields    */
       if (cap->a3l == 1)
         { for (ii=bb; ii < ee; ii++)
             { if ((Uchar) recd[ii] != (Uchar) cap->a4c[0])
                   return(ii);
             }
         }
       else
         { /*Mar2003 - Multi-byte field search for != 1 byte pattern        */
           /* count&save dsp of any matches, at end return dsp to last match*/
            { for (ii=bb,jj=0,kk=0; ii < ee; ii++)
                { if ((Uchar) recd[ii] == (Uchar) cap->a4c[0])
                    { kk++;               /* count matches                  */
                      jj = ii;            /* save dsp to last == in field   */
                    }
                }
              if (kk == 0)                /* if No matches in field         */
                  return(bb);             /* return dsp to 1st byte of field*/
              /*  return(jj); return dsp to last == Mar2003 Bad logic fixed */
            }
         }
     }
   else
    { if (memcmp(&recd[bb],&(cap->a4c[0]),ll) != 0)
          return(bb);
    }
 }

else       /* must be = condition */
 { for (ii=bb; ii < ee; ii++)
     { for (jj=ii,kk=0; jj < ee; jj++,kk++)
         { if (recd[jj] != cap->a4c[kk])
               break;
           if (kk >= (ll-1))
               return(ii);
         }
     }
 }
  return(-1);
}

/*eject*/
/*uvhdcob-------------------- search4 --------------------------------*/
/* search record for match to op6 constant, as specified in CA struct */
/* - see the CA structure defined earlier in this program             */
/* - defines search start, length, pattern data, length,& cc = > < !  */
/* if match: return dsplcmnt to matching data, if nomatch: return -1  */
/*May2003 - op5 & op6 added to allow 3rd condition on search, etc     */

int search4(char *recd, struct CA *cap)
{
int ii,jj,kk;                  /* misc indices                       */
int bb = cap->a5d;             /* dsplcmnt in rec to begin search    */
int ee = cap->a5d+cap->a5l;    /* dsplcmnt in rec to end search      */
int ll = cap->a6l;             /* length of search pattern           */


/* use different search rtns, depending on search condition > < = !    */
/*  & depending on search pattern length - 1 byte or multi-bytes       */
/*  <!> 1 byte compares    - will compare to each byte of search area  */
/* <!> multi-byte compares - search area length must = pattern length  */
/*                        - will compare corresponding bytes           */
if (cap->a6cc[0] == '>')
 { if (ll == 1)
    { for (ii=bb; ii < ee; ii++)
        { if ((Uchar) recd[ii] > (Uchar) cap->a6c[0])
              return(ii);
        }
    }
   else
    { if (memcmp(&recd[bb],&(cap->a6c[0]),ll) > 0)
              return(bb);
    }
 }

else if (cap->a6cc[0] == '<')
 { if (ll == 1)
    { for (ii=bb; ii < ee; ii++)
        { if ((Uchar) recd[ii] < (Uchar) cap->a6c[0])
              return(ii);
        }
    }
   else
    { if (memcmp(&recd[bb],&(cap->a6c[0]),ll) < 0)
              return(bb);
    }
 }

/*eject*/
else if (cap->a6cc[0] == '!')
 { if (ll == 1)
     { /*Mar2003 - sep logic for != search in 1 byte OR multi-byte fields    */
       if (cap->a5l == 1)
         { for (ii=bb; ii < ee; ii++)
             { if ((Uchar) recd[ii] != (Uchar) cap->a6c[0])
                   return(ii);
             }
         }
       else
         { /*Mar2003 - Multi-byte field search for != 1 byte pattern        */
           /* count&save dsp of any matches, at end return dsp to last match*/
            { for (ii=bb,jj=0,kk=0; ii < ee; ii++)
                { if ((Uchar) recd[ii] == (Uchar) cap->a6c[0])
                    { kk++;               /* count matches                  */
                      jj = ii;            /* save dsp to last == in field   */
                    }
                }
              if (kk == 0)                /* if No matches in field         */
                  return(bb);             /* return dsp to 1st byte of field*/
              /*  return(jj); return dsp to last == Mar2003 Bad logic fixed */
            }
         }
     }
   else
    { if (memcmp(&recd[bb],&(cap->a6c[0]),ll) != 0)
          return(bb);
    }
 }

else       /* must be = condition */
 { for (ii=bb; ii < ee; ii++)
     { for (jj=ii,kk=0; jj < ee; jj++,kk++)
         { if (recd[jj] != cap->a6c[kk])
               break;
           if (kk >= (ll-1))
               return(ii);
         }
     }
 }
  return(-1);
}

/*eject*/
/*uvhdcob-------------------- search234 -------------------------------*/
/* search record for match to op3, op4,& op6 constants as per CA struct*/
/* - see the CA structure defined earlier in this program              */
/* - defines search start, length, pattern data, length,& cc = > < !   */
/* if match: return +1, if nomatch: return -1                          */
/*May2003 - subrtn renamed & extended to test results of search2,3,4   */

int search234(char *recd, struct CA *cap)
{
int mm,nn,oo;

mm = search2(recd,cap);             /* search for match on op2 constant*/

/* search for match on op4 constant if specified                      */
nn = 1;                             /* disable op4 consider if not spcfd*/
if (cap->a4l)
  { nn = search3(recd,cap);         /* search for match on op3 constant*/
  }

/* search for match on op6 constant if specified                      */
oo = 1;                             /* disable op6 consider if not spcfd*/
if (cap->a6l)
  { oo = search4(recd,cap);         /* search for match on op6 constant*/
  }

/* test results of 3 searches depending on conditions vs AND/ORs possible*/
/*May2003 - op4/op5 added to allow 3rd condition, also allowing AND/OR   */

if ((cap->a3cc[0] != '|') && (cap->a5cc[0] != '|'))
  { if ((mm >= 0) && (nn >= 0) && (oo >= 0))
        return(1);
  }
else if ((cap->a3cc[0] != '|') && (cap->a5cc[0] == '|'))
  { if ((mm >= 0) && ((nn >= 0) || (oo >= 0)))
        return(1);
  }
else if ((cap->a3cc[0] == '|') && (cap->a5cc[0] != '|'))
  { if ((mm >= 0) || ((nn >= 0) && (oo >= 0)))
        return(1);
  }
else if ((cap->a3cc[0] == '|') && (cap->a5cc[0] == '|'))
  { if ((mm >= 0) || (nn >= 0) || (oo >= 0))
        return(1);
  }

return(-1);
}

/*eject*/
/*uvhdcob--------------------- search34 -------------------------------*/
/* search record for match to op3/op4,& op5/op6 constants per CA struct*/
/* - see the CA structure defined earlier in this program              */
/* - defines search start, length, pattern data, length,& cc = > < !   */
/* if match: return +1, if nomatch: return -1                          */
/*May2003 - op4/op5 3rd condition added                                */
/* search234 used for all 3 conditions (search,write,tally,print)*/
/* search34 used to test 2nd & 3rd conditions (update)                 */
/* - since op1/op2 (1st condition) used for update constant            */

int search34(char *recd, struct CA *cap)
{
int nn,oo;

/* search for match on op4 constant if specified                      */
nn = 1;                             /* disable op4 consider if not spcfd*/
if (cap->a4l)
  { nn = search3(recd,cap);         /* search for match on op3 constant*/
  }

/* search for match on op6 constant if specified                      */
oo = 1;                             /* disable op6 consider if not spcfd*/
if (cap->a6l)
  { oo = search4(recd,cap);         /* search for match on op6 constant*/
  }

/* test results of 2 searches depending on conditions vs AND/OR possible*/

if (cap->a5cc[0] == '|')
  { if ((nn >= 0) || (oo >= 0))
        return(1);
  }
else
  { if ((nn >= 0) && (oo >= 0))
        return(1);
  }

return(-1);
}

/*eject*/
/*uvhdcob--------------------- print1 ---------------------------------*/
/* print specified number of records                                   */
/* - or records matching a pattern, to a specified maximum             */
/*                                                                     */
/* p5                        - print next 5 records                    */
/*                                                                     */
/* p5 0(20),='ABC'           - search for & print records with 'ABC'   */
/*                             within 1st 20 bytes to max 5 recs       */
/*                                                                     */
/* pp                        - repeat previous search                  */
/*                                                                     */
/* - if nofind set fileptr to last rec in file & return 0              */

int print1(void)
{
int nn;             /* max records search ctr       */
int mm;             /* search find/nofind 0+/-      */
int ff;             /* calc rmndr formfeed option f */
/* long fpsv; save fileptr of last match   */
/*Jun05/10 - was int, caused fileseek err, but use global def as others */
int rnsv;           /* save recnum1 of last match   */

upnext = 0;         /* inhibit getrec() advance nextrec */

/* test for new print command or repeat previous print command (pp)  */
if (cms[1] == 'p')                      /* repeat prior print ?      */
  { /* allow value updt on repeat cmd - pp99                         */
    if (cargs.cmv)
        pargs.cmv = cargs.cmv;
  }
else
  { /* store new search args - but 1st verify (cargs here, pargs below)*/
    if ((cargs.cmv == 0) && (cargs.a2l == 0))
      { errmsg("print cmd must specify number or pattern",cargs.cmd,"",0,0x10);
        return(0);
      }
    pargs = cargs;                      /* store new print args      */
  }
/* verify print a number of records or search pattern                */
if ((pargs.cmv == 0) && (pargs.a2l == 0))
  { errmsg("print cmd must specify number or pattern",pargs.cmd,"",0,0x10);
    return(0);
  }

/*eject*/
/*Aug13/11 - combine iprint into print as option 'i' */
/*         - ensure any prior print file closed      */
if (copsc['i'-'a'])
  { /*Feb05/09 - close file on each iprint (vs all prints to same file) */
    closefileX(pfname,"P",&pfptr,&pfopn,&pfctr,0x00);
  }

/*Feb05/09 - open print file if not already open */
openfileX(pfname,"P",&pfptr,&pfopn,0x00);

/*Jun01/10 - could move prt stats into printrec() condition on 1st printed*/
fprintf(pfptr,"now=%s uvhdcob %s %s\n",todttm,fn1,opsu);
fprintf(pfptr,"version=%s copybook=%s \n",uvversion,fn2d);
fprintf(pfptr,"rec#=%d rcount=%d rsize=%d fsize=%s fptr=%s\n"
             ,recnum1,rcount,rsz1,fsedit,fpedit1);
/* write print command to the output file                            */
fprintf(pfptr,"--> %s \n",pargs.cmd);

/*eject*/
/* print spcfd no of recs, or search by pattern & print to max recs  */
nn=0; fpsv=0; rnsv=0;             /* reset max print ctr        */
while (1)
  { rsz1 = getrec(0);             /* get next record */
    if (rsz1 <= 0)                /* EOF ?           */
      { break;
      }

   /* if search pattern spcfd - search for/print matching recs to max cnt*/
   /*Jan12/11 - fix bug, chg search4 to search234                        */
   if (pargs.a2l)
     { mm = search234(recd,&pargs);   /* 9701 search = > < !             */
       if (mm >= 0)
         { printrec(pfptr);           /* print matching record           */
           nn++;                      /* count records printed (max test)*/
           pfctr++;                   /* count prints for stats          */
           fpsv = fileptr;            /* save fileptr of last matched rec*/
           rnsv = recnum1;            /* save recnum1 last rec matched   */
         }
     }
   else
     { printrec(pfptr);               /* print current record            */
       nn++;                          /* count records printed (max test)*/
       pfctr++;                       /* count prints for stats          */
       fpsv = fileptr;                /* save fileptr of last matched rec*/
       rnsv = recnum1;                /* save recnum1 last rec matched   */
     }

   /* test max print count reached, if so display confirmation & return  */
   if ((pargs.cmv) && (nn >= pargs.cmv))
     { break;
     }

   /* if option f, write formfeed every f# records                  */
   if (copsi['f'-'a'])
     { ff = nn % copsi['f'-'a'];
       if (ff == 0)
          fprintf(pfptr,"\f");
     }

   /* increment fileptr to next record & repeat loop                 */
   /* fileptr += rsz1;  May31/10 replace w upnext/getrec */
 }

/*Feb05/09 - close file on each print (vs all prints to same file) */
/*Dec29/10 - move close print file to EOJ, lp cmd added to close   */
/* closefileX(pfname,"P",&pfptr,&pfopn,&pfctr,0x00); */

/* print loop ended by max count, or EOF + errmsg if no recs printed */
sprintf(opmsg1,"%s --> %d recs printed %s\n",pargs.cmd,nn,pfname);

/*eject*/
if (nn == 0)
  { printf("EOF reached with NO records printed \n");
    return(0);
  }

fileptr = fpsv;   /* so last printed rec will be displayed */
recnum1 = rnsv;   /*Jun03/10 also set recnum1 last updated */
upnext = 0;       /*Jun04/10 inhibit getrec to show up record*/
if (fileptr >= fileptr1)
  { sprintf(opmsg2,"searched to EOF & reset to last record printed\n");
  }
else
  { sprintf(opmsg2,"Last of %d Records Printed shown above\n",nn);
  }

/*Aug13/11 - combine iprint into print as option 'i' */
if (copsc['i'-'a'])
  { /*Feb05/09 - close file on each iprint (vs all prints to same file) */
    closefileX(pfname,"P",&pfptr,&pfopn,&pfctr,0x00);
    strcpy(prtcmdfile,prtcmd);         /* setup uvlp/lp for iprint cmd     */
    strcat(prtcmdfile," ");
    strcat(prtcmdfile,pfname);         /* append iprint filename           */
    system(prtcmdfile);                /* execute uvlp12 tmp/filedatetimeI */
  }
else
  { /*Dec29/10 - add 2nd msg re new cmd 'lp' to close printfile if desired*/
    sprintf(opmsg3,
     "- use 'lp' (close print) for separate files, omit for combined files\n");
  }

return(1);
}

/*eject*/
/*uvhdcob--------------------- printrec -------------------------------*/
/* print current record to the output print file                       */
/* - not used for screen display (which must not exceed screen size)   */
/* - this subrtn will write formatted lines to the print file          */
/*   for the entire record length                                      */

int printrec(FILE *fptr)
{
int bb,cc,ee,ii,ll,ss;
char ww[100];

/*Dec30/10 - fix bug field ctr not reset when printing */
fldctr = 1;

/* output field titles: rec#, fieldname,bgn end typ,field-data        */
fprintf(fptr,"rec#%8d %9s occurs  bgn end typ",recnum1,fnmflag);
fprintf(fptr,"<------ data (hex if typ=p/b) ----->\n");

/* extra space if option s2                                             */
if (opsi['s'-'a'] & 0x02)
  {  fprintf(fptr,"\n");
  }

/*uvhdcob---------------- test record *TYPE ----------------------------*/
/**TYPE=0(1),='N','name-record'  <-- data records with 'N' in byte 0    */
/* if *TYPE table entries stored from begining of cobmap                */
/* - test current data record to *TYPE defs for match                   */
/* - if match, advance up cobmap table for matching fieldname           */
/*   to determine 1st cobmap field to be displayed                      */

/*Jan29/09 - allow record type testing for EBCDIC input                 */
/*         - copy 1st 256 bytes to alt area for testing (max 256)       */
/*         - translate to ASCII if input is EBCDIC                      */
/*Apr04/11 - disable, *TYPE codes now trnsltd to EBCDIC if optn 'a' */
/*         - but not if coded in hex     */
/* memcpy(recda,recd,256);               */
/* if (opsc['a'-'a'])                    */
/*   { toascii2((Uchar*)recda,256,0x00); */
/*   }                                   */

/* init mtibgn = 0 & mtiend = mtimax, assuming no TYPE's present        */
mtibgn = 0;
/* Oct00 - getting extra field blank 0 0 bgn end at end single types    */
/*       - try change: mtiend=mtimax to: mtiend=mtimax-1;               */
mtiend = mtimax-1;

/*eject*/
/* test R/T by code OR (May20/10) by rec-size (RDW,IDX,text) */
if (ttimax)
  { /* set mtibgn/end to bgn/end of 1st type def, in case of nomatch    */
    /* ie - if nomatch, default display to 1st type defined             */
    mtibgn = typtbl[0].mtibgntyp;
    mtiend = typtbl[0].mtiendtyp;

    /* search typtbl for match to current data record                  */
    for (tti=0; tti < ttimax; tti++)
      { typrw = typtbl[tti];          /* move current tbl entry to w/s */

        /*May20/10 - allow TYPE by record-size (for RDW, IDX, text)        */
        /*         - identify alt format by maprec.lvl[0] == 'R' (vs 'T')  */
        /* *TYPE=0(1),='X','recname' <-- original format ID by recType code*/
        /* *TYPE=99:999,'recname'    <-- alternate format ID by Recsize    */
        if (typrw.lvl[0] == 'R')
          { if ((rsz1 >= typrw.bgn) && (rsz1 <= typrw.end))
              { mtibgn = typrw.mtibgntyp;
                mtiend = typrw.mtiendtyp;
                break;
              }
          }
        else
          { /*Apr04/05 - disabled recda, type codes now EBCDIC if 'a' */
            /* cc = memcmp(recda+typrw.bgn,typrw.typ,typrw.lth);      */
               cc = memcmp(recd+typrw.bgn,typrw.typ,typrw.lth);
            if (((typrw.cc[0] == '=') && (cc == 0))
                || ((typrw.cc[0] == '!') && (cc != 0))
                || ((typrw.cc[0] == '<') && (cc < 0))
                || ((typrw.cc[0] == '>') && (cc > 0)))
              { /* RT match - store mtir index for bgn/end display         */
                mtibgn = typrw.mtibgntyp;
                mtiend = typrw.mtiendtyp;
                break;
              }
          }
      }

   if (tti >= ttimax)
     { errmsg("data rec type NOmatch to cobmap *TYPEs - use 1st cobmapdef"
              ,typrw.des,"",0,0x111);
     }
  }

/*eject*/
/* current data record has been matched to an entry in record type table */
/*        - or the mandatory unidentified entry at the end of copybookmap*/
/* mtibgn - points to 1st cobmap entry for identified type               */
/* mtiend - points to 1st cobmap entry for identified type               */
/* mtir   - pointer incremented from mtibgn to mtiend                    */
/*          to display cobmap & data fields in current record type       */

mtir = mtibgn;        /* init mtir to mtibgn, 1st field to display     */
mtib = 0;             /* init mtib 0 in case of partial rec redef      */

/* mtib/mtir used to show base(key) fields till we reach redef type    */
/* store dsp of 1st signif redef fld by advance mtir to 1st with lth   */
while ((mtir < mtimax) && (maptbl[mtir].lth == 0))
  { mtir++;
  }
mtir1dsp = maptbl[mtir].bgn;   /* store dsp of 1st redef fld with lth  */

/*Aug06/11 - init all item occurs controls (not just ooii) */
oonn=0; ooii = 0; ooff=0; ooee=0; oozz=0;

/*Aug03/11 - init group occurs control fields */
/*Sep26/11 - allow nested group occurs 2 levels only */
/*Sep26/11 - clear using grp occurs zero structure */
goc1 = goc0;
goc2 = goc0;
godpb=0; godpl2=0; goffcor1=0; goffcor2=0; 
/*Aug26/11 - clear total record offset for depending on corrections */

/*eject*/
/*Sep30/11 - bgnscreen code (10 lines) removed N/A printrec vs display */

/*uvhdcob---------------- begin line -----------------------------------*/
bgnlinep:
recdend=0;  /*Sep02/11 ensure end field reset for null reply EOS/EOR test*/
/* begin each field format for display(printf)                           */
/* fieldname--------occurs->  bgn end typ<----data (hex if typ=p/b)--->  */
/*        30                     +11        +1      +36            = 78  */
/* current field depends on mtir index into cobmap MAPREC maptbl         */
/* - move current entry to work area for easy access                     */
/* - retrieve data from current record depending on cobmap dsplcmnt & lth*/

/* allow for partial redef record types which omit base(key) fields       */
/* - mtir index points to 1st field in current type (if any)              */
/* - mtib index (init 0) used to display base/key flds til dsp => mtir1dsp*/
/* - mtir1dsp (dsp of 1st redef fld with length) stored above             */
/*Aug13/11 - remove code to display base fields to partial redef records  */
/* - see old solution in versions prior to Aug03/2011                     */
/* - old code used mtibi/mtiri 1/0 or 0/1 to inc base or redef (kludgy)   */
/* - recode use mtir only from 0 base & chg mtir to redef after base fld cnt*/

/* get field from record base(key) until dsp => 1st redef field          */
/* - 1st bypass any 0 lth fields in base record                          */
/*Aug13/11 - remove code to display base fields to partial redef records  */
/* get field from redef record (only rec if no redef types present)  */
/* 1st bypass any 0 lth fields in redef record                       */
while ((maptbl[mtir].lth == 0) && (mtir < mtiend))
  { mtir++;
  }
maprw = maptbl[mtir];        /* store redef/rec field to be displayed*/

/* display 36 bytes max per field, 18 bytes if packed/binary (36 chars)  */
flth1 = maprw.lth;               /* presume fld lth = actual             */
if (flth1 > 36)
    flth1 = 36;                  /* field data retrieve 36 bytes max     */
flth2 = flth1;                   /* presume display lth same as retrieve */

/* if packed/binary - display lth 2 * field length max 36 bytes          */
if ((maprw.typ[0] == 'p') || (maprw.typ[0] == 'b'))
  { flth2 *= 2;                  /* hex display lth = 2 * fldlth         */
    if (flth2 > 36)
        flth2 = 36;              /* p/b display lth 36 bytes max         */
  }

/*eject*/
/*Aug03/11 - test for *BGNOCCURS & store/init Grp OCCurs controls */
/*Aug04/11 - store option g max group occurs desired */
/*Sep26/11 - allow nested group occurs (2 levels only) */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest == 1))
  { goc1.max = maprw.gocmax;   /* occurs count */
    goc1.max1 = goc1.max;      /* save orig to edit in case odo 1 */
    goc1.lth = maprw.goclth;   /* occurs group set total length */
    goc1.ctr = 0;              /* init index for 1st set        */
    goc1.end = opsi['g'-'a'];  /* store group end dsired from optn g */
    /*Aug25/11 - get depending on count if specified */
    /*         - to override max count on *BGNOCCURS */
    if (maprw.godpl)          /* dpo count from *BGNOCCURS on table load ? */
      { godpl2 = maprw.godpl; /* store fld lth in shorter symbol */
        memset(godpc,'\0',12);
        memcpy(godpc,recd+maprw.godps,godpl2);
        /* test dpo data type: packed, binary, numeric */
        /* if packed - retrieve right adjusted into zero filled work area   */
        /*      - then unpack & convert to common format (binary int)       */
        if (maprw.godpt[0] == 'p')             /* dpo count field packed ?  */
          { memset(w2,'\0',21);                /* null fill packed retrieve */
            memcpy(&w2[20-godpl2],godpc,godpl2);
            unpack(w3,w2,0x01);                /* unpack signed (ascii zones)*/
            godpb = atoi(w3);                  /* convert to integer         */
          }
        else if ((maprw.godpt[0] == ' ') && (maprw.godpt[1] == 'n'))
          { godpb = atol2(godpc,'~',8,0x01);
          }
        else /* assume binary 2,4,or 1 */
          { if (godpl2 == 2)                     /* binary short ?         */
              { memcpy((Uchar*)&godpb2,godpc,2); /* retrieve to short w/a  */
                if (LEM)
                  { bswap2((Uchar*)&godpb2);     /* switch big/little ends */
                  }
                godpb = godpb2;                  /* store in common 32 bit int*/
              }
            else if (godpl2 == 4)
              { memcpy((Uchar*)&godpb,godpc,4);  /* assume 4 byte int  */
                if (LEM)
                  { bswap4((Uchar*)&godpb);      /* switch big/little ends */
                  }
              }
            else /*Sep01/11 - assume 1 byte binary pic x */
              { godpb = godpc[0];
              }
          }
        /* validate depending on count retrieved from dpo field */
        if ((godpb > goc1.max) || (godpb < 0))
          { errmsg("occurs depending on field retrieved > max(to) or negative"
                   ,maprw.des,"",0,0x21);
          }
        /* - replace *BGNOCCURS count (max assumed)    */
        goc1.max = godpb;         /* replace max assumed with dpo actual */
      }

/*eject*/
    /*Aug21/11 - convert occurs options g99/o99 to g99999/o99999 */
    if (goc1.end == 99)
      { goc1.end = 99999;
      }
    if (goc1.end > goc1.max)
      { goc1.end = goc1.max;
      }
    if (goc1.end < 1)
      { goc1.end = 1;
      }
    goc1.mti = mtir;         /* save index to *BGNOCCURS for next loop */
    fldctr1 = fldctr;        /* save field ctr of 1st field in group occurs */
    goto nextfieldp;         /* go increment maptbl index to next field */
  }

/*Aug03/11 - test for *ENDOCCURS */
/* - increment grpoccurs ctr & reset to 1st field in group */
/* - if max occurs, clear grpoccurs controls & continue to next field */
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest == 1))
  { goc1.ctr++;               /* increment grp occurs ctr */
    if (goc1.ctr >= goc1.end) /* end count ?              */
      { /*Aug26/11 - calc record dsplcmnt offset for folwng fields */
        /* - significant only when depending on count < occurs to max */
        if (maprw.godpl)
          { goffcor1 = ((maprw.gocmax-godpb) * goc1.lth);
            goffcor2 += goffcor1;
          }
        goc1 = goc0;    /* clear GOC1 structure */
        godpb=0; 
        /*Sep26/11 - not sure about godpb (in structure or not ?)  */
        goto nextfieldp; /* go increment maptbl index to next field */
      }
    else
      { mtir = goc1.mti;  /* reset maptbl index to *BGNOCCURS */
        /*Aug04/11 - restore saved fieldctr on 1st field of group occurs*/
        fldctr = fldctr1;
        goto nextfieldp; /* go increment maptbl index to next field */
      }
  }

/*eject*/
/*Sep26/11 - add 2nd level nested group occurs */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest == 2))
  { goc2.max = maprw.gocmax;   /* occurs count */
    goc2.max1 = goc1.max;      /* save orig to edit in case odo 1 */
    goc2.lth = maprw.goclth;   /* occurs group set total length   */
    goc2.ctr = 0;              /* init index for 1st set          */
    goc2.end = opsi['g'-'a'];  /* same optn as goc level 1 */
    if (goc2.end > goc2.max)
      { goc2.end = goc2.max;
      }
 /* goc2.end = goc2.max;   might show all occurrences of level 2 */
    goc2.mti = mtir;      /* save index to *BGNOCCURS for next loop */
    fldctr2 = fldctr;     /* save field ctr of 1st field in group occurs */
    goto nextfieldp;      /* go increment maptbl index to next field */
  }

/*Sep26/11 - add 2nd level nested group occurs */
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest == 2))
  { goc2.ctr++;               /* increment grp occurs ctr */
    if (goc2.ctr >= goc2.end) /* end count ?              */
      { /*Aug26/11 - calc record dsplcmnt offset for folwng fields */
        /* - significant only when depending on count < occurs to max */
        if (maprw.godpl)
          { /*Sep27/11 - godpb N/A to 2nd level nested occurs */
            /* goffcor1 = ((maprw.gocmax-godpb) * goc2.lth); */
            goffcor1 = ((maprw.gocmax) * goc2.lth); 
            goffcor2 += goffcor1; 
          }
        goc2 = goc0;     /* clear GOC2 structure */
        goto nextfieldp; /* go increment maptbl index to next field */
      }
    else
      { mtir = goc2.mti;  /* reset maptbl index to *BGNOCCURS */
        /*Aug04/11 - restore saved fieldctr on 1st field of group occurs*/
        fldctr = fldctr2;
        goto nextfieldp;  /* go increment maptbl index to next field */
      }
  }

/*Sep27/11 - errmsg if group occurs nested > 2 */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest > 2))
  { errmsg("group occurs nested > 2 levels unsupported",maprw.des,"",0,0x11);
  }
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest > 2))
  { errmsg("group occurs nested > 2 levels unsupported",maprw.des,"",0,0x11);
  }

/*eject*/
/*Aug03/11 - calc group occurs offset (0 if *BGNOCCURS not stored) */
goc1.off = (goc1.lth * goc1.ctr);
goc2.off = (goc2.lth * goc2.ctr);
/*Sep26/11 - not sure about offset calc for 2nd level nested occurs */
goctoff = (goc1.off + goc2.off);
/*         - try add together in goctoff & use that below           */

/* get occurs value from current maptbl rec */
oonn = maprw.occurs;   

/*Aug04/11 - store item occurs end count from option 'o' */
ooee = opsi['o'-'a'];
/*Aug21/11 - convert occurs options g99/o99 to g99999/o99999 */
if (ooee == 99)
  { ooee = 99999;
  }
if (ooee > oonn)
  { ooee = oonn;
  }
if (ooee < 1)
  { ooee = 1;
  }

/* calc occurs offset = (current occurs index * field length) */
ooff = (ooii * maprw.lth);

/* retrieve data from record, depending on cobmap dsplcmnt & occurs index*/
/* init retrieve area to all blanks                                      */
/* after data insert, scan back form right & insert null after nonblank  */
memset(fdat1,' ',50);               

/*Aug03/11 - calc group occurs offset above (as well as item occurs offset) */
/*Aug26/11 - calc total record offset including dpo correction occurs < max */
recdoff = (maprw.bgn-goffcor2+goctoff+ooff);
if ((maprw.bgn-goffcor2) < 0)
  { errmsg("occurs depending on field correction error",maprw.des,"",0,0x21);
  }
/*Sep02/11 - calc end field dsplcmnt for null reply EOS/EOR test */
recdend = (maprw.bgn-goffcor2+goctoff+ooff+maprw.lth+rdwhs);

/*Aug22/11 - test end record when occurs depending on & varlth records */
if (recdoff >= rsz1)
  { mtir = mtiend+1;   /* to force end screen */
    goto endrecp;      /* endscreen display chg to endrecp printrec */
  }

sncopy(fdat1,recd+recdoff,flth1,0x00);  /* retrieve record field data */

/* copy data to display area - in case not binary/packed              */
/* (if binary/packed fdat2 will be overwritten with hexcodes          */
memcpy(fdat2,fdat1,50); 
/* ensure printable chars - translate any unprintables to '.' periods */
/* - can't do here if EBCDIC, but toascii2 0x04 will do below         */

/*Feb25/11 - clear hex for bad fields > 9 bytes on 2nd line */
memset(fdat4,'\0',40);               

/*eject*/
/* if packed - convert to horizontal hex display */
/* - verify & flag on right if bad digits/sign   */
if (maprw.typ[0] == 'p') 
  { data2hex(fdat2,fdat1,flth2,0x00);
    /*Jan10/11 - optn x1/x2/x4 inhibit validity check num/pack/char fields*/
    if (!(opsi['x'-'a'] & 0x02) || (opcmd[0] == 'v'))
      { ss = verifyp(fdat1,flth1,0x00);
        if (ss)
          { strcpy(fdat2+30,"<-BadP");
          }
      }
    sigval = testnp(fdat1,flth1); /*test inhibit display zero occurs fields*/
  }
else if (maprw.typ[0] == 'b') 
  { /* if binary - convert to horizontal hex display */
    /*           - show decimal value on right side  */
    data2hex(fdat2,fdat1,flth2,0x00);
    showdcmls(fdat2,fdat1,flth1);
    sigval = testnb(fdat1,flth1); /*test inhibit display zero occurs fields*/
  }
else if (maprw.typ[1] == 'n') 
  { /* if numeric data, test option 'a' translate EBCDIC to ASCII      */
    /* - bit 0x04 converts non-printable EBCDIC chasr to periods       */
    if (opsc['a'-'a'])                /* option 'a' (EBCDIC to ASCII)  */
      { toascii2((Uchar*)fdat2,flth1,0x04); /* translate EBCDIC to ASCII*/
      }
    /* replace unprintables with '.'s*/
    toprint2((Uchar*)fdat2,flth1,trtprint,0x00); 
    /* check chardata (in fdat1) for nonnumerics & show hex on right   */
    /* - will store fdat2 to print, will test fdat1 for nonnumerics    */
    /*Jan10/11 - optn x1/x2/x4 inhibit validity check num/pack/char fields*/
    if (!(opsi['x'-'a'] & 0x01) || (opcmd[0] == 'v'))
      { badn2hex(fdat2,fdat1,flth1);
      }
    sigval = testnn(fdat2,flth1); /*test inhibit display zero occurs fields*/
  }
else
  { /* if char data, test option 'a' translate EBCDIC to ASCII display */
    /* - bit 0x04 converts non-printable EBCDIC chasr to periods       */
    if (opsc['a'-'a'])                /* option 'a' (EBCDIC to ASCII)  */
      { toascii2((Uchar*)fdat2,flth1,0x04); /* translate EBCDIC to ASCII*/
      }
    toprint2((Uchar*)fdat2,flth1,trtprint,0x00); 
    /* check chardata (in fdat1) for unprintables & show hex on right  */
    /* - will store fdat2 to print, will test fdat1 for unprintables   */
    /*Jan10/11 - optn x1/x2/x4 inhibit validity check num/pack/char fields*/
    if (!(opsi['x'-'a'] & 0x04) || (opcmd[0] == 'v'))
      { bad2hex(fdat2,fdat1,flth1);
      }
    sigval = testnc(fdat2,flth1); /*test inhibit display zero occurs fields*/
  }

/*eject*/
/*Sep04/11 - calc record data begin/end */
/* - use on screen for begin/end (+1 below if option c1) */
bb = (maprw.bgn + goctoff + ooff - goffcor2);
ee = (maprw.end + goctoff + ooff - goffcor2);

/*Sep03/11 - add subrtn lookmap to find maptbl index for matched field */
/*         - to show search match field on 1st screen of long records  */
/*Sep04/11 - show search match on 1st screen problem fix for occurs    */
/*         - change maptbl index to data dsplcmnt corrected for occurs */
/* if ((recdmatch) && (linectr >= 16)) ... goto nextfield */
/*Sep30/11 - code removed n/a to printrec, see display */

/*Aug13/11 - test option i4 to inhibit display of ALL 0/blank fields */
if (opsi['i'-'a'] & 0x04)
  { if (!sigval)
      { goto nextfieldp;   /* go increment maptbl index to next field */
      }
  }

/*Aug04/11 - test option to bypass zero/blank occurs fields after 1st  */
/*         - if option v1+ coded on last g/o cmd for group/item occurs */
/*Aug13/11 - occurs optn v1 chgd to optn 'i', can set via cmd 'i'      */
if ((goc1.ctr > 0) && (opsi['i'-'a'] & 0x02))
  { if (!sigval)
      { goto nextfieldp; /* go increment maptbl index to next field */
      }
  }
if ((ooii > 0) && (opsi['i'-'a'] & 0x01))
  { if (!sigval)
      { goto nextfieldp; /* go increment maptbl index to next field */
      }
  }

/* zero suppress dsplcmnt & length for display          */
/*Feb24/11 - change optn 'g' (0/1 relative) to optn 'c' */
if (opsi['c'-'a'] & 0x01)
  { uvedit(zbgn,4,bb+1,"zzz9",0x02);
    uvedit(zend,4,ee+1,"zzz9",0x02);
  }
else
  { uvedit(zbgn,4,bb,"zzz9",0x02);
    uvedit(zend,4,ee,"zzz9",0x02);
  }
uvedit(zlth,4,maprw.lth,"zzz9",0x02);

/*eject*/
/*Dec27/10 - removed option 'n' inhibit seq# field on left of screen */
memset(fldnam,' ',30);
sprintf(ww,"%03d",fldctr);
memcpy(fldnam,ww,3);
sncopy(fldnam+4,maprw.fnm,30,0x01);

/* insert occurs counters: currentoccurs/maxoccurs       */
/*Sep27/11 - prioritized: item, grouplevel2, grouplevel1 */
if (oonn > 1)
  { sprintf(ww," %d/%d ",ooii+1,oonn);
    ll = strlen(ww);
    bb = 30 - ll;
    memcpy(fldnam+bb,ww,ll);
  }
else if (goc2.max > 1)
  { sprintf(ww," %d/%d ",goc2.ctr+1,goc2.max);
    ll = strlen(ww);
    bb = 30 - ll;
    memcpy(fldnam+bb,ww,ll);
  } 
else if (goc1.max1 > 1)
  { sprintf(ww," %d/%d ",goc1.ctr+1,goc1.max);
    ll = strlen(ww);
    bb = 30 - ll;
    memcpy(fldnam+bb,ww,ll);
  } 

fldnam[30] = '\0';      /* set fieldname length = 30 */

/*Sep30/11 - insert 'Bad@ 1234' code removed N/A to print vs display*/

/* now scan back from right & insert null after last non-blank */
for (ii=40; ii > 1; ii--)
  { if (fdat2[ii] != ' ')
      { break;
      }
  }
fdat2[ii+1] = '\0';         /* insert null after last non-blank */

/*Sep30/11 - insert bold control codes removed N/A to printrec vs display*/

/*eject*/
/* display currentline: <--fieldname occurs->  bgn end typ<---data--->  */
/*Oct13/10 - insert space between bgn/end (John Faulhaber IBM)          */
fprintf(fptr,"%-30s%4s %4s%3s %s\n",fldnam,zbgn,zend,maprw.typ,fdat2);

/*Feb25/11 - show hex for bad fields > 9 bytes on 2nd line                 */
if (fdat4[0])
  { fprintf(fptr,"%-43s%s\n"," ",fdat4);
    linectr++;                     /* incrmnt ctr for extra line */
  }
linectr++;                                        /* increment line ctr */

/*Aug06/11 - nextfieldp: increment maptbl index here (vs bgnline) */
/*         - unless displaying item occurs                       */
/*         - jump here if current field display inhibited        */
nextfieldp:

/* increment occurs index for next occurs (if any) */
ooii++;

/* if last occurs for this field - increment maptbl index for next field*/
if (ooii >= ooee)
  { mtir++;              /* increment maptbl index to next field */
    ooii = 0;            /* reset occurs index for next field    */
    ooee = 0;            /*Aug17/11 also occurs end fix bug loop */
  }

/*Aug04/11 - increment field ctr - on 1st occurrence of item occurs */
/*         - also on group occurs & on non-occurs since ooii=0      */
/*Aug13/11 - move here to seq# fields inhibited by optn 'i' 0/blank */
if ((ooii < 1) && (memcmp(maprw.des,"*BGNOCC",7))
               && (memcmp(maprw.des,"*ENDOCC",7)))
  { fldctr++;
  }

if ((mtir > mtiend)) /* || (linectr >= linemax)) */
                     /*Sep30/11 - n/a to printrec, see display */
  { goto endrecp;      /* endscreen display chg to endrecp printrec */
  }

/*Sep02/11 - test last field in record for occurs depending on */
/* recdend = (maprw.bgn-goffcor2+goctoff+ooff+maprw.lth+rdwhs); prior calc*/
if (recdend >= rsz1)
  { goto endrecp;      /* endscreen display chg to endrecp printrec */
  }

goto bgnlinep;

/*Aug23/11 - insert tag endrecp for occurs depending end of record */
endrecp:

/* end fields for current record - space between records                 */
fprintf(fptr,"\n");

return(1);
}

/*eject*/
/*uvhdcob--------------------- write1 ---------------------------------*/
/* write specified number of records                                   */
/* - or records matching a pattern, to a specified maximum             */
/*                                                                     */
/* w5                        - write next 5 records                    */
/*                                                                     */
/* w5e4x 0(20),='ABC'        - search for & write records with 'ABC'   */
/*                             within 1st 20 bytes to max 5 recs       */
/*                           - write Every 4th record (option e4)      */
/*                           - write other records to 2nd write file   */
/*                             (tmp/filename.datetimeX vs W)           */
/*                                                                     */
/* ww                        - repeat previous write                   */
/*                                                                     */
/* - if nofind set fileptr to last rec in file & return 0              */

int write1(void)
{
int nn;             /* max records search ctr       */
int mm;             /* search find/nofind 0+/-      */
int ii;             /* recs dropped by DISAM flag   */
int tt;             /* count for every nth select   */
int ww;             /* set if current record written*/
int xx;             /* count non-matched recs written*/
int yy;             /* count non-matched recs til EOF*/

upnext = 0;         /* inhibit getrec() advance nextrec */

/* test for 'w=s' transfer last search cmd to write cmd storage structure */
if ((cms[1] == '=') && (cms[2] == 's'))
  { wargs = sargs;              /* store write cmd from last search cmd */
    wargs.cmd[0] = 'w';         /* change cmd from 's' to 'w'           */
    wargs.cmc[0] = 'w';         /* change cmc from 's' to 'w'           */
    printf("write args stored from last search: %s \n",wargs.cmd);
    printf("execute 'ww' to write spcfd records from current to EOF --> ");
    return(2);
  }

/* test for new write command or repeat previous write command (ww)  */
if (cms[1] == 'w')                      /* repeat prior write ?      */
  { /* allow value updt on repeat cmd - ww99                         */
    if (cargs.cmv)
        wargs.cmv = cargs.cmv;
  }
else
  { /* store new search args - but 1st verify (cargs here, pargs below)*/
    if ((cargs.cmv == 0) && (cargs.a2l == 0))
      { errmsg("write cmd must specify number or pattern",cargs.cmd,"",0,0x10);
        return(0);
      }
    wargs = cargs;                      /* store new write args      */
  }
/* verify write a number of records or search pattern */
if ((wargs.cmv == 0) && (wargs.a2l == 0))
  { errmsg("write cmd must specify number or pattern",cargs.cmd,"",0,0x10);
    return(0);
  }

/*eject*/
/*Feb05/09 - common functions openfileX & closefileX for P,I,W,V,D files*/
/*         - chg P/I/W/V/D cmds to open & close output file on each cmd */
/*         - cmd line option w1 to write 1 combined file vs separate    */
/*         - filename format as follows:                                */
/* $UVTMPDIR/inputfilename_yymmdd_hhmmssX               <-- X=P/I/W/V/D */
/* $UVTMPDIR/inputfilename_yymmdd_ <-- basefilename + time + X each open*/

/*Feb05/09 - call function to open file on 1st write (depending optn w1)*/
openfileX(wfname,"W",&wfptr,&wfopn,0x00);

/* write spcfd no of recs, or search by pattern & write to max recs  */
nn=0; ii=0; fpsv=0; rnsv=0; tt=0; xx=0; yy=0;   /* clear counters    */
while (1)
  { rsz1 = getrec(0);             /* get next record */
    if (rsz1 <= 0)                /* EOF ?           */
      { break;
      }
   ww = 0;                            /* reset switch cur rec written   */

   /* if option 'i' spcfd - drop if x'00' in last byte (ISAM deleted) */
   /*Dec24/10 - delete this option */

   /* if search pattern spcfd - search for & write matching recs to max cnt*/
   if (wargs.a2l)
    { mm = search234(recd,&wargs);   /* 9701 search = > < !            */
      if (mm >= 0)
       { /* test option e to write every nth record                     */
         tt++;                       /* count all matches for every nth test*/
         if (wargs.opi['e'-'a'])
          { if ((tt % wargs.opi['e'-'a']) == 0)
             { writerec();           /* write matching record           */
               nn++;                 /* count records written (max test)*/
               ww++;                 /* set sw cur rec written          */
               fpsv = fileptr;       /* save fileptr of last matched rec*/
               rnsv = recnum1;       /* save recnum1 last rec matched   */
             }
          }
         else
          { writerec();              /* write matching record           */
            nn++;                    /* count records written (max test)*/
            ww++;                    /* set sw cur rec written          */
            fpsv = fileptr;          /* save fileptr of last matched rec*/
            rnsv = recnum1;          /* save recnum1 last rec matched   */
          }
       }
    }
/*eject*/
   else
    { /* test option e to write every nth record                     */
      tt++;                          /* count all matches for every nth test*/
      if (wargs.opi['e'-'a'])
       { if ((tt % wargs.opi['e'-'a']) == 0)
          { writerec();              /* write matching record           */
            nn++;                    /* count records written (max test)*/
            ww++;                    /* set sw cur rec written          */
            fpsv = fileptr;          /* save fileptr of last matched rec*/
            rnsv = recnum1;          /* save recnum1 last rec matched   */
          }
       }
      else
       { writerec();                 /* write current record            */
         nn++;                       /* count records written (max test)*/
         ww++;                       /* set sw cur rec written          */
         fpsv = fileptr;             /* save fileptr of last written rec*/
         rnsv = recnum1;             /* save recnum1 last rec matched   */
       }
    }

   /* increment fileptr to next record & repeat loop                 */
   /* fileptr += rsz1;  May31/10 replace w upnext/getrec */

   /* test max write count reached, if so display confirmation & return */
   if ((wargs.cmv) && (nn >= wargs.cmv))
     { break;
     }
 }

/* write loop ended by max count, or EOF - show stats */
sprintf(opmsg1,"%s %d records written to: %s\n",wargs.cmd,nn,wfname);

/*Jun05/10 - chg opmsg1 to show ISAM deleted records if any   */
/*Dec29/10 - remove ISAM deleted code                         */
/* if (ii >= 1)                                               */
/*   { sprintf(opmsg1,"%s %d written, %d dropped(ISAM), %s\n" */
/*                  ,wargs.cmd,nn,ii,wfname);                 */
/*   }                                                        */

if (fileptr >= fileptr1)
  { sprintf(opmsg2,"searched to EOF & reset to last record written\n");
  }
else
  { sprintf(opmsg2,"Last Record Written shown above\n");
  }

/*Dec29/10 - add 2nd msg re new cmd 'lp' to close printfile if desired*/
sprintf(opmsg3,
        "- use 'lw' (close write) for separate files, omit for combined\n");

/*eject*/
/* if option x2, continue to write 2nd file until EOF reached */
/*Feb05/09 - removed */

/*Feb05/09 - close file, inhibit if cmd line optn w1 for 1 file all writes*/
/*Dec29/10 - cmd 'l' added to close files as desired, disable close here  */
/*         - remove option w1 to write 1 file or separate files           */
/* if (!((opsi['w'-'a']) & 0x01))                   */
/*   { closefileX(wfname,"W",&wfptr,&wfopn,&wfctr,0x00); } */

if (nn == 0)
  { printf("EOF reached with NO records written \n");
    return(0);
  }
else
  { fileptr = fpsv;   /* so last written rec will be displayed */
    recnum1 = rnsv;   /*Jun03/10 also set recnum1 last updated */
    upnext = 0;       /*Jun04/10 inhibit getrec to show up record*/
  }

return(1);
}

/*eject*/
/*uvhdcob--------------------- writerec --------------------------------*/
/* write current record to output file                                  */
/*May19/10 - writerec updated from uvhd into this uvhdcob               */
/*         - optn t1/t2 to append CR/LF & increase recsize              */

int writerec(void)
{
int ii;
int ss;
int nn;
int dd;         /*Nov25/10 - option d dsplcmnt to 1st byte to write    */
char wrsc[8];   /*Nov08/07 recsize numeric chars insert by option k1/k2*/

/* test options n1/n2 for 4 byte numeric recsize at begin/end data record */
wrsn1 = 0; wrsn2 = 0;
if (wargs.opi['n'-'a'] & 0x01)
  { wrsn1 = 4;
  }
else if (wargs.opi['n'-'a'] & 0x02)
  { wrsn2 = 4;
  }
wrsn3 = wrsn1 + wrsn2;  /* combine (4 or 0) for easier calcs below */

/*Feb07/09 - calc actual data size depending on input file type     */
/* - OK to subtract hdr sizes for both RDW & IDX (will be 0 if n/u) */
rsz1d = (rsz1 - rdwhs - vrhs);

/*eject*/
/* determine write rcsz - option r if spcfd, else (current-rcsz - dd)  */
/*Nov25/10 - if no optn r, write size = cur-rcsz - dd (dd 0 if unspcfd)*/ 
dd = wargs.opi['d'-'a'];             /* capture optn d for convenience */
if (wargs.opi['r'-'a'])
  { wrs1w = wargs.opi['r'-'a'];
  }
else
  { wrs1w = (rsz1d - dd);            /* presume I/O write = data*/
    if (wrs1w < 0)
      { wrs1w = 4;
      }
  }

/* test write options z2/z4 for RDW output            */
/* - set prefix size & store prefix in outrec area    */
wrs1h = rsz1d;                       /* presume size in hdr = data-size */

/* test write options z2/z4 for RDW output            */
/* - set prefix size & store prefix in outrec area    */
if (wargs.opi['z'-'a'] & 0x02)
  { wrhs = 2;                        /* store RDW hdr size      */
    wrs1w += (2 + wrsn3);            /* I/O write size          */
    wrs1h += (0 + wrsn3);            /* value in RDW hdr same   */
    memcpy(wrecb,u2.cc,2);
  }
else if (wargs.opi['z'-'a'] & 0x0C)  /*Jan14/11 - z4 or z8      */
  { wrhs = 4;                        /* store RDW hdr size      */
    wrs1w += (4 + wrsn3);            /* I/O write size          */
    wrs1h += (4 + wrsn3);            /* value in RDW hdr same   */
    memcpy(wrecb,u2.cc,4);
  }
else
  { wrhs = 0;
  }

/* create recsize prefixes in case of options z2/z4 with possible z1 */
/* - allow for BIG-end/littel-end machine                            */
/* - allow for option z1 to create little end format                 */
wrs1hs = wrs1h;                 /* move int recsize to short */
memset(u1.cc,'\0',4);           /* init union to switch ends */
memcpy(u1.cc,(char*)&wrs1hs,2); /* copy short into union     */
memcpy(u2.cc,u1.cc,4);          /* copy to output in case no switch req'd*/

/* if BEM - we are done (unlikely to use option z1) */
/* if LEM & option z1 we are done */
/* if LEM & not option z1, we need to switch ends   */
#if (LEM)
if (!(wargs.opi['z'-'a'] & 0x01))
  { u2.cc[0] = u1.cc[1];
    u2.cc[1] = u1.cc[0];
  }
#endif

/* calc input record data adrs = base adrs + any IDX or RDW prefix size */
irecd = (recb + vrhs + rdwhs);

/* calc adrs for out record data = base + z2/z4 offset + n1 offset */
wrecd = (wrecb + wrhs + wrsn1);

/*eject*/
/* clear wrec area to allow for variable length records  */
/* - clear min 2048 or rsz1 if larger                    */
if (rsz1 > 2048)
  { nn = rsz1; }
else
  { nn = 2048; }
/*Nov08/07 - clear to ASCII blank default, but EBCDIC blank if option a */
if (opsc['a'-'a'])
  { memset(wrecd,0x40,nn);       /* clear write area to EBCDIC blanks */
  }
else
  { memset(wrecd,0x20,nn);       /* clear write area to ASCII blanks  */
  }

/* store RDW hdr if any */
if (wargs.opi['z'-'a'] & 0x02)
  { memcpy(wrecb,u2.cc,2);
  }
else if (wargs.opi['z'-'a'] & 0x0C)  /*Jan14/11 - z4 or z8      */
  { memcpy(wrecb,u2.cc,4);
  }

/*Jan14/11 - allow option z8 write BDW = RDW+4 (on every record) */
if (wargs.opi['z'-'a'] & 0x08)
  { u3 = u1;
    u3.ss += 4;                    /* BDW size = RDW size + 4 */
    u4 = u3;                       /* done if BEM */
#if (LEM)
    if (!(wargs.opi['z'-'a'] & 0x01))
      { u4.cc[0] = u3.cc[1];
        u4.cc[1] = u3.cc[0];
      }
#endif
    ss = fwrite(u4.cc,1,4,wfptr);  /* write BDW */
    if (ss <= 0)
      { errmsg("writing BDW to output file",wargs.cmd,wfname,0,0x40);
      }
  }

/* copy input data to write output area */
/*Feb07/09 - copy just the data size from input record */
/*Nov25/10 - allow option 'd' dsplcmnt of 1st byte to write */
memcpy(wrecd,irecd+dd,rsz1d);

/*Nov08/07 - test option a1 to translate write records to ASCII      */
if (wargs.opi['a'-'a'] & 0x01)
  { toascii2((Uchar*)wrecd,wrs1w,0x00);
  }
/*Apr16/08 (Uchar*) inserted for HP compile warning mismatch ptr types*/

/* translate any unprintable chars to '.' periods if option c1 */
if (wargs.opi['c'-'a'] & 0x01)
  { toprint2((Uchar*)wrecd,wrs1w,trtprint,0x00);
  }

/*eject*/
/*Nov08/07 - insert recsize as 4 numeric characters if option n1/n2     */
/*           (n1 = insert at begin record, n2 = insert at end record)   */
/*Feb09/09 - fix write optn n1/n2, insert input size, not optn r outsize*/
/*         - assume user wants input data & not any optn r fixed size   */

/* calc adrs to insert option n1 numeric recsize (if any) */
wrecn1 = (wrecb + wrhs);

/* calc adrs for option n2 numeric recsize (if any) */
wrecn2 = (wrecb + wrs1w - 4);

sprintf(wrsc,"%04d",rsz1d);   /* convert input data size to digits */

/* if optin n1/n2 - insert write size at begin/end record */
if (wargs.opi['n'-'a'] & 0x01)
  { memcpy(wrecn1,wrsc,4); 
  }
else if (wargs.opi['n'-'a'] & 0x02)
  { memcpy(wrecn2,wrsc,4);
  }

/*eject*/
/* if option t4 - insert CR/LF terminator after last nonblank     */
/*Feb09/09 - fix write optn t4, scan back not writing shorter size*/
if (wargs.opi['t'-'a'] & 0x04)
  { for (ii=wrs1w-1; ii > 8; ii--)
      { if ((Uchar)wrecb[ii] > 0x20)
          { break;
          }
      }
    if (wargs.opi['t'-'a'] & 0x01)
      { wrecb[++ii] = '\r';
        ii++;
      }
    if (wargs.opi['t'-'a'] & 0x02)
      { wrecb[++ii] = '\n';
        ii++;
      }
    wrs1w = ii;       /*Feb09/09 - write size ending at LineFeed*/
  }
else /* not t4 after LNB - append CR/LF at end rec & increase recsz */
  {  /*Dec11/07 - ensure fixed size = optn w independent optns p,k  */
     /*         - but terminators extra depending optn t1,t2,t3     */
     /*Feb05/09 - terminator chgd from addon to within recsize      */
     /*May19/10 - change terminator back to following recsize       */
     /*         - losing data if input is RDW                       */
    if ((wargs.opi['t'-'a'] & 0x01) && (wargs.opi['t'-'a'] & 0x02))
      { wrecb[wrs1w] = '\r';
        wrecb[wrs1w+1] = '\n';
        wrs1w += 2;
      }
    else if (wargs.opi['t'-'a'] & 0x01)
      { wrecb[wrs1w] = '\r';
        wrs1w++;
      }
    else if (wargs.opi['t'-'a'] & 0x02)
      { wrecb[wrs1w] = '\n';
        wrs1w++;
      }
  }

ss = fwrite(wrecb,1,wrs1w,wfptr); /* write to output file#1 */
if (ss <= 0)
  { errmsg("writing output file",wargs.cmd,wfname,0,0x40);
  }
wfctr++;                          /* count writes */

return(1);
}

/*eject*/
/*uvhd------------------------- update --------------------------------*/
/*Dec08/10 - update imported from uvhd to uvhdcob                      */
/*         - allow constant lth < op1 lth & clear excess to blanks     */
/*Note - uvhdcob updates area 'recd' vs 'recb' for uvhd                */
/*     - RDW recs have prefix in recb (preceding recd)                 */
/*     - code below has 4 'recb's & 6 'recd's                          */
/*                                                                     */
/* update current record - return 1 if ok, 0 if any error              */
/*                   - sample commands follow:                         */
/*  u 0(3),='ABC'    - change 1st 3 bytes of current record to 'ABC'   */
/*  u 10(3),=x'0D0A' - change bytes 11&12 of current record to x'0D0A' */
/*  uu               - repeat prior update (on current record)         */

int update(void)
{
int uu;         /* records updated counter          */
int nn;         /* records read searching for updts */
int ss;         /* op3/4 & op4/5 qualify status     */
int ll;         /* excess lth to clear if op1 lth > op2 lth */
int op1l;       /*Aug13/11 - op1 lth 99 changed to current recsize */

upnext = 0;     /* inhibit advance to next record on 1st getrec */
uu=0; nn=0;     /* clear counters */
fpsv=0; rnsv=0; 

/* verify option u to allow update */
if ((opsc['u'-'a']) == 0)
  { printf(">>>UPDATE requires option u on uvhd command line<<<\n");
    showhelp(help07,25,0x01);
    printf(">>>UPDATE requires option u on uvhd command line<<<\n");
    exit(9);
  }

/* save record for possible roll-back of last update to current record */
memcpy(recsav2,recb,rsz1);        /* save record for possible roll-back*/

/* save record for possible roll-back of multi updts to current record */
/* IE - save only if cur fileptr not = fileptr of last updt            */
if (fileptr != fplastup)
    memcpy(recsav1,recb,rsz1);   /* save rec for multi updt roll-back  */


/* test for new update or repeat previous update                      */
if (cms[1] == 'u')                      /* repeat prior update ?      */
  { /* trsfr any multi-rec count from uu99 to stored uargs structure  */
    /* - to allow user to test update on 1 record, then repeat on all */
    uargs.cmv = cargs.cmv;              /* update multi-rec count     */
  }
else
  { /* store new search args - but 1st verify (cargs here, uargs below)*/
    if ((cargs.a1l <= 0) || (cargs.a2l <= 0))
      { errmsg("update args invalid",cargs.cmd,"",0,0x10);
        return(0);
      }
    uargs = cargs;                 /* store new search args */
  }

/*eject*/
/* verify update args - op1 lth & op2 constant lth > 0 ? */
if ((uargs.a1l <= 0) || (uargs.a2l <= 0))
  { errmsg("update args invalid",uargs.cmd,"",0,0x10);
    return(0);
  }

/*Aug13/11 - chg update to convert op1 lth 99 to current recsize      */
/*           & if op2 1 byte, then memset all op1 lth to op2 constant */
if (uargs.a1l == 99)
  { op1l = rsz1;
  }
else
  { op1l = uargs.a1l;
  }

/*Dec07/10 - verify update op1 dsp+lth not > recsize */
/*Aug13/11 - allow if op1 lth 99 (converted to current recsize above) */
if ((uargs.a1d + op1l > rsz1) && (uargs.a1l != 99))
  { errmsg("update op1 dsplcmnt+length > recsize",uargs.cmd,"",0,0x10);
    return(0);
  }

/*Jun04/10 - test option to transfer update args to search args */
/*         - for subsequent 'ss' to verify updates              */
if (uargs.opc['s'-'a'])
  { sargs = uargs;       /* transfer updt args to search args */
    sargs.a4l = 0;       /* disable search on op4,5,6         */
    sargs.a5l = 0;   
    sargs.a6l = 0;
  }

/*eject*/
/* instruction verified - test for multi-rec update or just current  */
/* 1 rec updt allows multi-field updts & roll-back, multirec does not*/
if (uargs.cmv == 0)
  { /* qualify record if op3/op4 &/or op5/op6 spcfd (may be AND/OR)       */
    ss = search34(recd,&uargs);         /* search for op3/4 &/or op5/6    */
    if (ss > 0)
      { /* move constant data into record                                 */
        /*Aug13/11 - chg update to convert op1 lth 99 to current recsize  */
        /*           if op2 1 byte, then memset all op1 lth to op2 constant*/
        if (uargs.a2l == 1)
          { memset(recd+uargs.a1d,uargs.a2c[0],op1l);
          }
        else
          { sncopy(recd+uargs.a1d,uargs.a2c,op1l,0x00);
            /*Dec07/10 - allow update constant lth < op1 lth & blank excess  */
            if (op1l > uargs.a2l)
              { ll = (op1l - uargs.a2l);
                memset(recd+uargs.a1d+uargs.a2l,AEB,ll);
              }
          }

        /* rewrite the record & store fileptr for possible roll-back      */
        fileseek("update 1");

        writestat = write(fd1,recb,rsz1);
        if (writestat < 0)
            errmsg("updt write err",fn1,"",0,0x40);
        fplastup = fileptr;             /* save fileptr of last rec updtd */

        /* show update command - if uu vs original (already on screen)    */
        sprintf(opmsg1,"above record updated - %s \n",uargs.cmd);
      }
  }

/*eject*/
else
 {/* multi-record update, from cur fileptr for count spcfd or til EOF*/
  /* u99 0(3),'ABC'                                                  */
  while(1)
   { rsz1 = getrec(0);
     if (rsz1 <= 0)
      { sprintf(opmsg1,"EOF, %d records read, %d updated %s\n",nn,uu,uargs.cmd);
         /* if any records updated, set fileptr to last rec updated   */
         if (uu)
           { fileptr = fpsv;
             recnum1 = rnsv; /*Jun03/10 also set recnum1 last updated   */
             upnext = 0;     /* inhibit getrec to display correct record*/
             sprintf(opmsg2,"searched to EOF & reset to last record updated\n");
           }
         else
           { ; 
           }
         break;
       }
     nn++;                              /* count recs read for max test*/

     /* qualify record if op3/op4 &/or op5/op6 spcfd (may be AND/OR)       */
     ss = search34(recd,&uargs);         /* search for op3/4 &/or op5/6    */

     if (ss < 0)
       { /* fileptr += rsz1;  May25/10 replace w getrec(0) */
         continue;
       }

    /*Aug13/11 - chg update to convert op1 lth 99 to current recsize      */
    /*           & if op2 1 byte, then memset all op1 lth to op2 constant */
    if (uargs.a1l == 99)
      { op1l = rsz1;
      }
    else
      { op1l = uargs.a1l;
      }

    /*Aug13/11 - chg update to convert op1 lth 99 to current recsize  */
    /*           if op2 1 byte, then memset all op1 lth to op2 constant*/
    if (uargs.a2l == 1)
      { memset(recd+uargs.a1d,uargs.a2c[0],op1l);
      }
    else
      { sncopy(recd+uargs.a1d,uargs.a2c,op1l,0x00);
        /*Dec07/10 - allow update constant lth < op1 lth & blank excess  */
        if (op1l > uargs.a2l)
          { ll = (op1l - uargs.a2l);
            memset(recd+uargs.a1d+uargs.a2l,AEB,ll);
          }
      }

/*eject*/
     /* seek to current record & rewrite                               */
     /* May2001: fseek changed to call fileseek (largefiles lseek/lseek64) */
     fileseek("update multiple");

     writestat = write(fd1,recb,rsz1); /*May2001 fwrite -> write for LFS */
     if (writestat < 0)
         errmsg("updt write err",fn1,"",0,0x40);

     uu++;                         /* count records updated           */
     fpsv = fileptr;               /* save fileptr of last rec updated*/
     rnsv = recnum1;               /* save recnum1 of last rec updated*/

     /* test for max record search limit reached */
     if (nn < uargs.cmv)
       { /* fileptr += rsz1;  May25/10 replace w getrec(0) */
         continue;
       }
     else
       { sprintf(opmsg1,"%d records read, %d updated %s\n",nn,uu,uargs.cmd);
         fileptr = fpsv;    /* so last updated rec will be displayed   */
         recnum1 = rnsv;    /*Jun03/10 also set recnum1 last updated   */
         upnext = 0;        /* inhibit getrec to display correct record*/
         break;
       }
   }
 }
return(1);
}

/*eject*/
/*uvhd------------------------- move -----------------------------------*/
/* move field - return 1 if ok, 0 if any error                          */
/*            - examples based on dat1/custmas1 demo file               */
/*  m    35(30),90     - move tel# & contact name following cust name   */
/*  m    35(30),90(12) - move tel# only & clear remainder of op1 lth    */
/*  m    50(20),'DEC 06/2010' - store constant, clear remaining op1 lth */
/*  +1                 - goto next record (or anywhere)                 */
/*  mm                 - repeat prior move (on current record)          */
/*  m99 35(30),90      - move tel# & contact for all recs until EOF     */

int move1(void)
{
int uu;         /* records updated(move) counter    */
int nn;         /* records read searching for moves */
int ss;         /* op3/4 & op4/5 qualify status     */
int ll;         /* calc lth tl clear when op1 lth > op2 lth */

upnext = 0;     /* inhibit advance to next record on 1st getrec */
uu=0; nn=0;     /* clear counters */
fpsv=0; rnsv=0; 

/* verify option u to allow move */
if ((opsc['u'-'a']) == 0)
  { printf(">>>MOVE requires option u on uvhd command line<<<\n");
    showhelp(help16,25,0x01);
    printf(">>>MOVE requires option u on uvhd command line<<<\n");
    exit(9);
  }

/* save record for possible roll-back of last move to current record */
memcpy(recsav2,recb,rsz1);        /* save record for possible roll-back*/

/* save record for possible roll-back of multi moves to current record */
/* IE - save only if cur fileptr not = fileptr of last move            */
if (fileptr != fplastup)
    memcpy(recsav1,recb,rsz1);   /* save rec for multi move roll-back  */


/* test for new move or repeat previous move                         */
if (cms[1] == 'm')                      /* repeat prior move ?       */
  { /* trsfr any multi-rec count from mm99 to stored margs structure */
    /* - to allow user to test move on 1 record, then repeat on all  */
    margs.cmv = cargs.cmv;              /* move multi-rec count      */
  }
else
  { /* store new search args - but 1st verify (cargs here, margs below)*/
    if ((cargs.a1l <= 0) || (cargs.a2l <= 0))
      { errmsg("move args invalid",cargs.cmd,"",0,0x10);
        return(0);
      }
    margs = cargs;                      /* store new search args      */
  }

/*eject*/
/* verify move args - op1 lth & op2 field/constant lth > 0 ? */
if ((margs.a1l <= 0) || (margs.a2l <= 0))
  { errmsg("move args invalid",margs.cmd,"",0,0x10);
    return(0);
  }
/*Dec07/10 - verify move op1 dsp+lth not > recsize */
if (margs.a1d + margs.a1l > rsz1)
  { errmsg("move op1 dsplcmnt+length > recsize",margs.cmd,"",0,0x10);
    return(0);
  }

/* instruction verified - test for multi-rec move or just current     */
/* 1 rec move allows multi-field moves & roll-back, multirec does not */
if (margs.cmv == 0)
  {
    /* qualify record if op3/op4 &/or op5/op6 spcfd (may be AND/OR)   */
    /*Jun11/06 - fix bug, change recb to recd except recsave I/O      */
    ss = search34(recd,&margs);         /* search for op3/4 &/or op5/6*/
    if (ss > 0)
      { /* move field or constant data in record */
        /*Dec07/10 - if optn a, constants s/b EBCDIC & clear blank EBCDIC*/
        if (margs.a2cc[0])
          { sncopy(recd+margs.a1d,margs.a2c,margs.a1l,0x00);
          }
        else
          { /* allow overlapping by move to wrecb for move back to recb */
            memcpy(wrecb,recb,rsz1);
            sncopy(recd+margs.a1d,wrecd+margs.a2d,margs.a1l,0x00);
          }

        /*Dec07/10 - allow update constant lth < op1 lth & blank excess  */
        /* if op1 lth > op2 lth - clear extra to blanks */
        if (margs.a1l > margs.a2l)
          { ll = (margs.a1l - margs.a2l);
            memset(recb + margs.a1d + margs.a2l,AEB,ll);
          }

        /* rewrite the record & store fileptr for possible roll-back  */
        fileseek("move 1");

        writestat = write(fd1,recb,rsz1);
        if (writestat < 0)
            errmsg("move write err",fn1,"",0,0x40);
        fplastup = fileptr;             /* save fileptr of last rec moved*/

        /* show move command - if mm vs original (already on screen)     */
        sprintf(opmsg1,"above record move - %s \n",margs.cmd);
      }
  }

/*eject*/
else
 {/* multi-record move, from cur fileptr for count spcfd or til EOF*/
  /* m99 0(3),'ABC'                                                */
  while(1)
   { rsz1 = getrec(0);
     if (rsz1 <= 0)
      { sprintf(opmsg1,"EOF, %d records read, %d move %s\n",nn,uu,margs.cmd);
         /* if any records moved, set fileptr to last rec moved  */
         if (uu)
           { fileptr = fpsv;
             recnum1 = rnsv; /*Jun03/10 also set recnum1 last move   */
             upnext = 0;     /* inhibit getrec to display correct record*/
             sprintf(opmsg2,"searched to EOF & reset to last record moved\n");
           }
         else
           { ;
           } 
         break;
       }
     nn++;                              /* count recs read for max test*/

     /* qualify record if op3/op4 &/or op5/op6 spcfd (may be AND/OR)       */
     ss = search34(recd,&margs);         /* search for op3/4 &/or op5/6    */

     if (ss < 0)
       { /* fileptr += rsz1;  May25/10 replace w getrec(0) */
         continue;
       }

     /* move field - move field or constant data in record */
     if (margs.a2cc[0])
       { sncopy(recd+margs.a1d,margs.a2c,margs.a1l,0x00);
       }
     else
       { /* allow overlapping by move to wrecb for move back to recb */
         memcpy(wrecb,recb,rsz1);
         sncopy(recd+margs.a1d,wrecd+margs.a2d,margs.a1l,0x00);
       }

     /* if op1 lth > op2 lth - clear extra to blanks */
     if (margs.a1l > margs.a2l)
       { ll = (margs.a1l - margs.a2l);
         memset(recd + margs.a1d + margs.a2l,AEB,ll);
       }

     /* seek to current record & rewrite */
     /* May2001: fseek changed to call fileseek (largefiles lseek/lseek64)*/
     fileseek("move multiple");

     writestat = write(fd1,recb,rsz1); /*May2001 fwrite -> write for LFS */
     if (writestat < 0)
         errmsg("move/update write err",fn1,"",0,0x40);

     uu++;                         /* count records moved           */
     fpsv = fileptr;               /* save fileptr of last rec moved*/
     rnsv = recnum1;               /* save recnum1 of last rec moved*/

/*eject*/
     /* test for max record search limit reached */
     if (nn < margs.cmv)
       { /* fileptr += rsz1;  May25/10 replace w getrec(0) */
         continue;
       }
     else
       { sprintf(opmsg1,"%d records read, %d moved %s\n",nn,uu,margs.cmd);
         fileptr = fpsv;    /* so last moved rec will be displayed     */
         recnum1 = rnsv;    /*Jun03/10 also set recnum1 last moved     */
         upnext = 0;        /* inhibit getrec to display correct record*/
         break;
       }
   }
 }
return(1);
}

/*eject*/
/*uvhd------------------------- moven ----------------------------------*/
/*Dec26/10 - move numeric field - return 1 if ok, 0 if any error        */ 
/*            - examples based on dat1/custmas1 demo file               */
/*  n    180(5p),120(5p)  - move this yr Jan sales to last yr           */
/*  n99  180(5p),120(5p)  - repeat move on all recs until EOF           */
/*  nx12 180(5p),120(5p)  - might add multi-field move in future        */
/*  n    245(9z),120(5p)  - move 5 bytes packed to 9 bytes zoned        */
/*  nn                    - repeat prior move (on current record)       */
/*  n    53(9z),38(6z)    - move 6 bytes to 9 bytes & zero fill extra   */
/*  n    53(9ze),38(6ze)  - move for EBCDIC file                        */

int moven(void)
{
int uu;         /* records updated(move) counter    */
int nn;         /* records read searching for moves */
int ss;         /* op3/4 & op4/5 qualify status     */
UVi64 w64;      /* 64 bit work area to retrieve field to move */

upnext = 0;     /* inhibit advance to next record on 1st getrec */
uu=0; nn=0;     /* clear counters */
fpsv=0; rnsv=0; 

/* verify option u to allow move */
if ((opsc['u'-'a']) == 0)
  { printf(">>>move Numeric requires option u on uvhd command line<<<\n");
    showhelp(help02,25,0x01);
    printf(">>>move Numeric requires option u on uvhd command line<<<\n");
    exit(9);
  }

/* save record for possible roll-back of last move to current record */
memcpy(recsav2,recb,rsz1);        /* save record for possible roll-back*/

/* save record for possible roll-back of multi moves to current record */
/* IE - save only if cur fileptr not = fileptr of last move            */
if (fileptr != fplastup)
    memcpy(recsav1,recb,rsz1);   /* save rec for multi move roll-back  */


/* test for new move or repeat previous move                         */
if (cms[1] == 'n')                      /* repeat prior move ?       */
  { /* trsfr any multi-rec count from nn99 to stored nargs structure */
    /* - to allow user to test move on 1 record, then repeat on all  */
    nargs.cmv = cargs.cmv;              /* move multi-rec count      */
  }
else
  { /* store new search args - but 1st verify (cargs here, nargs below)*/
    /*Dec26/10 - allow op2 lth 0 for value stored in dsplcmnt */
    if (cargs.a1l <= 0)
      { errmsg("move numeric args invalid",cargs.cmd,"",0,0x10);
        return(0);
      }
    nargs = cargs;                      /* store new search args      */
  }

/*eject*/
/* verify move args - op1 lth & op2 field/constant lth > 0 ? */
if (nargs.a1l <= 0)
  { errmsg("move numeric args invalid",nargs.cmd,"",0,0x10);
    return(0);
  }
/*Dec07/10 - verify move op1 dsp+lth not > recsize */
if (nargs.a1d + nargs.a1l > rsz1)
  { errmsg("move numeric op1 dsplcmnt+length > recsize",nargs.cmd,"",0,0x10);
    return(0);
  }

/* instruction verified - test for multi-rec move or just current     */
/* 1 rec move allows multi-field moves & roll-back, multirec does not */
if (nargs.cmv == 0)
  { /* qualify record if op3/op4 &/or op5/op6 spcfd (may be AND/OR)   */
    /*Jun11/06 - fix bug, change recb to recd except recsave I/O      */
    ss = search34(recd,&nargs);         /* search for op3/4 &/or op5/6*/
    if (ss > 0)
      { /* move field in 1 record */

        /* allow overlapping by move to wrecb for move back to recb */
        memcpy(wrecb,recb,rsz1);
        w64 = getop(wrecd,&nargs,2);
        putop1(recd,&nargs,w64);

        /* rewrite the record & store fileptr for possible roll-back  */
        fileseek("move numeric");

        writestat = write(fd1,recb,rsz1);
        if (writestat < 0)
            errmsg("move numeric write err",fn1,"",0,0x40);
        fplastup = fileptr;             /* save fileptr of last rec moved*/

        /* show move command - if nn vs original (already on screen)     */
        sprintf(opmsg1,"above record move numeric - %s \n",nargs.cmd);
      }
  }

/*eject*/
else
 {/* multi-record move, from cur fileptr for count spcfd or til EOF*/
  while(1)
   { rsz1 = getrec(0);
     if (rsz1 <= 0)
      { sprintf(opmsg1,"EOF, %d records read, %d move numeric %s\n"
                      ,nn,uu,nargs.cmd);
         /* if any records moved, set fileptr to last rec moved  */
         if (uu)
           { fileptr = fpsv;
             recnum1 = rnsv; /*Jun03/10 also set recnum1 last move   */
             upnext = 0;     /* inhibit getrec to display correct record*/
             sprintf(opmsg2,"searched to EOF & reset to last record moved\n");
           }
         else
           { ;
           }   
         break;
       }
     nn++;                              /* count recs read for max test*/

     /* qualify record if op3/op4 &/or op5/op6 spcfd (may be AND/OR)       */
     ss = search34(recd,&nargs);         /* search for op3/4 &/or op5/6    */

     if (ss < 0)
       { continue;
       }

     /* allow overlapping by move to wrecb for move back to recb */
     memcpy(wrecb,recb,rsz1);
     w64 = getop(wrecd,&nargs,2);
     putop1(recd,&nargs,w64);

     /* seek to current record & rewrite */
     /* May2001: fseek changed to call fileseek (largefiles lseek/lseek64)*/
     fileseek("move numeric multiple");

     writestat = write(fd1,recb,rsz1); /*May2001 fwrite -> write for LFS */
     if (writestat < 0)
         errmsg("move numeric/update write err",fn1,"",0,0x40);

     uu++;                         /* count records moved           */
     fpsv = fileptr;               /* save fileptr of last rec moved*/
     rnsv = recnum1;               /* save recnum1 of last rec moved*/

/*eject*/
     /* test for max record search limit reached */
     if (nn < nargs.cmv)
       { /* fileptr += rsz1;  May25/10 replace w getrec(0) */
         continue;
       }
     else
       { sprintf(opmsg1,"%d records read, %d moved %s\n"
                       ,nn,uu,nargs.cmd);
         fileptr = fpsv;    /* so last moved rec will be displayed     */
         recnum1 = rnsv;    /*Jun03/10 also set recnum1 last moved     */
         upnext = 0;        /* inhibit getrec to display correct record*/
         break;
       }
   }
 }
return(1);
}

/*eject*/
/*uvhdcob-------------- roll-back last update ------------------------*/
/* via oprtr cmd 'x'                                                  */
/*Feb02/09 - change 'recd' to 'recb' on update I/O's & saves */

int back1(void)
{

/* verify current fileptr = fileptr of last updt                      */
if (fileptr != fplastup)
  { printf("rollback rejected - cur rec not same as last updt\n");
    return(0);
  }

/* May2001: fseek changed to call fileseek (largefiles lseek/lseek64) */
fileseek("rollback x");

writestat = write(fd1,recsav2,rsz1);   /* May2001 fwrite -> write for LFS*/
if (writestat <= 0)
    errmsg("rollback write err",fn1,"",0,0x40);

/* copy cur rec before rollback to rollback save area               */
/* - to allow toggling between updated & not updated                */
memcpy(recsav2,recb,rsz1);             /* update the save area      */

upnext = 0; /* redisplay rolled-back record (inhibit advance to next)*/

return(1);
}

/*eject*/
/*uvhdcob------------- roll-back all updts to cur rec ----------------*/
/* via oprtr cmd 'X'                                                  */
/*Feb02/09 - change 'recd' to 'recb' on update I/O's & saves */

int backall(void)
{

/* verify current fileptr = fileptr of last updt                      */
if (fileptr != fplastup)
  { printf("rollback rejected - cur rec not same as last updt\n");
    return(0);
  }

/* May2001: fseek changed to call fileseek (largefiles lseek/lseek64) */
fileseek("rollback X");

writestat = write(fd1,recsav1,rsz1);    /*May2001 fwrite ->write LFS */
if (writestat <= 0)
    errmsg("rollback write err",fn1,"",0,0x40);

/* copy cur rec before rollback to rollback save area               */
/* - to allow toggling between updated & not updated                */
memcpy(recsav1,recb,rsz1);             /* update the save area      */

upnext = 0; /* redisplay rolled-back record (inhibit advance to next)*/

return(1);
}

/*eject*/
/*uvhdcob----------------------- check1 ---------------------------------*/
/* check sequence - display 1st record not in sequence                   */
/*  c  0(6)       - check sequence of cols 1-6                           */

int check1(void)
{
int cc;
int dd,ll;       /* save seqnum field dsplcmnt & length */
int ii;          /* option i value */

upnext = 0;      /* inhibit getrec() advance nextrec */

/* test new chkseq cmd or repeat previously stored cmd (cc)             */
if (cms[1] == 'c')
   ;
else
  { /* store new chkseq args - 1st verify args                          */
    if (cargs.a1l <= 0)
      { errmsg("check sequence cmd must specify field dsplcmnt(lth)"
               ,cargs.cmd,"",0,0x10);
        return(0);
      }
    kargs = cargs;                 /* store chkseq args                 */
  }

/* verify chkseq args - op1 lth > 0                                     */
if (kargs.a1l <= 0)
  { errmsg("check sequence cmd must specify field dsplcmnt(lth)"
           ,kargs.cmd,"",0,0x10);
    return(0);
  }

/* init seq chk from current record util EOF (or seq err)              */
/* get current record & save seqchk field for compare to following rec */
rsz1 = getrec(0);             /* get next record */
if (rsz1 <= 0)                /* EOF ?           */
  {
    errmsg("check seq at EOF already ?, reset to BOF & retry"
           ,kargs.cmd,"",0,0x10);
    return(0);
  }

dd = kargs.a1d;                    /* save seqnum field dsplcmnt    */
ll = kargs.a1l;                    /* save seqnum field length      */
memcpy(chksav1,recd+dd,ll);        /* save seqnum field from 1st rec*/

/*eject*/
/* begin loop to check sequence - until EOF (or seq err)               */
while (1)
  { /* fileptr += rsz1;  May31/10 replace w upnext/getrec */
    rsz1 = getrec(0);                 /* get next record */
    if (rsz1 <= 0)                    /* EOF ?           */
      { sprintf(opmsg1,"%s --> sequence OK, reached EOF with no errors\n"
               ,kargs.cmd);
        return(0);
      }

    memcpy(chksav2,recd+dd,ll);     /* get seqnum from current record  */

    /* test option to check by specified increment - option i1,i10,etc */
    if (kargs.opc['i'-'a'] == 'i')
      { ii = kargs.opi['i'-'a'];    /* save seq# option increment */
        if (ii == 0)
          { ii = 1;                 /* default to 1 if unspcfd    */
          }
        chksav1i = atol2(chksav1,'~',ll,0x01); /* cnvt prior rec# to int*/
        chksav2i = atol2(chksav2,'~',ll,0x01); /* cnvt current rec# to int*/
        chksav1i += ii;                        /* prior val + incrmnt   */
        if (chksav1i != chksav2i)
          { break;
          }
      }
    else
      { /* character compare current record seq field to save area     */
        cc = memcmp(chksav2,chksav1,ll);
        if ((cc < 0) && (kargs.opc['d'-'a'] != 'd'))
            break;
        if ((cc > 0) && (kargs.opc['d'-'a'] == 'd'))
            break;
        if ((cc == 0) && (kargs.opc['e'-'a'] == 'e'))
            break;
      }

    /* current rec OK - save seq fld (for == chk) & repeat loop        */
    memcpy(chksav1,chksav2,ll); /* save current seqnum for next rec chk*/
  }

/* loop broken by out of sequence - display errmsg & return            */
sprintf(opmsg1,"%s ERROR, 1st out of sequence record above\n",kargs.cmd);
return(1);                        /* return (1) to show next record    */
}

/*eject*/
/*uvhdcob--------------------- tally -----------------------------------*/
/* tally(count) records (from current record to EOF or within max spcfd */
/* - or records matching a pattern, to a specified maximum              */
/*                                                                      */
/* t                 - count recs from current point to EOF             */
/*                                                                      */
/* t500 0(80),='ABC' - count records with 'ABC' anywhere in 1st 80 bytes*/
/*                     (count from current record for 500 max or EOF)   */
/*                                                                      */
/* tt                        - repeat previous count                    */
/*                                                                      */
/* - if nofind set fileptr to last rec in file & return 0               */

int tally1(void)
{
int nn;             /* max records search ctr       */
int mm;             /* search find/nofind 0+/-      */
int tt;             /* tally counter                */

upnext = 0;         /* inhibit getrec() advance nextrec */

nn=0; tt=0; fpsv=0; rnsv=0;     /* clear counters       */

/* test for 't=s' transfer last search cmd to tally cmd storage structure */
if ((cms[1] == '=') && (cms[2] == 's'))
  { targs = sargs;              /* store tally cmd from last search cmd  */
    targs.cmd[0] = 't';         /* change cmd from 's' to 't'           */
    targs.cmc[0] = 't';         /* change cmc from 's' to 't'           */
    printf("tally args stored from last search: %s \n",targs.cmd);
    printf("execute 'tt' to tally spcfd records from current to EOF --> ");
    return(2);
  }

/* test for new tally command or repeat previous tally command (ee)*/
if (cms[1] == 't')                      /* repeat prior tally ?        */
  { /* allow value updt on repeat cmd - tt99                               */
    if (cargs.cmv)
        targs.cmv = cargs.cmv;
  }
else
  { /* store new tally args                                          */
    targs = cargs;                      /* store new tally args      */
  }

/*Jun04/10 - test option to transfer tally args to search args */
/*         - for subsequent 'ss' to verify tallies             */
if (targs.opc['s'-'a'])
  { sargs = targs;       /* transfer tally args to search args */
    sargs.a4l = 0;       /* disable search on op4,5,6          */
    sargs.a5l = 0;
    sargs.a6l = 0;
  }

/*eject*/
/* tally (count) recs matching any spcfd patterns                  */
/* - within max recs (if spcfd), or until EOF                          */
while (1)
  { rsz1 = getrec(0);             /* get next record */
    if (rsz1 <= 0)                /* EOF ?           */
      { break;
      }
   nn++;                              /* count records read            */

   /* if tally pattern spcfd - search & count matching recs to max cnt*/
   if (targs.a2l)
     { mm = search234(recd,&targs);   /* search for patterns spcfd       */
       if (mm >= 0)
         { tt++;                      /* count matching records          */
           fpsv = fileptr;            /* save fileptr of last match      */
           rnsv = recnum1;            /* save recnum1 last rec matched   */
         }
     }
   else
     { tt++;                          /* count all recs (no pattern spcfd)*/
       fpsv = fileptr;                /* save fileptr of last counted    */
       rnsv = recnum1;                /* save recnum1 last rec matched   */
     }

   /* test max tally limit reached, if so break read loop now    */
   if ((targs.cmv) && (nn >= targs.cmv))
     { break;
     }

   /* increment fileptr to next record & repeat loop                 */
   /* fileptr += rsz1;  May31/10 replace w upnext/getrec */

 }

/* tally loop ended by max count */
/* - store results msg to be displayed after last rec read */
sprintf(opmsg1,"%s --> %d recs counted of %d read\n",targs.cmd,tt,nn);
sprintf(opmsg2,"searched to EOF & reset to last record counted\n");

/* if pattern search found any matches, set fileptr to last match    */
if (targs.a2l && tt)
  { fileptr = fpsv;
    recnum1 = rnsv;   /*Jun03/10 also set recnum1 last updated   */
    upnext = 0;       /*Jun04/10 inhibit getrec to show up record*/
  }

return(1);
}

/*eject*/
/*uvhd------------------------ accumulate ------------------------------*/
/* accumulate a record field (from current to EOF or within max spcfd)  */
/* - or acum records matching a pattern, to a specified maximum         */
/*                                                                      */
/* a 120(5p)    <-- acum 120-124 5 byte packed from current point to EOF*/
/*                                                                      */
/* a 120(5p),,77(2),'BC'  <-- acum records with 'BC' in 77-78 (til EOF) */
/*                                                                      */
/* aa                     <-- repeat previous acum                      */

int acum1(void)
{
UVi64 acumr;      /* accum field retrvd from current record */
UVi64 acumx;      /* accum crossfoot option x               */
UVi64 acumt;      /* accum total from all records this cmd  */
int aa;           /* records accumulated   */
int nn;           /* max records ctr       */
int mm;           /* search match/nomatch  */
int xx;           /* crossfoot option value*/
int ii;

upnext = 0;       /* inhibit advance to next record on 1st getrec */
nn=0; aa=0; fpsv=0; rnsv=0;     /* clear counters */
acumt = 0;        /* init acum total */

/* test for new acum command or repeat previous acum command (ee)*/
if (cms[1] == 'a')                      /* repeat prior acum ?   */
  { /* allow value updt on repeat cmd - aa99                     */
    if (cargs.cmv)
        aargs.cmv = cargs.cmv;
  }
else
  { /* store new acum args */
    aargs = cargs;  
  }

/*eject*/
/* acum recs matching any spcfd patterns       */
/* - within max recs (if spcfd), or until EOF  */
while (1)
 { rsz1 = getrec(0);
   if (rsz1 <= 0)                     /* EOF ? */
     { break;
     }
   nn++;                               /* count records read */

   /* if acum pattern spcfd - search & acum matching recs to max cnt  */
   if (aargs.a3l)
      /*Jun11/06 - fix bug, change recb to recd except recsave I/O      */
     { mm = search34(recd,&aargs);       /* search for patterns spcfd   */
       if (mm >= 0)
         { aa++;                         /* acum matching records       */
           /*Feb26/11 - add crossfoot option x */
           /* - copy args structure so we can increment a1d by a1l each xft*/
           xargs = aargs;                /* init args for this record   */
           xx = aargs.opi['x'-'a'];      /* retrieve crossfoot value    */
           if (xx <= 0) { xx = 1;}       /* default 1 field             */
           acumx = 0;                    /* init xft acum this record   */
           for (ii=0; ii < xx; ii++)
              { acumr = getop(recd,&xargs,1); /* retrieve current xft fld*/
                acumx += acumr;          /* acum xft total this record   */
                xargs.a1d += xargs.a1l;  /* up dsplcmnt by fld lth       */
              }
           acumt += acumx;               /* add to acum total this cmd  */
           fpsv = fileptr;               /* save fileptr of last match   */
           rnsv = recnum1;               /* save recnum1 last rec matched*/
         }
     }
   else
     { aa++;                           /* acum all recs (no pattern spcfd)*/
       /*Feb26/11 - add crossfoot option x */
       /* - copy args structure so we can increment a1d by a1l each xft*/
       xargs = aargs;                /* init args for this record   */
       xx = aargs.opi['x'-'a'];      /* retrieve crossfoot value    */
       if (xx <= 0) { xx = 1;}       /* default 1 field             */
       acumx = 0;                    /* init xft acum this record   */
       for (ii=0; ii < xx; ii++)
          { acumr = getop(recd,&xargs,1); /* retrieve current xft fld*/
            acumx += acumr;          /* acum xft total this record   */
            xargs.a1d += xargs.a1l;  /* up dsplcmnt by fld lth       */
          }
       acumt += acumx;                 /* add to acum total this cmd      */
       fpsv = fileptr;                 /* save fileptr of last acum       */
       rnsv = recnum1;                 /* save recnum1 last rec matched   */
     }

   /* test max acum limit reached, if so break read loop now */
   if ((aargs.cmv) && (nn >= aargs.cmv))
     { break;
     }

   /* increment fileptr to next record & repeat loop */
   /* fileptr += rsz1;  May25/10 replace w getrec(0) */
 }

/*eject*/
/* acum loop ended by max count, or EOF */
/* - store results msg to be displayed  */
sprintf(opmsg1,"%s --> acum total=%ld from %d recs of %d read\n"
              ,aargs.cmd,acumt,aa,nn);
sprintf(opmsg2,"searched to EOF & reset to last record accumulated\n");

/* if pattern search found any matches, set fileptr to last match */
if (aargs.a3l && aa)
  { fileptr = fpsv;            /* store fileptr of last match     */
    recnum1 = rnsv;            /* store recnum1 of last match     */
  }

/*May26/10 - force read lastrec/display with opmsg1 in case acum all to EOF*/
upnext = 0;      /* inhibit getrec to display correct record*/

return(1);
}

/*eject*/
/*uvhdcob--------------------- verify1 --------------------------------*/
/* verify fields in current record                                     */
/* - verify packed fields valid digits & signs                         */
/* - verify character fields printable characters                      */

int verify1(void)
{
int cc,jj,nn,oo,ss;
int vpx,vcx,vnx;      /* errs returned by verifyp, verifyc,& verifyn */
int vaxt2;
int vx1st, vxlast;    /* 1st & last rec#s w errs when nostop/count optn*/

vpxt=0;               /* init verifyp err count      */
vcxt=0;               /* init verifyc err count      */
vnxt=0;               /* init verifyn err count      */
vaxt=0;               /* init all errors count       */
vrxt=0;               /* init total recs with errs   */
vaxt2=0;              /* options no-stop test        */
vx1st=0;              /* rec# of 1st err             */
vxlast=0;             /* rec# of last err            */
v2num=0;              /* rec# of 1st err all recs    */
v2dsp=-1;             /* dsp# of 1st err all recs    */
nn = 0;               /* reset records read          */
upnext = 0;           /* inhibit advance on 1st getrec*/

/* store vargs only on initial v cmd (not on repeat vv cmd) */
/* if count not spcfd - set high to verify to EOF           */
/*Dec23/10 - remove dflt dflt vargs.cmv=999999999, require explicit*/
if (cms[1] != 'v')
  { vargs = cargs;
  }

/*Feb12/09 - if 'vv': bypass current record before search/verify        */
if (cargs.cmd[1] == 'v')
  { /*Dec23/10 - replace getrec(0) with upnext=1                            */
    upnext = 1;
    /*Dec23/10 - if vv has options, replace vargs options with cargs options*/
    memcpy(wopsc,cargs.opc,26);
    wopsc['v'-'a'] = '\0';        /* null known option 'v' */
    if (memcmp(wopsc,nulls,26))
      { memcpy(vargs.opc,cargs.opc,26);
        memcpy(vargs.opi,cargs.opi,104);
      }
  }

/*Dec26/10 - default command records to process count to 1 if unspcfd */
if (vargs.cmv < 1)
  { vargs.cmv = 1;
  }

/*eject*/
/*Dec28/10 - test option to write records with verify errors */
if (vargs.opc['w'-'a'])
  { ss = openfileX(vwfname,"VW",&vwfptr,&vwfopn,0x00);
    /* opens file & returns 1, if not already open, else returns 0 */
    /*Dec30/10 - clear vwfctr only if file opened this time */
    if (ss)
      { vwfctr = 0;  /* clear count for all verifies til file close/reopen*/
      }
    if (vargs.opi['w'-'a'] == 99)
      { vargs.opi['w'-'a'] = 999999999;
      }
  }

/*Dec28/10 - test option to print records with verify errors */
if (vargs.opc['p'-'a'])
  { ss = openfileX(vpfname,"VP",&vpfptr,&vpfopn,0x00);
    /* opens file & returns 1, if not already open, else returns 0 */
    /*Dec30/10 - clear vpfctr only if file opened this time        */
    /*Jan02/10 - also insert command & filename at begin file      */
    if (ss)
      { vpfctr = 0;  /* clear count for all verifies til file close/reopen*/
        fprintf(vpfptr,"--> %s opening: %s\n",vargs.cmd,vpfname);
        /*Jan10/11 - add hdngs to identify datafile & copybook */
        fprintf(vpfptr,"now=%s uvhdcob %s %s\n",todttm,fn1,opsu);
        fprintf(vpfptr,"version=%s copybook=%s \n",uvversion,fn2d);
        fprintf(vpfptr,"rec#=%d rcount=%d rsize=%d fsize=%s fptr=%s\n\n"
                      ,recnum1,rcount,rsz1,fsedit,fpedit1);
      }
    if (vargs.opi['p'-'a'] == 99)
      { vargs.opi['p'-'a'] = 999999999;
      }
  }

/*eject*/
/* begin loop to get & verify records til max count or EOF */
while (1)
  { rsz1 = getrec(0);             /* get next record */
    if (rsz1 <= 0)                /* EOF ?           */
      { break;
      }

    /*Dec25/10 - save record for possible rollback after update by         */ 
    /* - verify optns z1/z2/z4 cnvrt blank num/pack to 0s & unprints to '.'*/
    if (vargs.opi['z'-'a'])
      { memcpy(recsav1,recb,rsz1); /* save record for possible roll-back*/
        memcpy(recsav2,recb,rsz1); /* save both rollbacks for 'x' or 'X'*/
      }
    vzups=0;          /* reset updt swtch optn z1/z2/z4 */

    v1xt  = 0;        /* init count errs in current record            */
    v1dsp = -1;       /* init save byte# 1st err field current record */
                      /*Dec26/10 - init -1 so byte# 0 works           */

    /* test max verify count reached */
    if (nn >= vargs.cmv)
      { break;
      }
    /* count records verified Dec26/10 moved after test max */
    nn++;          

/*Sep30/11 - copy code from display & printrec to this verify1 */
/*         - to get updates for grp occurs nested */
/*uvhdcob---------------- test record *TYPE ----------------------------*/
/**TYPE=0(1),='N','name-record'  <-- data records with 'N' in byte 0    */
/* if *TYPE table entries stored from begining of cobmap                */
/* - test current data record to *TYPE defs for match                   */
/* - if match, advance up cobmap table for matching fieldname           */
/*   to determine 1st cobmap field to be displayed                      */

/*Jan29/09 - allow record type testing for EBCDIC input                 */
/*         - copy 1st 256 bytes to alt area for testing (max 256)       */
/*         - translate to ASCII if input is EBCDIC                      */
/*Apr04/11 - disable, *TYPE codes now trnsltd to EBCDIC if optn 'a' */
/*         - but not if coded in hex     */
/* memcpy(recda,recd,256);               */
/* if (opsc['a'-'a'])                    */
/*   { toascii2((Uchar*)recda,256,0x00); */
/*   }                                   */

/* init mtibgn = 0 & mtiend = mtimax, assuming no TYPE's present        */
mtibgn = 0;
/* Oct00 - getting extra field blank 0 0 bgn end at end single types    */
/*       - try change: mtiend=mtimax to: mtiend=mtimax-1;               */
mtiend = mtimax-1;

/*eject*/
/* test R/T by code OR (May20/10) by rec-size (RDW,IDX,text) */
if (ttimax)
  { /* set mtibgn/end to bgn/end of 1st type def, in case of nomatch    */
    /* ie - if nomatch, default display to 1st type defined             */
    mtibgn = typtbl[0].mtibgntyp;
    mtiend = typtbl[0].mtiendtyp;

    /* search typtbl for match to current data record                  */
    for (tti=0; tti < ttimax; tti++)
      { typrw = typtbl[tti];          /* move current tbl entry to w/s */

        /*May20/10 - allow TYPE by record-size (for RDW, IDX, text)        */
        /*         - identify alt format by maprec.lvl[0] == 'R' (vs 'T')  */
        /* *TYPE=0(1),='X','recname' <-- original format ID by recType code*/
        /* *TYPE=99:999,'recname'    <-- alternate format ID by Recsize    */
        if (typrw.lvl[0] == 'R')
          { if ((rsz1 >= typrw.bgn) && (rsz1 <= typrw.end))
              { mtibgn = typrw.mtibgntyp;
                mtiend = typrw.mtiendtyp;
                break;
              }
          }
        else
          { /*Apr04/05 - disabled recda, type codes now EBCDIC if 'a' */
            /* cc = memcmp(recda+typrw.bgn,typrw.typ,typrw.lth);      */
               cc = memcmp(recd+typrw.bgn,typrw.typ,typrw.lth);
            if (((typrw.cc[0] == '=') && (cc == 0))
                || ((typrw.cc[0] == '!') && (cc != 0))
                || ((typrw.cc[0] == '<') && (cc < 0))
                || ((typrw.cc[0] == '>') && (cc > 0)))
              { /* RT match - store mtir index for bgn/end display         */
                mtibgn = typrw.mtibgntyp;
                mtiend = typrw.mtiendtyp;
                break;
              }
          }
      }

   if (tti >= ttimax)
     { errmsg("data rec type NOmatch to cobmap *TYPEs - use 1st cobmapdef"
              ,typrw.des,"",0,0x111);
     }
  }

/*eject*/
/* current data record has been matched to an entry in record type table */
/*        - or the mandatory unidentified entry at the end of copybookmap*/
/* mtibgn - points to 1st cobmap entry for identified type               */
/* mtiend - points to 1st cobmap entry for identified type               */
/* mtir   - pointer incremented from mtibgn to mtiend                    */
/*          to display cobmap & data fields in current record type       */

mtir = mtibgn;        /* init mtir to mtibgn, 1st field to display     */
mtib = 0;             /* init mtib 0 in case of partial rec redef      */

/* mtib/mtir used to show base(key) fields till we reach redef type    */
/* store dsp of 1st signif redef fld by advance mtir to 1st with lth   */
while ((mtir < mtimax) && (maptbl[mtir].lth == 0))
  { mtir++;
  }
mtir1dsp = maptbl[mtir].bgn;   /* store dsp of 1st redef fld with lth  */

/*Aug06/11 - init all item occurs controls (not just ooii) */
oonn=0; ooii = 0; ooff=0; ooee=0; oozz=0;

/*Aug03/11 - init group occurs control fields */
/*Sep26/11 - allow nested group occurs 2 levels only */
/*Sep26/11 - clear using grp occurs zero structure */
goc1 = goc0;
goc2 = goc0;
godpb=0; godpl2=0; goffcor1=0; goffcor2=0; 
/*Aug26/11 - clear total record offset for depending on corrections */

/*eject*/
/*Sep30/11 - bgnscreen code (10 lines) removed N/A printrec vs display */

/*uvhdcob---------------- begin line -----------------------------------*/
bgnlinev:
recdend=0;  /*Sep02/11 ensure end field reset for null reply EOS/EOR test*/
/* begin each field format for display(printf)                           */
/* fieldname--------occurs->  bgn end typ<----data (hex if typ=p/b)--->  */
/*        30                     +11        +1      +36            = 78  */
/* current field depends on mtir index into cobmap MAPREC maptbl         */
/* - move current entry to work area for easy access                     */
/* - retrieve data from current record depending on cobmap dsplcmnt & lth*/

/* allow for partial redef record types which omit base(key) fields       */
/* - mtir index points to 1st field in current type (if any)              */
/* - mtib index (init 0) used to display base/key flds til dsp => mtir1dsp*/
/* - mtir1dsp (dsp of 1st redef fld with length) stored above             */
/*Aug13/11 - remove code to display base fields to partial redef records  */
/* - see old solution in versions prior to Aug03/2011                     */
/* - old code used mtibi/mtiri 1/0 or 0/1 to inc base or redef (kludgy)   */
/* - recode use mtir only from 0 base & chg mtir to redef after base fld cnt*/

/* get field from record base(key) until dsp => 1st redef field          */
/* - 1st bypass any 0 lth fields in base record                          */
/*Aug13/11 - remove code to display base fields to partial redef records  */
/* get field from redef record (only rec if no redef types present)  */
/* 1st bypass any 0 lth fields in redef record                       */
while ((maptbl[mtir].lth == 0) && (mtir < mtiend))
  { mtir++;
  }
maprw = maptbl[mtir];        /* store redef/rec field to be displayed*/

/* display 36 bytes max per field, 18 bytes if packed/binary (36 chars)  */
flth1 = maprw.lth;               /* presume fld lth = actual             */
if (flth1 > 36)
    flth1 = 36;                  /* field data retrieve 36 bytes max     */
flth2 = flth1;                   /* presume display lth same as retrieve */

/* if packed/binary - display lth 2 * field length max 36 bytes          */
if ((maprw.typ[0] == 'p') || (maprw.typ[0] == 'b'))
  { flth2 *= 2;                  /* hex display lth = 2 * fldlth         */
    if (flth2 > 36)
        flth2 = 36;              /* p/b display lth 36 bytes max         */
  }

/*eject*/
/*Aug03/11 - test for *BGNOCCURS & store/init Grp OCCurs controls */
/*Aug04/11 - store option g max group occurs desired */
/*Sep26/11 - allow nested group occurs (2 levels only) */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest == 1))
  { goc1.max = maprw.gocmax;   /* occurs count */
    goc1.max1 = goc1.max;      /* save orig to edit in case odo 1 */
    goc1.lth = maprw.goclth;   /* occurs group set total length */
    goc1.ctr = 0;              /* init index for 1st set        */
    goc1.end = opsi['g'-'a'];  /* store group end dsired from optn g */
    /*Aug25/11 - get depending on count if specified */
    /*         - to override max count on *BGNOCCURS */
    if (maprw.godpl)          /* dpo count from *BGNOCCURS on table load ? */
      { godpl2 = maprw.godpl; /* store fld lth in shorter symbol */
        memset(godpc,'\0',12);
        memcpy(godpc,recd+maprw.godps,godpl2);
        /* test dpo data type: packed, binary, numeric */
        /* if packed - retrieve right adjusted into zero filled work area   */
        /*      - then unpack & convert to common format (binary int)       */
        if (maprw.godpt[0] == 'p')             /* dpo count field packed ?  */
          { memset(w2,'\0',21);                /* null fill packed retrieve */
            memcpy(&w2[20-godpl2],godpc,godpl2);
            unpack(w3,w2,0x01);                /* unpack signed (ascii zones)*/
            godpb = atoi(w3);                  /* convert to integer         */
          }
        else if ((maprw.godpt[0] == ' ') && (maprw.godpt[1] == 'n'))
          { godpb = atol2(godpc,'~',8,0x01);
          }
        else /* assume binary 2,4,or 1 */
          { if (godpl2 == 2)                     /* binary short ?         */
              { memcpy((Uchar*)&godpb2,godpc,2); /* retrieve to short w/a  */
                if (LEM)
                  { bswap2((Uchar*)&godpb2);     /* switch big/little ends */
                  }
                godpb = godpb2;                  /* store in common 32 bit int*/
              }
            else if (godpl2 == 4)
              { memcpy((Uchar*)&godpb,godpc,4);  /* assume 4 byte int  */
                if (LEM)
                  { bswap4((Uchar*)&godpb);      /* switch big/little ends */
                  }
              }
            else /*Sep01/11 - assume 1 byte binary pic x */
              { godpb = godpc[0];
              }
          }
        /* validate depending on count retrieved from dpo field */
        if ((godpb > goc1.max) || (godpb < 0))
          { errmsg("occurs depending on field retrieved > max(to) or negative"
                   ,maprw.des,"",0,0x21);
          }
        /* - replace *BGNOCCURS count (max assumed)    */
        goc1.max = godpb;         /* replace max assumed with dpo actual */
      }

/*eject*/
    /*Aug21/11 - convert occurs options g99/o99 to g99999/o99999 */
    if (goc1.end == 99)
      { goc1.end = 99999;
      }
    if (goc1.end > goc1.max)
      { goc1.end = goc1.max;
      }
    if (goc1.end < 1)
      { goc1.end = 1;
      }
    goc1.mti = mtir;         /* save index to *BGNOCCURS for next loop */
    fldctr1 = fldctr;        /* save field ctr of 1st field in group occurs */
    goto nextfieldv;         /* go increment maptbl index to next field */
  }

/*Aug03/11 - test for *ENDOCCURS */
/* - increment grpoccurs ctr & reset to 1st field in group */
/* - if max occurs, clear grpoccurs controls & continue to next field */
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest == 1))
  { goc1.ctr++;               /* increment grp occurs ctr */
    if (goc1.ctr >= goc1.end) /* end count ?              */
      { /*Aug26/11 - calc record dsplcmnt offset for folwng fields */
        /* - significant only when depending on count < occurs to max */
        if (maprw.godpl)
          { goffcor1 = ((maprw.gocmax-godpb) * goc1.lth);
            goffcor2 += goffcor1;
          }
        goc1 = goc0;    /* clear GOC1 structure */
        godpb=0; 
        /*Sep26/11 - not sure about godpb (in structure or not ?)  */
        goto nextfieldv; /* go increment maptbl index to next field */
      }
    else
      { mtir = goc1.mti;  /* reset maptbl index to *BGNOCCURS */
        /*Aug04/11 - restore saved fieldctr on 1st field of group occurs*/
        fldctr = fldctr1;
        goto nextfieldv; /* go increment maptbl index to next field */
      }
  }

/*eject*/
/*Sep26/11 - add 2nd level nested group occurs */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest == 2))
  { goc2.max = maprw.gocmax;   /* occurs count */
    goc2.max1 = goc1.max;      /* save orig to edit in case odo 1 */
    goc2.lth = maprw.goclth;   /* occurs group set total length   */
    goc2.ctr = 0;              /* init index for 1st set          */
    goc2.end = opsi['g'-'a'];  /* same optn as goc level 1 */
    if (goc2.end > goc2.max)
      { goc2.end = goc2.max;
      }
 /* goc2.end = goc2.max;   might show all occurrences of level 2 */
    goc2.mti = mtir;      /* save index to *BGNOCCURS for next loop */
    fldctr2 = fldctr;     /* save field ctr of 1st field in group occurs */
    goto nextfieldv;      /* go increment maptbl index to next field */
  }

/*Sep26/11 - add 2nd level nested group occurs */
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest == 2))
  { goc2.ctr++;               /* increment grp occurs ctr */
    if (goc2.ctr >= goc2.end) /* end count ?              */
      { /*Aug26/11 - calc record dsplcmnt offset for folwng fields */
        /* - significant only when depending on count < occurs to max */
        if (maprw.godpl)
          { /*Sep27/11 - godpb N/A to 2nd level nested occurs */
            /* goffcor1 = ((maprw.gocmax-godpb) * goc2.lth); */
            goffcor1 = ((maprw.gocmax) * goc2.lth); 
            goffcor2 += goffcor1; 
          }
        goc2 = goc0;     /* clear GOC2 structure */
        goto nextfieldv; /* go increment maptbl index to next field */
      }
    else
      { mtir = goc2.mti;  /* reset maptbl index to *BGNOCCURS */
        /*Aug04/11 - restore saved fieldctr on 1st field of group occurs*/
        fldctr = fldctr2;
        goto nextfieldv;  /* go increment maptbl index to next field */
      }
  }

/*Sep27/11 - errmsg if group occurs nested > 2 */
if ((memcmp(maprw.des,"*BGNOCC",7) == 0) && (maprw.gocnest > 2))
  { errmsg("group occurs nested > 2 levels unsupported",maprw.des,"",0,0x11);
  }
if ((memcmp(maprw.des,"*ENDOCC",7) == 0) && (maprw.gocnest > 2))
  { errmsg("group occurs nested > 2 levels unsupported",maprw.des,"",0,0x11);
  }

/*eject*/
/*Aug03/11 - calc group occurs offset (0 if *BGNOCCURS not stored) */
goc1.off = (goc1.lth * goc1.ctr);
goc2.off = (goc2.lth * goc2.ctr);
/*Sep26/11 - not sure about offset calc for 2nd level nested occurs */
goctoff = (goc1.off + goc2.off);
/*         - try add together in goctoff & use that below           */

/* get occurs value from current maptbl rec */
oonn = maprw.occurs;   

/*Aug04/11 - store item occurs end count from option 'o' */
ooee = opsi['o'-'a'];
/*Aug21/11 - convert occurs options g99/o99 to g99999/o99999 */
if (ooee == 99)
  { ooee = 99999;
  }
if (ooee > oonn)
  { ooee = oonn;
  }
if (ooee < 1)
  { ooee = 1;
  }

/* calc occurs offset = (current occurs index * field length) */
ooff = (ooii * maprw.lth);

/* retrieve data from record, depending on cobmap dsplcmnt & occurs index*/
/* init retrieve area to all blanks                                      */
/* after data insert, scan back form right & insert null after nonblank  */
memset(fdat1,' ',50);               

/*Aug03/11 - calc group occurs offset above (as well as item occurs offset) */
/*Aug26/11 - calc total record offset including dpo correction occurs < max */
recdoff = (maprw.bgn-goffcor2+goctoff+ooff);
if ((maprw.bgn-goffcor2) < 0)
  { errmsg("occurs depending on field correction error",maprw.des,"",0,0x21);
  }
/*Sep02/11 - calc end field dsplcmnt for null reply EOS/EOR test */
recdend = (maprw.bgn-goffcor2+goctoff+ooff+maprw.lth+rdwhs);

/*Aug22/11 - test end record when occurs depending on & varlth records */
if (recdoff >= rsz1)
  { mtir = mtiend+1;   /* to force end screen */
    goto endrecv;      /* endscreen display chg to endrecv verify1 */
  }

sncopy(fdat1,recd+recdoff,flth1,0x00);  /* retrieve record field data */

/* copy data to display area - in case not binary/packed              */
/* (if binary/packed fdat2 will be overwritten with hexcodes          */
memcpy(fdat2,fdat1,50); 
/* ensure printable chars - translate any unprintables to '.' periods */
/* - can't do here if EBCDIC, but toascii2 0x04 will do below         */

/*Feb25/11 - clear hex for bad fields > 9 bytes on 2nd line */
memset(fdat4,'\0',40);               

/*eject*/
        /* verify depending on field type */
        if (maprw.typ[0] == 'p') 
          { vpx = verifyp(fdat1,flth1,0x02);
            cnvbpf20();   /* test z2 cnvt blank packed fld to 0s*/ 
            vpxt += vpx;                   /* acum packed errs  */
            vaxt += vpx;                   /* acum total errs   */
            v1xt += vpx;                   /* acum errs this rec*/
          }
        else if (maprw.typ[0] == 'b') 
          { /* ignore binary fields */
            ;
          }
        else if (maprw.typ[1] == 'n') 
          { /* check numeric field for non-numerics */
            vnx = verifyn(fdat2,flth1,0x00);
            cnvbnf20();      /* test z1 cnvt blank num fld to 0s */ 
            vnxt += vnx;                 /* acum nonnumeric errs */
            vaxt += vnx;                 /* acum total errs      */
            v1xt += vnx;                 /* acum errs this record*/
          }
        else
          { /* check chardata for unprintables */
            vcx = verifyc(fdat2,flth1,0x00);
            cnvbcf20();      /* test z4 cnvt unprintables to periods */
            vcxt += vcx;                 /* acum character errs */
            vaxt += vcx;                 /* acum total errs     */
            v1xt += vcx;                 /* acum errs this record*/
          }

/*eject*/
        /* end of current field in current record */
        /* if any err - save start byte# of err field for later report */
        /* - but not if dsplcmnt in range inhibited by optns a-b,c-d,e-f*/
        if (v1xt)
          { oo = (maprw.bgn + goc1.off + ooff);
            if (((vargs.opc['a'-'a']) && (oo >= vargs.opi['a'-'a']) 
                                      && (oo <= vargs.opi['b'-'a'])) ||
                ((vargs.opc['c'-'a']) && (oo >= vargs.opi['c'-'a']) 
                                      && (oo <= vargs.opi['d'-'a'])) ||
                ((vargs.opc['e'-'a']) && (oo >= vargs.opi['e'-'a'])
                                      && (oo <= vargs.opi['f'-'a'])))
              { ;
              }
            else 
              { if (v1dsp < 0)
                  { v1dsp = maprw.bgn+goc1.off+ooff; /* save byte# 1st err rpt*/
                  }
                if (v2dsp < 0)
                  { v2dsp = maprw.bgn+goc1.off+ooff; /* save byte# 1st err rpt*/
                    v2num = recnum1;        /* save rec# 1st err for report */
                  }
              }
          }
        /*Dec24/10 - also save record# of 1st err & last err */
        /*         - to report when no-stop-on-err optn used */
        if (v1xt && !vx1st)
          { vx1st = recnum1;    /* save rec# of 1st err      */
          }
        if (v1xt)
          { vxlast = recnum1;   /* save last rec# with err   */
          }

/*eject*/
/*Aug06/11 - nextfieldv: increment maptbl index here (vs bgnline) */
/*         - unless displaying item occurs                       */
/*         - jump here if current field display inhibited        */
nextfieldv:

/* increment occurs index for next occurs (if any) */
ooii++;

/* if last occurs for this field - increment maptbl index for next field*/
if (ooii >= ooee)
  { mtir++;              /* increment maptbl index to next field */
    ooii = 0;            /* reset occurs index for next field    */
    ooee = 0;            /*Aug17/11 also occurs end fix bug loop */
  }

/*Aug04/11 - increment field ctr - on 1st occurrence of item occurs */
/*         - also on group occurs & on non-occurs since ooii=0      */
/*Aug13/11 - move here to seq# fields inhibited by optn 'i' 0/blank */
if ((ooii < 1) && (memcmp(maprw.des,"*BGNOCC",7))
               && (memcmp(maprw.des,"*ENDOCC",7)))
  { fldctr++;
  }

if ((mtir > mtiend)) /* || (linectr >= linemax)) */
                     /*Sep30/11 - n/a to verify1, see display */
  { goto endrecv;      /* endscreen display chg to endrecv verify1 */
  }

/*Sep02/11 - test last field in record for occurs depending on */
/* recdend = (maprw.bgn-goffcor2+goctoff+ooff+maprw.lth+rdwhs); prior calc*/
if (recdend >= rsz1)
  { goto endrecv;      /* endscreen display chg to endrecv verify1 */
  }

goto bgnlinev;

/*eject*/
/*Aug23/11 - insert tag for rec ended by occurs depending on */
endrecv:     /* end verify of all fields in current record */
    /*Dec28/10 - increment total recs w errs if any errs in current record */
    if (v1xt)
      { vrxt++;            /* count records with verify errors */
        /*Dec28/10 - test option to write/print records with verify errors */
        if (vwfctr < vargs.opi['w'-'a'])
          { vwfctr++;      /* count verify writes */
            ss = fwrite(recb,1,rsz1,vwfptr);
            if (ss <= 0)
              { errmsg("verify write error",vargs.cmd,vwfname,0,0x40);
              }
          }
        if (vpfctr < vargs.opi['p'-'a'])
          { /*Dec30/10 - if option j, write formfeed every j# records */
            vpfctr++;      /* count verify writes */
            if (vargs.opi['j'-'a'])
              { jj = (vpfctr % vargs.opi['j'-'a']);
                if (jj == 0)
                  { fprintf(vpfptr,"\f");
                  }
              }
            printrec(vpfptr);
          }
      }

    /*Dec25/10 - test optns z1/z2/z4 cnvrt blank num/pack & pic x unprints */
    if (vzups)
      { if (!(opsc['u'-'a']))
          { printf(">>verify z1/z2/z4 requires option u on command line<<\n");
            exit(9);
          }
        /* rewrite the record & store fileptr for possible roll-back */
        fileseek("verify z1/z2/z4 cnvrt blank num/pack to 0s & unprintables\n");
        writestat = write(fd1,recb,rsz1);
        if (writestat < 0)
          { errmsg("update err for verify cnvrt blank num/pack to zeros\n"
                   ,fn1,"",0,0x40);
          }
        fplastup = fileptr;             /* save fileptr of last rec updtd */
      }

    /* if any errors in current record - break loop & report error  */
    /*Dec23/10 - verify no-stop-on-err options x1 num, x2 packed, x4 char */
    vaxt2 = vaxt;       /* will subtract num/pack/char errs for final test*/
    if (vargs.opi['x'-'a'] & 0x01)
      { vaxt2 -= vnxt;
      }
    if (vargs.opi['x'-'a'] & 0x02)
      { vaxt2 -= vpxt;
      }
    if (vargs.opi['x'-'a'] & 0x04)
      { vaxt2 -= vcxt;
      }
    if (vaxt2 > 0)
      { break;
      }
  }
/*eject*/
/* verify loop ended by max count, or EOF              */
/* store results msg - depending on error found or not */ 
if (vaxt)
  { /*Aug22/10 - test optn g1 to report dsplcmnts 1 rel vs 0 rel */
    /*Feb24/11 - change optn 'g' (0/1 relative) to optn 'c'      */
    if (opsi['c'-'a'] & 0x01)
      { v1dsp++;
      }
    /*Dec24/10 - alt verify msg with 1st & last rec#s with errors      */
    /*           when no-stop-on-err options used to count errs til EOF*/
    if (v1xt)    /* if errs in current record (nostop on err not used) */
      { sprintf(opmsg1,
     "%s --> %d recs verified, %d error recs, %d this record, 1st at byte# %d\n"
                      ,vargs.cmd,nn,vrxt,v1xt,v1dsp);
      }
    else
      { sprintf(opmsg1,
     "%s --> %d recs verified, %d with errs, 1st at rec# %d, last at rec# %d\n"
                      ,vargs.cmd,nn,vrxt,vx1st,vxlast);
      }
    sprintf(opmsg2,
    "ERRs: %d packed, %d numeric signs/digits, %d unprintable characters\n"
    ,vpxt,vnxt,vcxt);
/*Dec23/10 - opmsg3 for verify, vv99 continue, vv99x7 count/nostop */
    strcpy(opmsg3,
    "- vv99 continue, vv99x7 (x1=num,x2=pack,x4=char) count/nostop til EOF\n");
  }
else
  { sprintf(opmsg1,"%s --> %d records verified, No errors found \n"
                 ,vargs.cmd,nn);
  }

/*Dec31/10 - if verify print file open, append verify stats */
if (vpfopn)
  { fprintf(vpfptr,opmsg1);
    fprintf(vpfptr,opmsg2);
    fprintf(vpfptr,"--> %s closing: %s\n",vargs.cmd,vpfname);
  }

/*Dec28/10 - close file for write/print records with verify errors if open */
/*Dec29/10 - remove closefiles here, new cmd lvw & lvp to close files      */
/* closefileX(vwfname,"VW",&vwfptr,&vwfopn,&vwctr,0x00);  */
/* closefileX(vpfname,"VP",&vpfptr,&vpfopn,&vpctr,0x00);  */

return(vaxt);     /* return total errors */
}

/*eject*/
/*uvhdcob----------------------- verifyc -------------------------------*/
/* verify character data - no unprintable characters                    */
/* - for non packed/binary fields that contain unprintable chars        */
/* - data in arg1, length arg2 (max36)                                  */

int verifyc(char *fdat1, int fl, short bits)
{
int bd,ii;
char fdat1a[40];        /* convert EBCDIC to ASCII w/a   */
bd = 0;                 /* init Bad Data switch off      */

/*Mar20/10 - inhibit verify of redefined fields          */
if (maprw.rdf == 'r')
  { return(0);
  }

/*Mar21/10 - test options a,b,c,d to inhibit fields by start byte#     */
/*Dec28/10 - chg optns for 4 field start bytes to 3 ranges a-b,c-d,e-f */
if (maprw.lth > 0)
  { if ((vargs.opc['a'-'a']) && (maprw.bgn >= vargs.opi['a'-'a']) 
                             && (maprw.bgn <= vargs.opi['b'-'a']))
      { return(0);
      }
    if ((vargs.opc['c'-'a']) && (maprw.bgn >= vargs.opi['c'-'a']) 
                             && (maprw.bgn <= vargs.opi['d'-'a']))
      { return(0);
      }
    if ((vargs.opc['e'-'a']) && (maprw.bgn >= vargs.opi['e'-'a']) 
                             && (maprw.bgn <= vargs.opi['f'-'a']))
      { return(0);
      }
  }

/* move input data to work area for test unprintable chars */
memset(fdat1a,' ',40);        /* init work area */
sncopy(fdat1a,fdat1,fl,0x00); /* store input for translate */

/* if option 'a' - need to translate EBCDIC data to ASCII before test */
if (opsc['a'-'a'])
  { toascii2((Uchar*)fdat1a,fl,0x00); /* translate EBCDIC to ASCII */
  }

/* test field length for any unprintable chars             */
/*Dec22/10 - test option o1 to allow CR/LF in pic x fields */
/*Dec23/10 - remove optn o1, always ignore CR/LF in pic x  */
for (ii=0; (ii < fl); ii++)
  { if ((fdat1a[ii] == 0x0D) || (fdat1a[ii] == 0x0A))
      { continue;
      }
    if (!(isprint(fdat1a[ii])))
      { bd++;          /* count bad data bytes */
      }
  }

/* return unprintable characters count */
return(bd);
}

/*eject*/
/*uvhdcob----------------------- verifyn -------------------------------*/
/* verify character data - no nonnumeric characters                    */
/* - for non packed/binary fields that contain nonnumeric chars        */
/* - data in arg1, length arg2 (max36)                                  */

int verifyn(char *fdat1, int fl, short bits)
{
int bd,ii;
char fdw[40];            /* EBCDIC to ASCII work area                  */
Uchar sign;
Uchar units;
int fl1;                 /* field length -1 (index of units sign byte) */
bd = 0;                  /* init Bad Data switch off                   */

/*Mar20/10 - inhibit verify of redefined fields          */
if (maprw.rdf == 'r')
  { return(0);
  }

/*Mar21/10 - test options a,b,c,d to inhibit fields by start byte#   */
/*Dec28/10 - chg optns for 4 field start bytes to 3 ranges a-b,c-d,e-f */
if (maprw.lth > 0)
  { if ((vargs.opc['a'-'a']) && (maprw.bgn >= vargs.opi['a'-'a']) 
                             && (maprw.bgn <= vargs.opi['b'-'a']))
      { return(0);
      }
    if ((vargs.opc['c'-'a']) && (maprw.bgn >= vargs.opi['c'-'a']) 
                             && (maprw.bgn <= vargs.opi['d'-'a']))
      { return(0);
      }
    if ((vargs.opc['e'-'a']) && (maprw.bgn >= vargs.opi['e'-'a']) 
                             && (maprw.bgn <= vargs.opi['f'-'a']))
      { return(0);
      }
  }

/* move input data to work area for test nonnumeric chars  */
memset(fdw,' ',40);          /* init work area             */
sncopy(fdw,fdat1,fl,0x00);   /* store input for translate  */

/* if option 'a' - need to translate EBCDIC data to ASCII before test */
if (opsc['a'-'a'])
  { toascii2((Uchar*)fdw,fl,0x00); /* translate EBCDIC to ASCII  */
  }

/*eject*/
/* check sign byte separately from digits                  */
fl1 = (fl -1);               /* calc index to sign byte    */
sign = fdw[fl1];             /* isolate sign byte          */
sign &= 0xF0;                /* clear digit from sign byte */
units = fdw[fl1];            /* isolate units digit        */

/*Dec22/10 - test options to allow signs in units of numeric fields       */
/* y1 - (default) Micro Focus COBOL comatible neg x'70' p-q               */
/* y2 - EBCDIC signs, option 'a' will translate to ASCII before verify num*/
/* - original EBCDIC signs: pos {A-I x'C0'-x'C9' neg }J-R x'D0'-x'D9'     */
/* - after translation:     pos '{' & 'A'-'I' neg '}' & 'J'-'R'           */
/* y4 - separate +/- signs anywhere in field                              */

/*Dec24/10 - allow sign options on v cmd as well as cmd line              */
/* - if optn y not spcfd, default to cmd line (dflt y1 or y2 if a EBCDIC) */
if (!(vargs.opi['y'-'a']))
  { vargs.opi['y'-'a'] = opsi['y'-'a'];
  }

/* 1st test y4 for +/- signs anywhere in field */
if (vargs.opi['y'-'a'] & 0x04)
  { for (ii=0; (ii < fl); ii++)
      { if ((fdw[ii] ==  '+') || (fdw[ii] ==  '-'))
          { continue;
          }
        if (!(isdigit(fdw[ii])))
          { bd++;          /* count bad data bytes */
          }
      }
  }

/*Dec22/10 - test y1 (default) Micro Focus COBOL comatible neg x'70' p-q */
else if (vargs.opi['y'-'a'] & 0x01)
  { if (sign == 0x70)
      { fdw[fl1] &= 0x3F;      /* chg x'70' to x'30' */
      }
    for (ii=0; (ii < fl); ii++)
      { if (!(isdigit(fdw[ii])))
          { bd++;              /* count bad data bytes */
          }
      }
  }

/*eject*/
/* test y2 for EBCDIC signs, if EBCDIC data optn 'a' already trnsltd above*/
/* - original EBCDIC signs: pos {A-I x'C0'-x'C9' neg }J-R x'D0'-x'D9'     */
/* - after translation:     pos '{' & 'A'-'I' neg '}' & 'J'-'R'           */
else if (vargs.opi['y'-'a'] & 0x02)
  { /* 1st verify units position */
      { if (((units == '{') || (units == '}'))  ||
           ((units >= 'A') && (units <= 'I'))   ||
            ((units >= 'J') && (units <= 'R'))  ||
            ((units >= '0') && (units <= '9')))
          { ;
          }
        else
          { bd++;
          }
        /* test bytes (not including units) for any nonnumeric chars */
        for (ii=0; (ii < (fl-1)); ii++)
          { if ((fdw[ii] < '0') || (fdw[ii] > '9'))
              { bd++;                   /* count bad data bytes */
              }
          }
      }
  }

/* return nonnumeric characters count */
return(bd);
}

/*eject*/
/*uvhdcob------------------------ verifyp --------------------------------*/
/* verify packed data field - digits & sign                               */

int verifyp(char *pd, int pl, short bits)
{
int ii,jj,kk,dd,ee;
char pdw[10];             /* packed data will be right adjusted in w/a */
char zdw[20];             /* zero filled & data unpacked right adjusted*/
char sign;                /* sign isolated x'0C', x'0D', x'0F' valid   */
memset(pdw,'\0',10);      /* init packed w/a to nulls       */
memset(zdw,'0',20);       /* init zoned  w/a to zero digits */
ee = 0;                   /* init error count               */

/*Mar20/10 - inhibit verify of redefined fields          */
if (maprw.rdf == 'r')
  { return(0);
  }

/*Mar21/10 - test options a,b,c,d to inhibit fields by start byte#*/
/*Dec28/10 - chg optns for 4 field start bytes to 3 ranges a-b,c-d,e-f */
if (maprw.lth > 0)
  { if ((vargs.opc['a'-'a']) && (maprw.bgn >= vargs.opi['a'-'a']) 
                             && (maprw.bgn <= vargs.opi['b'-'a']))
      { return(0);
      }
    if ((vargs.opc['c'-'a']) && (maprw.bgn >= vargs.opi['c'-'a']) 
                             && (maprw.bgn <= vargs.opi['d'-'a']))
      { return(0);
      }
    if ((vargs.opc['e'-'a']) && (maprw.bgn >= vargs.opi['e'-'a']) 
                             && (maprw.bgn <= vargs.opi['f'-'a']))
      { return(0);
      }
  }

/* store packed data right adjusted in 10 byte w/a */
dd = (10 - pl);          /* calc dsplcmnt of left byte in 10 byte w/a */
memcpy(pdw+dd,pd,pl);    /* store data rt adjusted in 10 bytes */

/* isolate sign & verify */
sign = pdw[9];           /* isolate sign to 1 byte w/a */
sign &= 0x0F;            /* clear zone of sign byte    */
if ((sign == 0x0C) || (sign == 0x0D) || (sign == 0x0F))
  { ; }
else
  { ee++; }

/*eject*/
/* unpack data to zoned w/a */
ii = 9;                 /* set index to right side of packed input */
jj = 19;                /* set index to right side of zoned output */
while(ii >= 0)
  { zdw[jj--] = (char) (0x30 | ((intU) pdw[ii] & 0x0F));
    zdw[jj--] = (char) (0x30 | (intU) (Uchar) pdw[ii--] >> 4);
  }
/* verify 19 bytes all digits (ignore 20th byte sign) */
for (kk=0; kk < 19; kk++)
  { if (!(isdigit(zdw[kk])))
      { ee++;
      }
  }
/* return error count */
return(ee);
}

/*eject*/
/*----------------------------- cnvbnf20 ------------------------------*/
/*Dec25/10 - test optn z1 to convert all blank numeric/packed to zeros */
int cnvbnf20(void)
{
if (vargs.opi['z'-'a'] & 0x01)
  { if (opsc['a'-'a'])
      { if (memcmp(recd+maprw.bgn,Eblanks,maprw.lth) == 0)
          { memset(recd+maprw.bgn,0xF0,maprw.lth);
            vzups++;          /* set update at end all fields */
          }
      }
    else
      { if (memcmp(recd+maprw.bgn,Ablanks,maprw.lth) == 0)
          { memset(recd+maprw.bgn,0x30,maprw.lth);
            vzups++;          /* set update at end all fields */
          }
      }
  }
return(vzups);
}

/*----------------------------- cnvbpf20 ------------------------------*/
/*Dec25/10 - test optn z1 to convert all blank numeric/packed to zeros */
int cnvbpf20(void)
{
/*Dec25/10 - test optn z1 to convert all blank numeric/packed to zeros */
if (vargs.opi['z'-'a'] & 0x02)
  { if (opsc['a'-'a'])
      { if (memcmp(recd+maprw.bgn,Eblanks,maprw.lth) == 0)
          { memset(recd+maprw.bgn,0x00,maprw.lth);
            (recd+maprw.bgn)[maprw.lth-1] = 0x0C;
            vzups++;          /* set update at end all fields */
          }
      }
    else
      { if (memcmp(recd+maprw.bgn,Ablanks,maprw.lth) == 0)
          { memset(recd+maprw.bgn,0x00,maprw.lth);
            (recd+maprw.bgn)[maprw.lth-1] = 0x0C;
            vzups++;          /* set update at end all fields */
          }
      }
  }
return(vzups);
}

/*eject*/
/*----------------------------- cnvbcf20 ------------------------------*/
/*Dec25/10 - test optn z4 to convert unprintable characters to periods */
int cnvbcf20(void)
{
if (vargs.opi['z'-'a'] & 0x04)
  { if (opsc['a'-'a'])
      { memcpy(wrecd,recd+maprw.bgn,maprw.lth);
        toprint2((Uchar*)recd+maprw.bgn,maprw.lth,trtprintE,0x00);
        if (memcmp(recd,wrecd,maprw.lth) != 0)
          { vzups++;
          }
      }
    else
      { memcpy(wrecd,recd+maprw.bgn,maprw.lth);
        toprint2((Uchar*)recd+maprw.bgn,maprw.lth,trtprint,0x00);
        if (memcmp(recd,wrecd,maprw.lth) != 0)
          { vzups++;
          }
      }
  }
return(vzups);
}

/*eject*/
/*uvhdcob------------------------- showhelps ----------------------------*/
/* show helpscreens - arg1 points to a table of helpscreen pointers      */
/* - default to showing each in sequence until null pointer (end table)  */
/*   (see table of help screen ptrs stored up front in this program)     */
/* - allow user to enter help screen# to modify display sequence         */
/*   (or 'q' to quit help screens, 'qq' to quit help screens & program   */

int showhelps(char **hsp[], int hsmax)
{
int ii = 0;                /* index for table of help screen ptrs     */
int rr = 0;                /* user reply for next desired help screen */
char reply[80];            /* operator reply                          */

/* begin loop to display help screens until end of table, or user quit */
while (ii < hsmax)
  { showhelp(hsp[ii],25,0x01);    /* show current help screen          */
    if (ii < hsmax-1)
    { printf("enter null for help screen #%d of %d, or desired#, or q=quit --> "
              ,ii+2,hsmax);
     }
    else
     { printf("End %d help screens, enter desired#, or null to exit help --> "
           ,hsmax);
     }
    fgets(reply,80,stdin);     /* wait for operator reply           */
    if (reply[0] == 'q')
      { return(2);             /* return 2 to indicate oprtr quit   */
      }

    /* if operator entered valid index to desired help screen       */
    /* - use it, else display next sequential help screen           */
    rr = atol(reply);          /* convert reply to integer          */
    rr--;                      /* decrement for zero relative index */
    if ((rr >= 0) && (rr < hsmax))
      { ii = rr;               /* replace table index with users desire */
      }
    else
      { ii++;                  /* increment to next sequential help screen*/
      }
  }

return(1);
}
/*eject*/
/*uvhdcob----------------------- printRV ------------------------------*/
/* display warning message in Reverse Video                            */

short printRV(char *warnmsg)
{

/*build Reverse Video warnmsg, allowing for inhibit via option b2 */
warnmsg2[0] = '\0';             /* init out area for inhibit option */
if ((opsi['b'-'a'] & 0x02) == 0)
    strcat(warnmsg2,smso);
strcat(warnmsg2,warnmsg);
if ((opsi['b'-'a'] & 0x02) == 0)
    strcat(warnmsg2,rmso);
printf(warnmsg2);

return(1);
}

/*eject*/
/*uvhdcob----------------------- bad2hex -------------------------------*/
/* convert bad data to hex                                              */
/* - to detect character fields that contain unprintable chars          */
/* - data in fdat1, length flth1 (max36)                                */
/* - if 1st 11 bytes have unprintables, show hex on right (max 22)      */
/* - will store fdat2 to print, will test fdat1 for unprintables        */

int bad2hex(char *fdat2, char *fdat1, int flth1)
{
int bd,fl,fl2,ii;
char fdat1a[40];        /* convert EBCDIC to ASCII w/a   */
bd = 0;                 /* init Bad Data switch off      */

/* determine field length to test & cnvrt to hex if reqd */
/* shorter of field length or 18 bytes max               */
fl = flth1;            /* presume field length <= 18     */
if (fl >= 18)
  { fl = 18;
  }
fl2 = (fl * 2);        /* calc field length converted to hex   */

/* move input data to work area for test unprintable chars */
memset(fdat1a,' ',40);        /* init work area */
sncopy(fdat1a,fdat1,fl,0x00); /* store input for translate */

/* if option 'a' - need to translate EBCDIC data to ASCII before test */
if (opsc['a'-'a'])
  { toascii2((Uchar*)fdat1a,fl,0x00);  /* translate EBCDIC to ASCII */
  }

/* test field length or 1st 18 bytes for unprintable chars */
/*Dec22/10 - test option o1 allow CR or LF                 */
/*Dec24/10 - removed option 'o' allow CR/LF in char flds   */
/*         - dont think I need, already in verifyc         */
/*Sep06/11 - remove CR/LF except show odo 13 or 10         */
/*         - CR/LF exception still in verifyc()            */
/*Nov11/11 - alow CR/LF if in last field of cobmap         */
for (ii=0; (ii < fl); ii++)
  { if (!(isprint(fdat1a[ii])))
      { if (((fdat1a[ii] == 0x0D) || (fdat1a[ii] == 0x0A)) 
           && (mtir+1 >= mtimax))
          { ; } 
        else 
          { bd++;                /* count bad data bytes */
          }
      }
  }

/* if no Bad Data - return now, else show hex on right (max 22) */
if (bd == 0)
  { return(0);
  }

/*eject*/
/* show data on left & hexchars on right */
/*Feb25/11 - show hex for bad fields > 9 bytes on 2nd line       */
if (fl <= 9)
  { data2hex(fdat2+12,fdat1,fl2,0x00); /* convert hex <= 9 bytes */
  }
else
  { data2hex(fdat4,fdat1,fl2,0x00);    /* convert hex > 9 bytes  */
  }

strcpy(fdat2+30,"<-BadC"); 

return(1);
}

/*eject*/
/*uvhdcob----------------------- badn2hex ------------------------------*/
/* convert bad numeric data to hex                                      */
/* - data in fdat1, length flth1 (max36)                                */
/* - if 1st 11 bytes have non-numerics, show hex on right (max 22)      */
/* - will store fdat2 to print, will test fdat1 for non-numerics        */

int badn2hex(char *fdat2, char *fdat1, int flth1)
{
int bd,fl,fl2;
bd = 0;                 /* init Bad Data switch off      */

/* determine field length to test & cnvrt to hex if reqd */
/* shorter of field length or 11 bytes max               */
fl = flth1;            /* presume field length < 12      */
fl2 = (fl * 2);        /* calc field length converted to hex*/

/* call subfunctn to check numeric field for non-numerics */
bd = verifyn(fdat1,fl,0x00);

/* if no Bad Data - return now, else show hex on right (max 22) */
if (bd == 0)
  { return(0);
  }

/* show data on left & hexchars on right */
/*Feb25/11 - show hex for bad fields > 9 bytes on 2nd line       */
if (fl <= 9)
  { data2hex(fdat2+12,fdat1,fl2,0x00); /* convert hex <= 9 bytes */
  }
else
  { data2hex(fdat4,fdat1,fl2,0x00);    /* convert hex > 9 bytes  */
  }

strcpy(fdat2+30,"<-BadN"); 

return(1);
}

/*eject*/
/*uvhd------------------------- findrec --------------------------------*/
/*May24/10 - add 'f' find specified rec#                                */
/*         - for variable lth records (RDW,LST,IDXf3/8)                 */
/* - assumes current rec# correct & searches forward                    */
/*May26/10 - add option 'm' & 'n' to find minimum to maximum recsize    */
/* f99         - use high# to see how many records in file (shows last) */
/* f999m123    - option 'm' to find record with specified record-size   */
/* f999m50n90  - option 'm' & 'n' to find recs from min to max size     */
/* ff          - repeat prior find command, save retype number & options*/
/*Nov21/10 - Index built automatically at program startup for varlth files*/

int findrec()
{
int mm;        /* option 'm' retrieved */
int nn;        /* option 'n' retrieved */

upnext = 0;    /*Jun02/10 - inhibit fp/rn updt */

/*May26/10 - allow repeat cmd for find spcfd rec-size   */
if (cms[1] == 'f')       /* repeat prior find command ? */
  { upnext = 1;          /*Jun02/10 - set fp/rn upate   */
  }
else
  { fargs = cargs;       /* store initial find cmd args */
    /*Nov21/10 - decrement find rec# (now seems 0 rel)  */
    /* fargs.cmv--; */
    /*Jan10/11 - fix findrec not finding record#1 */
    if (fargs.cmv <= 1)
      { fargs.cmv = 1;
        recnum1 = 1;
        fileptr = 0;
      }
  }

mm = fargs.opi['m'-'a']; /* store option 'm' min size (exact of no max) */
nn = fargs.opi['n'-'a']; /* store option 'n' max size                   */

/*May19/11 - test recnum > records in file, ifso set fileptr to last rec*/
if (fargs.cmv >= rcount)
  { fargs.cmv = rcount;
    recnum1 = rcount;
    fileptr = fileptr1;
    upnext = 0;
    rsz1 = getrec(0);       /* get next record */
    upnext = 0;
    return(2);
  }

/*eject*/
/*Jul09/10 - added Index tables for findrec() faster access by record#  */
/*         - tables of fileptrs & record#s to 1,2,3% etc of filesize    */
/* if Index already build - use it to find target record# */
if (fii1 == 2)
  { /* lookup table of rec#s/fileptrs for 1st rec#/fileptr >= target rec# */
    for (fii = 1; fii < 102; fii++)
      { if (firn[fii] >= fargs.cmv)
          { fii--; 
            recnum1 = firn[fii];
            fileptr = fifp[fii];
            break;
          }
      }
  }

/* begin loop to get records until current rec# = spcfd rec# */
while (1)
  { rsz1 = getrec(0);       /* get next record */
    if (rsz1 <= 0)
      { strcpy(opmsg1,"EOF reached before find record# reached\n");
        strcpy(opmsg2,
        "enter -1 to see last in file, or 1 to return to begin file\n");
        return(-1);
      }

    /*May26/10 - test option m/n for recsize or recsize range */
    if ((mm) && (nn))
      { if ((rsz1 >= mm) && (rsz1 <= nn))
          { sprintf(opmsg1,"recsize %d (in range %d:%d) at rec# %d\n"
                         ,rsz1,mm,nn,recnum1);
            upnext = 0;           /* force display found record */
            return(1);
          }
      }
    else if (mm)
      { if (rsz1 == mm)
          { sprintf(opmsg1,"record-size %d found at record# %d\n",rsz1,recnum1);
            upnext = 0;           /* force display found record */
            return(1);
          }
      }

    if (recnum1 == fargs.cmv)     /* target rec# found ? */
      { upnext = 0;   
        return(1);
      }
  }
return(0);
}

/*eject*/
/*----------------------------- findex ---------------------------------*/
/*Jul09/10 - build Index tables for findrec() faster access by record#  */
/*         - tables of fileptrs & record#s to 1,2,3% etc of filesize    */
/* initialize/calculate fifp[102] & firn[102] as follows: */
/* fifp[0]=0, fifp[1]=1% fsize, fifp[2]=2% fsize,..., fifp[100]=100% fisze*/
/* firn[0]=0, firn[1]=rec# at 1% filesize,..., firn[99]=lastrec# in file  */

int findex(void)
{
UVi64 fsa;               /* accumulate filesize for 1%, 2%,...,100%   */
UVi64 fs1;               /* calc 1% of filesize                       */
UVi64 fs1min;            /* min increment 64 or recsize if fixed      */

/*Jul11/10 - add elapsed time msg at end indexing */
time_t time1;            /* time Indexing begun   */
time_t time2;            /* time Indexing ended   */
int    time3;            /* Indexing elapsed time */
int    ss;
time1 = time(0);         /* get time at begining of Indexing */
fileptr = 0;             /* ensure fileptr at Begin File     */
recnum1 = 1;             /* init record ctr at begin file    */
firn[0] = 1;             /* store rec#1 in table paired with fileptr 0 */
fsa = 0;                 /* init filesize acum for % points            */
fs1 = (filesize / 100);  /* calc 1% of filesize for increment to 100%  */

/*Nov21/10 - min filesize increment 500 bytes or filesize if < 500 */
/*Jan10/11 - chg to recsize if fixed or else 10 bytes (Apr22/11)   */
fs1min = 10;
if (ftype == 'f')
  { fs1min = rszo;
  }
if (fs1 < fs1min)
  { fs1 = fs1min;
  }
if (fs1 > filesize)
  { fs1 = filesize;
  }

/*Apr20/11 - test for Index already built for same filname & same filesize*/
ss = findexload();    /* returns 0 if Index has to be rebuilt */
if (ss)
  { return(2);
  }

/*eject*/
/*Jan10/11 - why fii=0 here inserting fileptrs, but fii=1 below insert rec#s*/
for (fii = 0; fii < 102; fii++)
  { /* store filesize %ptrs til filesize reached, fill rmndr with filesize*/
    if (fsa < filesize)
      { fifp[fii] = fsa;
      }      
    else
      { fifp[fii] = filesize;
      }
    fsa += fs1;          /* incremnt acum by 1% filesize         */
    /*Nov21/10 - inc fsa moved after storing to make 1st entry 0 */
  }

/* prepare for loop to get records & build Index */
fii = 1;           /* reset table index for build rec# phase */
fileptr = 0;       /* ensure fileptr reset to begin file     */
printf("Begin building Index to be saved in %s\n",finame);

/*eject*/
/* begin loop to get records until EOF */
while (1)
  { rsz1 = getrec(1);       /* get next record */
    if (rsz1 > 0)           /* if not EOF      */
      { /* if fileptr >= current fifp[fii] - store rec# & up index for next*/
        if (fileptr >= fifp[fii])
          { firn[fii] = recnum1;
            /*Mar29/11 - store fileptr corspndng to recnum1 in 1% slots */
            fifp[fii] = fileptr;
            fii++;
          }
        /*May28/11 - test Index build progress message interval record count*/
        pmsgctr++;             /* increment Index build msg interval counter*/
        if (pmsgctr >= pmsgcnt)
          { printf("Index build at rec# %d of %s bytes filesize\n"
                   ,recnum1,fsedit);
            pmsgctr = 0;        /* reset ctr for next msg */
          }
      }
    else
      { /* EOF - building Index for findrec() faster access by record#   */
        /*     - store last rec# in any remaining entries in Index table */
        while(fii < 102)
          { firn[fii] = rcount;
            /*Mar29/11 - store fileptr corspndng to EOF (filesize) */
            fifp[fii] = filesize;
            fii++;
          }
        /* set Index build switch off & set fileptr to last record   */
        fii1 = 2;            /* set Index build completed            */
        /*Jul11/10 get Index end time & calc elapsed time for opmsg1 */
        time2 = time(0);
        time3 = (time2 - time1);
        indexbuildtime = time3;   /* save for findexsave() */
        printf("Index built in %d seconds, saved in %s\n"
               ,time3,finame);
        /*Nov21/10 - store rcount & inhibit subsequent changes     */
        /* - set rcountx & eof1 here as well as at EOF in getrec() */
        rcount = recnum1;       /* store record count in file      */
        rcountx = 1;            /* inhibit subsequent calcrecs     */
        eof1++;                 /* count times reached EOF         */
        /*May19/11 - save ptr to last record in file               */
        fileptr1 = fileptrp;    /* store ptr to last rec in file   */
        /*Apr20/11 - save Index in a file to save rebuilding next time */
        findexsave();
        /*may04/11 - init last BDW fileptr & rec# for any rdwerr() */
        bdwfp = 0;
        bdwrn = 1;
        return(1);
      }
  }
return(1);
}

/*eject*/
/*----------------------------- findexsave ------------------------------*/
/*Apr20/11 - save Index for loading next time uvhd called for this file  */
/*         - saved to $UVTMPDIR/uvhdindex_X------filename------X         */
/* - used if filesize same as when Index file written (saved in rec#2)   */

/* Index file records are formatted as follows                  */
/* #01:uvhdindex_X--------filename--------X                     */
/* #02:filesize=999999,fileptr1=999900,options=z8               */
/* #03:IndexCreated=yymmdd_hhmmss,BuildTimeSeconds=999          */
/* #04:BDWmin=99,BDWmax=9999,BDWavg=999,Blocks=999              */
/* #05:RCSZmin=99,RCSZmax=9999,RCSZavg=999,Records=9999         */
/* #06:1=0,2=99,3=999,4=999,...etc...                           */
/* #07:10=9999,11=9999,...etc...                                */

int findexsave(void)
{
char *pp;
int ii,ss;
int ll;        /* length of accumulated rec#s=fileptrs in current rec */
int jj;        /* length of current rec#=fileptr          */
int nn;        /* line# ctr to create #04:...,#05:...,etc */

/* create filename & open file for writing                */
/*May03/11 - Index filename now formatted at program init */
/*         - $UVTMPDIR/uvhdindex_X---datafilename---X     */
fiptr = fopen(finame,"wb");       /* open file*/
if (fiptr == (FILE*)0)
  { errmsg("opening save Index file",finame,"",0,0x40);
  }

/* write 1st 5 records with filename, filesize,options,creation date, stats*/
strcpy(firec,fir1id);          /* #01:uvhdindex_ */
strcat(firec,fn1b);            /* basename of input file */
putlin0(fiptr,firec,180,'\n',0x42);
strcpy(firec,fir2fs);          /* #02:filesize=999,...   */

/*Oct08/11 - edit fileptr1 for printf's %ld or %lld for 64/32bit HP gcc */
sprintf(fpedit1e,E64,fileptr1);
sprintf(w1,"%s,fileptr1=%s,options=%s",fsedit,fpedit1e,opsu);
/*May19/11 - fileptr1 added for findexload to restore */

strcat(firec,w1);
putlin0(fiptr,firec,100,'\n',0x42);
sprintf(firec,"#03:IndexCreated=%s_%s,BuildTimeSeconds=%d"
             ,date6,time6,indexbuildtime);
putlin0(fiptr,firec,100,'\n',0x42);

/* write rec #04:BDWmin=99,BDWmax=99,BDWavg=99,Blocks=99           */
/* calc bdwavg & rdwavg from totals accumulated during index build */
if (bdwcnt)
  { bdwavg = (bdwsum / bdwcnt);
  }
if (recnum1)
  { rdwavg = (rdwsum / recnum1);
  }

/*eject*/
sprintf(firec,"#04:BDWmin=%d,BDWmax=%d,BDWavg=%d,Blocks=%d"
             ,bdwmin,bdwmax,bdwavg,bdwcnt);
putlin0(fiptr,firec,100,'\n',0x42);
sprintf(firec,"#05:RCSZmin=%d,RCSZmax=%d,RCSZavg=%d,Records=%d"
             ,rdwmin,rdwmax,rdwavg,recnum1);
putlin0(fiptr,firec,100,'\n',0x42);

/* begin loop to write rec#s=fileptrs */
/* - restricting each record to < 80 bytes */
memset(firec,'\0',180);        /* init build area */
nn = 6;                        /* init ctr for #05:,#06: etc */
sprintf(firec,"#%02d:",nn);

for (ii=0; ii < 102; ii++)
  { /* format current rec#=filptr & test to see if appending exceeds 80 */
    sprintf(w2,"%d=%ld,",firn[ii],fifp[ii]);
    jj = strlen(w2);           /* get lth of current rec#=filptr     */
    ll = strlen(firec);        /* get acum lth of rec#s=fileptrs,... */
    if (ll+jj >= 80)
      { putlin0(fiptr,firec,100,'\n',0x42);
        memset(firec,'\0',100);
        nn++;
        sprintf(firec,"#%02d:",nn);
      }
    strcat(firec,w2);

    /* quit when index table fileptr entry reaches filesize */
    if (fifp[ii] >= filesize)
      { break;
      }
  }

/* write any partial line */
if (firec[0])
  { putlin0(fiptr,firec,100,'\n',0x42);
  }

/* close file & return */
fclose(fiptr);
return(1);
}

/*eject*/
/*----------------------------- findexload ------------------------------*/
/*Apr20/11 - load Index from a prior uvhd for this file             */
/*         - if index file exists with matching filename & filesize */

/* called at begin findex() */
/* - return 1 if index usable (saves rebuilding) */
/* - return 0 if index must be built             */

/* Index file records are formatted as follows                  */
/* #01:uvhdindex_X--------filename--------X                     */
/* #02:filesize=999999,fileptr1=999900,options=z8               */
/* #03:IndexCreated=yymmdd_hhmmss,BuildTimeSeconds=999          */
/* #04:BDWmin=99,BDWmax=9999,BDWavg=999,Blocks=999              */
/* #05:RCSZmin=99,RCSZmax=9999,RCSZavg=999,Records=9999         */
/* #06:1=0,2=99,3=999,4=999,...etc...                           */
/* #07:10=9999,11=9999,...etc...                                */

int findexload(void)
{
char *pp;
int ii,jj,kk,ss;
char firns[16];    /* current rec# string extracted from current line    */
char fifps[16];    /* current fileptr string extracted from current line */
int firn1;         /* current rec# converted to int for load to table    */
UVi64 fifp1;       /* current fileptr converted to long for load to table*/
/*May19/11 - fix index not working fileptr > 2.1 gig, chg fifp1 to UVI64 */
char filn[8];      /* current line# "#99:" validate index file records   */
int firi;          /* dsplcmnt to current rec#=fileptr on current line   */

/* force index rebuild even if existing & same size */
if (opsi['f'-'a'] & 0x02)
  { return(0);
  }

/* test for index file existing for this filename & same filesize */
/*May03/11 - Index filename now formatted at program init */
/*         - $UVTMPDIR/uvhdindex_X---datafilename---X     */
ss = stat(finame,&fstatI);
if (ss < 0)
  { /* stat failed, index does not exist, return 0 to build now */
    return(0);
  }

/* open file, get filesize when index built & compare to current filesize*/
fiptr = fopen(finame,"rb");  /* open file*/
if (fiptr == (FILE*)0)
  { errmsg("opening saved Index file",finame,"",0,0x40);
  }

/*eject*/
/* get filesize from rec#2 when index built & compare to current filesize*/
ss = getlin0(fiptr,firec,180,'\n',0x0562);
ss = getlin0(fiptr,firec,180,'\n',0x0562);
if (memcmp(firec,fir2fs,13) != 0)   /* must be #02:filesize= */
  { return(0);
  }
stncopy(filesizeIs,firec+13,',',16,0x03);
/* filesizeI = strtol(filesizeIs,(char**)0,10); May19/11*/
/* filesizeI = atol(filesizeIs); Oct04/11 chg back for gcc 32 bit HP Itanium */
filesizeI = strtoll(filesizeIs,(char**)0,10);
if (filesizeI != filesize)
  { return(0);
  }
/*May19/11 - restore ptr to last record in file */
pp = strstr(firec,"fileptr1=");
if (pp)
  { stncopy(fileptr1s,pp+9,',',20,0x03);
    /* fileptr1 = atol(fileptr1s); Oct04/11 chg back gcc 32 bit HP Itanium */
    fileptr1 = strtoll(fileptr1s,(char**)0,10);
  }

/* save create date from rec#03 for oprtr msg */
ss = getlin0(fiptr,firec,180,'\n',0x0562); /* get record#03 */
pp = strstr(firec,"Created=");
if (pp)
  { stncopy(indexcreated,pp+8,',',20,0x03);
  }

/* get rec#04 - save BDWmin if filetype z8 (validate BDW bypass on getrdw)*/
ss = getlin0(fiptr,firec,180,'\n',0x0562);
pp = strstr(firec,"BDWmin=");
if (pp)
  { stncopy(bdwmins,pp+7,',',16,0x03);
    bdwmin = atol(bdwmins);
  }
if ((opsi['z'-'a'] & 0x08) && (bdwmin <= 8))
  { errmsg("load index rec#04 BDWmin 0 for filetype z8",finame,"",0,0x40);
  }

/*May11/11 - get rec#05 RCSZmin,RCSZmax,RCSZavg,Records & save rcount */
ss = getlin0(fiptr,firec,180,'\n',0x0562);
pp = strstr(firec,"Records=");
if (pp)
  { stncopy(rcounts,pp+8,',',16,0x03);
    rcount = atol(rcounts);  /* save record count */
    rcountx = 1;             /* inhibit calcrecs */
  }
/*May28/11 - save max recsize for search op max check */
pp = strstr(firec,"RCSZmax=");
if (pp)
  { stncopy(rdwmaxs,pp+8,',',16,0x03);
    rdwmax = atol(rdwmaxs);  /* save recsize max */
  }

printf("Begin ReLoad Index %s, built %s\n",finame,indexcreated);

/*eject*/
/* begin loop to load index file rec#s=fileptrs into index table */
/* - until EOF reached in Index file */
ii = 0;        /* init index to tables of rec#s & fileptrs     */
jj = 5;        /* init ctr to verify index file records "#99:" */
while (1)
  { memset(firec,'\0',100);
    ss = getlin0(fiptr,firec,180,'\n',0x0562);
    if (ss < 0)
      { break;
      }
    jj++;            /* increment line# */
    sprintf(filn,"#%02d:",jj);
    if (memcmp(firec,filn,4) != 0)
      { return(0);
      }

    /* begin loop to store rec#s=fileptrs from current record */
    /* - presume end of line when nulls or rec# < 1           */
    firi = 4;          /* init dsplcmnt to 1st rec#=fileptr   */
    while(firec[firi])
      { sdscopy(firns,firec,100,&firi,"~~=~",0x12);
        sdscopy(fifps,firec,100,&firi,"~~,~",0x12);
        firn1 = atol2(firns,'~',16,0x01);
        /* fifp1 = strtol(fifps,(char**)0,10); May19/11*/
        /* fifp1 = atol(fifps); Oct04/11 chg back for gcc 32 bit HP Itanium */
        fifp1 = strtoll(fifps,(char**)0,10);
        if (firn1 < 1)
          { break;
          }
        firn[ii] = firn1;
        fifp[ii] =fifp1;
        ii++;
      }
  }

/* EOF on Index file of rec#s=fileptrs */
/* - fill remaining table entries with last rec#=filptr */
ii--;  /* backup to last entry */
for (jj=ii; jj < 102; jj++)
  { firn[jj] = firn[ii];
    fifp[jj] = fifp[ii];
  }

fclose(fiptr);
/* inform oprtr - using existing Index file */
printf("ReLoaded Index %s, built %s\n",finame,indexcreated);
fii1 = 2;               /* set Index reload completed      */
return(1);
}

/*eject*/
/*uvhdcob---------------------- showdcmls -------------------------*/
/* if binary 2 or 4 byte field - insert decimal value on right side*/
/* arg1 - fdat2 already converted to hex         */
/* arg2 - fdat1 binary data isolated from record */
/* arg3 - field length (expect 2 or 4)           */

int showdcmls(char *fdat2, char *fdat1, int flth1)
{
char editwa[20];                   /* edit work area */

/* - switch ends (default) if option i1 not specified              */
if (flth1 == 2)
  { /* if (opsi['i'-'a'] & 0x02)  switch ends ? (default)   */
    /*Aug13/11 - use option i for inhibit show 0/b flds, use LEM here */
    if (LEM)                   /* switch ends ? (default)   */
      { usc.cc[0] = fdat1[1];
        usc.cc[1] = fdat1[0];
      }
    else
      { memcpy(usc.cc,fdat1,2);     /* copy to union short/char  */
      }
    sprintf(editwa,"(%d dcml)",usc.ss);
    sncopy(fdat2+16,editwa,20,0x01);    /* insert decimal value on right */
  }

else if (flth1 == 4)
  { /*Aug13/11 - use option i for inhibit show 0/b flds, use LEM here */
    if (LEM)                   /* switch ends ? (default)   */
      { uic.cc[0] = fdat1[3];
        uic.cc[1] = fdat1[2];
        uic.cc[2] = fdat1[1];
        uic.cc[3] = fdat1[0];
      }
    else
      { memcpy(uic.cc,fdat1,4);         /* copy to union int/char */
      }
    sprintf(editwa,"(%d dcml)",uic.ii);
    sncopy(fdat2+16,editwa,20,0x01);    /* insert decimal value on right */
  }

/*eject*/
else if (flth1 == 8)
  { /*Aug13/11 - use option i for inhibit show 0/b flds, use LEM here */
    if (LEM)                   /* switch ends ? (default)   */
      { ulc.cc[0] = fdat1[7];
        ulc.cc[1] = fdat1[6];
        ulc.cc[2] = fdat1[5];
        ulc.cc[3] = fdat1[4];
        ulc.cc[4] = fdat1[3];
        ulc.cc[5] = fdat1[2];
        ulc.cc[6] = fdat1[1];
        ulc.cc[7] = fdat1[0];
      }
    else
      { memcpy(ulc.cc,fdat1,8);         /* copy to union long/char      */
      }
    sprintf(editwa,"(%ld dcml)",ulc.ll);
    /*Feb27/11/OM/SUN - problem sprintf %lld, changed to %ld OK */
    sncopy(fdat2+16,editwa,20,0x01);    /* insert decimal value on right */
  }

return(1);
}

/*eject*/
/*uvhdcob---------------------- switchb -------------------------------*/
/* return record slot size from ptr to 2 or 4 byte rec hdr             */
/* switch big-end to little-end if INTEL, SCO (not SUN, HP, etc)       */
/* - stores record-type, record-size,& slot-size                       */
/* - calc slot size = rcsz + 2 or +4 (if maxrcs>=4095) +3 &0x0000FFFC  */
/* - arg2 bits indicates 2 or 4 byte rec hdr                           */
/* - apply max & min rules to vrsize & vrslot                          */
/*note: switchb return value used only for min & max at file open      */

int switchb(char *vhdr, short bits)
{
/* work area unions to switch ends */
/* union INTC u1;  */
/* union INTC u2;  */
/*Mar2003 - unions u1 & u2 moved to global from switchb subfunction    */
/*        - was getting erroneous 'usage before def' msg from lcc-win32*/

int mm;

memset(u1.cc,'\0',4);          /* clear work area union                */

if (bits & 0x01)               /* if input rec hdr 4 vs 2 ?            */
  { memcpy(u1.cc,vhdr,4);      /* store 4 byte rec type & size         */
    vrtyp = u1.cc[0];          /* isolate rec type                     */
    vrtyp &= 0xF0;             /* clear digit (type in zone only)      */
    /* limit max rcsz to 65K (clear 1st 2 bytes of 4 byte rec size)    */
    u1.cc[0] = 0x00;
    u1.cc[1] = 0x00;
  }
else
  { memcpy(u1.cc+2,vhdr,2);    /* store 2 byte rec type & size         */
    vrtyp = u1.cc[2];          /* isolate rec type                     */
    vrtyp &= 0xF0;             /* clear digit (type in zone only)      */
    u1.cc[2] &= 0x0F;          /* clear zone (type) from rcsz          */
  }

/* switch big-end to little-end if INTEL or SCO (not SUN, HP, etc)     */
#if (LEM)
    u2.cc[0] = u1.cc[3];
    u2.cc[1] = u1.cc[2];
    u2.cc[2] = u1.cc[1];
    u2.cc[3] = u1.cc[0];
#else
    memcpy(u2.cc,u1.cc,4);
#endif

vrsize = u2.ii;                /* store record size                    */

/*Feb2003 - compiling on windows lcc-win32 get folwng errmsg ??        */
/* warning - uvhd.c line 3852 possible usage of u2 before definition   */
/*         - executable seems to work OK                               */

/*eject*/
/* enforce min & max rcsz */
/*Dec2002 - disable, problem on file hdr rec if max recsz < 128       */
/* if (vrsize < vrmin); vrsize = vrmin; */
/* if (vrsize > vrmax); vrsize = vrmax; */

/* calc slot size = rcsz + 2 or 4(if maxrcsz>=4095) + roundup to multiple 4*/
vrslot = vrsize + vrhs;
mm = (vrslot % 4);
if (mm)
  { vrslot += (4 - mm);
  }

return(u2.ii);
}

/*eject*/
/*uvhd------------------------- switchx -------------------------------*/
/* return record slot size from ptr to 2 or 4 byte rec hdr             */
/* switch big-end to little-end if INTEL, SCO (not SUN, HP, etc)       */
/* - stores record-type, record-size,& slot-size                       */
/* - calc slot size = rcsz + 2/4 rechdrsize + roundup to multiple of 4 */
/* - arg2 bits indicates 2 or 4 byte rec hdr                           */
/* - apply max & min rules to vrsize & vrslot                          */
/* - switchx return value used for min & max at file open              */
/*Feb23/07 - fix reading IDXFORMAT8 switchx roundup multiple of 4 not 8*/

int switchx(char *vhdr, short bits)
{
/* work area unions to switch ends */
/* union INTC u1;  */
/* union INTC u2;  */
/*Mar2003 - unions u1 & u2 moved to global from switchx subfunction    */
/*        - was getting erroneous 'usage before def' msg from lcc-win32*/

int mm;

memset(u1.cc,'\0',4);          /* clear work area union                */

if (bits & 0x01)               /* if input rec hdr 4 vs 2 ?            */
  { memcpy(u1.cc,vhdr,4);      /* store 4 byte rec type & size         */
    vrtyp = u1.cc[0];          /* isolate rec type                     */
    vrtyp &= 0xF0;             /* clear digit (type in zone only)      */
    /* limit max rcsz to 65K (clear 1st 2 bytes of 4 byte rec size)    */
    u1.cc[0] = 0x00;
    u1.cc[1] = 0x00;
  }
else
  { memcpy(u1.cc+2,vhdr,2);    /* store 2 byte rec type & size         */
    vrtyp = u1.cc[2];          /* isolate rec type                     */
    vrtyp &= 0xF0;             /* clear digit (type in zone only)      */
    u1.cc[2] &= 0x0F;          /* clear zone (type) from rcsz          */
  }

/* switch big-end to little-end if INTEL or SCO (not SUN, HP, etc)     */
#if (LEM)
    u2.cc[0] = u1.cc[3];
    u2.cc[1] = u1.cc[2];
    u2.cc[2] = u1.cc[1];
    u2.cc[3] = u1.cc[0];
#else
    memcpy(u2.cc,u1.cc,4);
#endif

vrsize = u2.ii;                /* store record size                    */

/*Feb2003 - compiling on windows lcc-win32 get folwng errmsg ??        */
/* warning - uvhd.c line 3852 possible usage of u2 before definition   */
/*         - executable seems to work OK                               */

/*eject*/
/* enforce min & max rcsz */
/*Dec2002 - disable, problem on file hdr rec if max recsz < 128       */
/* if (vrsize < vrmin); vrsize = vrmin; */
/* if (vrsize > vrmax); vrsize = vrmax; */

/* calc slot size = rcsz + rechdrsize (2/4) + roundup to multiple 4   */
vrslot = vrsize + vrhs;
mm = (vrslot % 4);
if (mm)
  { vrslot += (4 - mm);
  }

return(u2.ii);
}

/*eject*/
/*uvhd----------------------- open file -------------------------------*/
/* open input file, get file status, file size,& modification date     */
/* - coded as subfunction, since also used by 'z' truncate command     */
/* if filesize zero, set high - to allow uvhd on tape files            */

int openfile(void)
{
/* 1st get file size, using 'stat' function */
/*Dec07/07 - for lcc-win32, use _stati64    */
#if defined(LF64) && defined(DWIN)
statstat = _stati64(fn1,&fstat1);
#elif defined(LF64)
statstat = stat64(fn1,&fstat1);
#else
statstat = stat(fn1,&fstat1);
#endif

if (statstat < 0)
  { errmsg("file status error",fn1,"",0,0x40);
  }

filesize = fstat1.st_size;       /* store filesize                     */
if (filesize <= 0)               /* filesize 0 ?                       */
  { /*Aug13/11 - errmsg/quit if data file empty */
    errmsg("data file empty",fn1,"",0,0x20);
  }

/*Jun12/06 - ensure BDWmin not saved from last block in file */
filesizeb = (filesize - 32768);  /* calc fileptr of last max blocksize */
if (filesizeb <= 0)
  { filesizeb = filesize;
  }

cnvdttm(fmdate,fstat1.st_mtime); /* store last mod date                */
fmdate[10] = '\0';               /* drop seconds                       */

/* set file flags depending on option u (update)                       */
if (opsc['u'-'a'])
    openflags = O_RDWR;          /* presume O_RDWR (2) update ?        */
else
    openflags = O_RDONLY;        /* no optn u - change O_RDONLY (0)    */

/*Mar2003 - DWIN version requires O_BINARY flag                        */
#ifdef DWIN
openflags |= O_BINARY;           /* add binary flag for lcc-win32      */
#endif

/*eject*/
/* open file                                                           */
/*May2001 - provide largefile support -D LF64                          */
/*        - fopen changed to open/open64 for lseek/lseek64 (no fopen64)*/
/*Dec07/07 - open64 N/R for lcc-win32 */
#if defined(LF64) && !defined(DWIN)
fd1 = open64(fn1,openflags,0);
#else
fd1 = open(fn1,openflags,0);
#endif

if (fd1 < 0)
     errmsg("cant open file",fn1,"",0,0x40);

/*Dec02/11 - disable filelock for MinGW */
#if ! defined(DWIN)
/*Dec07/10 - setlock on fileopen if option u (but not u2)   */
if ((opsc['u'-'a']) && (!(opsi['u'-'a'] & 0x02)))
  { /* request file-lock via subfunction (calling fcntl)        */
    /* - if file locked, display status, wait 10 seconds & retry*/
    while (1)
      { lockstat = setlock(fd1,F_WRLCK, fn1);
        if (lockstat == 0)
          { waitlock(&flwait1,fn1,"lock on open file");
            continue;
          }
        else
          { break;
          }
      }
  }
#endif

/*Oct08/11 - edit filesize for printf's %ld or %lld for 64/32bit HP gcc */
sprintf(fsedit,E64,filesize);

return(1);
}

/*eject*/
/*----------------------------- setlock --------------------------------*/
/* set file lock on sequential file                                     */
/* - called after fopen (passed fileptr to convert to file dscrptr)     */
/* - return 0 if file already locked                                    */
/* - return 1 if set file lock successful (not already locked)          */

int setlock(int fd, int locktype, char *fname)
{
/*Dec02/11 - disable filelock for MinGW */
#if ! defined(DWIN)
struct flock flarg;            /* file lock arguments structure         */

/* setup flock values for fcntl call - to lock entire file              */
flarg.l_type = locktype;
flarg.l_whence = 0;
flarg.l_start = 0;
flarg.l_len = 0;
flarg.l_pid = 0;

/* request filelock via fcntl in while loop                         */
/* - repeat request if interrupt or deadlock                        */
/* - if file already locked, return 0 to caller                     */
/* - if error other than deadlock/already locked -> errmsg & end    */
/* - if filelock request successful, return 1 to caller             */

while (fcntl(fd,F_SETLK,&flarg) == -1)
  { if (errno == EINTR || errno == EDEADLOCK || errno == EDEADLK)
        continue;
    if (errno == EACCES || errno == EAGAIN)
        return(0);                   /* return 0 for already locked */
    else
        errmsg("setlock fcntl failed",fname,"",0,0x40);
  }

#endif
return(1);                           /* return 1 for setlock success */
}

/*eject*/
/*---------------------------- waitlock --------------------------------*/
/* wait on filelock & display status message every 10 secs +            */
/* wait period = 10 * (ttl mins waiting already) in seconds             */
/*             = minimum 10 secs, max 300 secs (5 mins)                 */

void waitlock(int *waita, char *file, char *msg)
{
/*Dec02/11 - disable filelock for MinGW */
#if ! defined(DWIN)
int waitm;
int wait1;

/* display file lock status message                                    */
printf("waiting %d seconds for %s %s\n",*waita,msg,file);

/* calc sleep time wait1 = (10 * minutes waiting) seconds              */
/* minimum 10 secs, max 300 secs                                       */
waitm = *waita / 60;                /* calc wait time in minutes       */
wait1 = 10 * waitm;                 /* calc secs to wait this time     */
if (wait1 < 10) wait1 = 10;         /* min 10 secs                     */
if (wait1 > 300) wait1 = 300;       /* max 300 secs                    */
sleep (wait1);                      /* sleep current wait time         */
*waita += wait1;                    /* acum total wait time            */

#endif
return;
}

/*eject*/
/*uvhd----------------------- fileseek --------------------------------*/
/* May2001 - fileseek calls lseek or lseek64                           */
/* - always seeks to fileptr variable                                  */
/* - returns only if no error detected                                 */

int fileseek(char *emsg)
{
UVi64 fileptrseek;

/*Nov21/10 - ensure fileptr not negative */
if (fileptr < 0)
  { fileptr = 0;
    recnum1 = 1;
  }

/* May 2001 - for largefiles, use lseek/lseek64 vs fseek           */
/* status = fseek(fp1,fileptr,0);    <-- fseek uses file PTR       */
/* status = lseek(fd1,fileptr,0);    <-- lseek uses file DSCRPTR   */
/* status = lseek64(fd1,fileptr,0);  <-- lseek uses file DSCRPTR   */

/*May9/2001 - having problems debuggung for largefiles             */
/* - for debug: add msg below displayed on lseek64 ??              */
/* sizeoffp = sizeof(fileptr); */
/* printf("DEBUG: lseek64 fileptr=%ld, sizeoffileptr=%d\n",fileptr,sizeoffp);*/

/*Dec07/07 - for lcc-win32, call lseeki64                 */
/*Dec07/07 - we bomb out when we reach the 2 gig limit    */
/*Dec09/07 - fixed by new lseeki64 modified from fseeki64 */
fileptrseek = fileptr;     /* debug break point */

#if defined(LF64) && defined(DWIN)
/*Dec02/11 - change lseeki64 to _lseeki64 for MinGW) */
seekstat = _lseeki64(fd1,fileptr,0);
#elif defined(LF64)
seekstat = lseek64(fd1,fileptr,0);
#else
seekstat = lseek(fd1,fileptr,0);
#endif

if (seekstat < 0)
  { printf("seek error at %ld\n",fileptr);
    errmsg("seek error",fn1,emsg,0,0x40);
  }

return(1);
}

/*Feb04/09 - cmd history code removed (saved in src/uvhd_history.c)  */
/*         - 300 lines of code (histcode) removed                    */
/*         - sorthtdd, bublsort, inithist, writehist                 */

/*eject*/
/*uvhd-------------------------- openfileX ------------------------------*/
/*Feb05/09 - subfunction to open output files P,I,W,V,D                  */

int openfileX(char *xfname, char *xfid, FILE **xfptr, int *xfopn, short bits)
{
/* inhibit if file already open */
if (*xfopn)
  { return(0);
  }

/* base filename created at program init - now add time & ID (P/I/W/V/D) */
/* $UVTMPDIR/inputfilename_yymmdd_        - will append time & P/I/W/V/D */
/* $UVTMPDIR/inputfilename_yymmdd_hhmmssW - example for Write command    */

getdatetime();                /* get current date & time */

/* if $UVTMPDIR/ subdir not present, create it now */
/*May03/11 - moved to program init */

/* create filename & open file */
strcpy(xfname,basename);      /* base filename       */
strcat(xfname,time6);         /* append current time */
strcat(xfname,xfid);          /* append file ID      */

*xfptr = fopen(xfname,"wb");
if (*xfptr == (FILE*)0)
  { errmsg("opening file",xfname,"",0,0x40);
  }

/* ifptr = *xfptr;   Feb05/09 temp DEBUG */

*xfopn = 1;                  /* set file open switch */
return(1);
}

/*uvhd-------------------------- closefileX ------------------------------*/
/*Feb05/09 - subfunction to close output files P,I,W,V,D                  */
/*Dec29/10 - add bits 0x01 to cause errmsg if file not open               */

int closefileX
   (char *xfname, char *xfid, FILE **xfptr, int *xfopn, int *xfctr, short bits)
{
/* test switch & close file if only if open */
if (*xfopn)
  { fclose(*xfptr);
    printf("%s closed, %d records written\n",xfname,*xfctr);
    *xfctr = 0;            /* clear output count for next cmd */
  }
else if (bits & 0x01)
  { printf("%s No File Open for close attempt\n",xfname);
  }

*xfopn = 0;                /* reset file open switch */
return(1);
}

/*eject*/
/*-------------------------- close files ---------------------------*/
/*Dec29/10 - new cmd 'l' to close files                             */
/* lw  - close write file                                           */
/* lp  - close print file                                           */
/* lvp - close verify print file                                    */
/* lvw - close verify write file                                    */

int close1(void)
{
if (cops[1] == 'w')
  { closefileX(wfname,"W",&wfptr,&wfopn,&wfctr,0x01);
  }
else if (cops[1] == 'p')
  { closefileX(pfname,"P",&pfptr,&pfopn,&pfctr,0x01);
  }
else if ((cops[1] == 'v') && (cops[2] == 'p'))
  { closefileX(vpfname,"VP",&vpfptr,&vpfopn,&vpfctr,0x01);
  }
else if ((cops[1] == 'v') && (cops[2] == 'w'))
  { closefileX(vwfname,"VW",&vwfptr,&vwfopn,&vwfctr,0x01);
  }
else
  { printf("invalid modifier (2nd/3rd chars) for close command (l)\n");
    printf("lw=writefile, lp=printfile, lvp=verifyprint, lvw=verifywrite");
  }

return(0);
}

/*eject*/
/*uvhd--------------------------- calcrsl --------------------------------*/
/* calc possible record size by decrementing from current recsize         */
/* - until we can divide recsize evenly into filesize                     */

int calcrsl(int rsiz, int fsiz)
{
int rsiz1;
int mod1;

/* inhibit calc if recsize <= 0 or >= filesize */
if ((rsiz <= 0) || (rsiz >= fsiz))
  { return (rsiz);
  }

for (rsiz1=rsiz; rsiz1 > 0; rsiz1--)
  { mod1 = (fsiz % rsiz1);
    if (mod1 == 0)
      { return(rsiz1);
      }
  }

return(0);
}

/*uvhd--------------------------- calcrsg --------------------------------*/
/* calc possible record size by incrementing from current recsize         */
/* - until we can divide recsize evenly into filesize                     */

int calcrsg(int rsiz, int fsiz)
{
int rsiz1;
int rsiz2;
int mod1;

/* inhibit calc if recsize <= 0 or >= filesize */
if ((rsiz <= 0) || (rsiz >= fsiz))
  { return (rsiz);
  }

rsiz2 = rsiz * 4;                 /* calc upper limit for increment test */

for (rsiz1=rsiz; rsiz1 <= rsiz2; rsiz1++)
  { mod1 = (fsiz % rsiz1);
    if (mod1 == 0)
      { return(rsiz1);
      }
  }

return(0);
}

/*eject*/
/*Dec19/10 subfnctns for getop, putop1, etc to suport acum & move numeric*/
/*------------------------------- getop -------------------------------*/
/* retrieve op input to a common format (binary UVi64)                  */
/* argument is operand# coded 0-7 for ops 1-8                          */
/* - op area may be record input, record output, work area,or constant */
/*   (opptr already determined by calling function)                    */
/* - input may be various types: zoned/packed/binary,ascii/ebcdic      */

/*Dec19/10 - add getop,putop1,etc to support acum & move numeric */
/*         - arg changed from op# (0-7) to ptr to cargs structure*/
/*Dec26/10 - arg3 bits added to specify op2 for move numeric     */

UVi64 getop(char *recd, struct CA *carg, short bits)
{
UVi64 fill1 = 0;              /* assist debug                         */
UVi64 wbin;                   /* retrieval & return w/s               */
UVi64 fill2 = 0;              /* may help if gen I32 & user spcfs >4b */
UVi32 wint;                   /* retrieval for 4 byte int             */
short wshort;                 /* retrieval for 2 byte short           */
int ii;
Uchar wsign;
float wflt;                    /* retrieval w/a for float & double    */
double wdbl;

/* following local variables to simplify coding in this function      */
int opdsp;
int oplth;
char  *opptr;
char  opdt;
char  opdc;
Uchar *wbinpi;
Uchar *wbinp = (Uchar*)&wbin;
Uchar *wintp = (Uchar*)&wint;
int w2b;                       /* calc begin byte data in w/a w2      */
wbin = 0;                      /* clear retrieval work UVi32/UVi64    */

/* 1st store field ptr & lth locally to simplify coding this function*/
/*Dec19/10 - getop arg now ptr to cargs structure                */
/*Dec26/10 - arg3 bits added to specify op2 for move numeric     */
if (bits & 0x02)
  { opdsp = carg->a2d;
    opptr = recd + carg->a2d;
    oplth = carg->a2l;
    opdt = carg->a2dt;
    opdc = carg->a2dc;
  }
else
  { opdsp = carg->a1d;
    opptr = recd + carg->a1d;
    oplth = carg->a1l;
    opdt = carg->a1dt;
    opdc = carg->a1dc;
  }

/*eject*/
/* if operand 0 lth dont attempt access, return 0 */
if (carg->a1l <= 0)
  { return 0;
  }

/* setup ascii/ebcdic codes for digits & signs depending on op data type*/
setcodes(opdc);

/* calc indices for begin byte of op when processed in work area       */
w2b = (20 - oplth);

/* test op type & retrieve data accordingly                          */
/* 1st test for op numeric count (stored in dsplcmnt as binary value)*/
/*dec26/10 - assume numeric value if no length                       */
if (!oplth)
  { wbin = opdsp;
    return(wbin);
  }

/* must be area adrs - test for 'binary' data                        */
if (opdt == 'b')                            /* binary ? (1,2,or 4)   */
 { /* if binary field NEG - init retrieval area to all x'FF's        */
   /* - in case input fewer bytes than UVi64 4/8 architecture        */
   /* test left byte for BEM & right byte for LEM                    */
   if (BEM)
     { wsign = (Uchar) opptr[0];       /* get left byte to test BEM neg */
     }
   else
     { wsign = (Uchar) opptr[oplth-1]; /* get right byte to test BEM neg*/
     }
   if (wsign & 0x80)
     { wbin = -1;
     }
   else
     { wbin = 0;
     }

   /* now test for binary field length & convert accordingly          */
   if (oplth == 1)                          /* binary 1 byte char ?   */
     { wbin = opptr[0];                     /* store in 32/64 integer */
     }

   else if (oplth == 2)                     /* binary short ?         */
     { memcpy((Uchar*)&wshort,opptr,2);     /* retrieve to short w/a  */
       if (opdc == 's')
         { bswap2((Uchar*)&wshort);         /* switch big/little ends */
         }
       wbin = wshort;                       /* store in common 4/8    */
     }

/*eject*/
   else if (oplth == 3)                     /* binary 3 bytes ?      */
     { /* justify for BEM/LEM in 4 byte int, then test for byte swap */
       /* Dec2001 - byte swap test added (was ignored for 3 byte binary)*/
       if (BEM)
         { memcpy(wintp+1,opptr,3);         /* get right 3 bytes     */
           if (opdc == 's')
             { bswap3b(wintp);              /* switch 3 bytes BEM    */
             }
         }
       else
         { memcpy(wintp,opptr,3);           /* get left 3 bytes      */
           if (opdc == 's')
             { bswap3i(wintp);              /* switch 3 bytes INTEL  */
             }
         }
       wbin = wint;                         /* store in common 4/8    */
     }

   else if (oplth == 4)                     /* binary 4 bytes ?       */
     { memcpy(wintp,opptr,4);               /* retrieve to 4 byte int */
       if (opdc == 's')
         { bswap4(wintp);                   /* switch big/little ends */
         }
       wbin = wint;                         /* move/justify in 4/8 bytes*/
     }

/* length 5-8 */
   else
     {
#if (BEM)
       /* I64 & BEM copy lths 5-8 right justified into zero work area  */
       wbinpi = (wbinp+8-oplth);
       memcpy(wbinpi,opptr,oplth);
#else
       /* I64 & LEM copy lths 5-8 left justified into zero work area   */
       memcpy(wbinp,opptr,oplth);
#endif
       /* I64, wbin stored for BEM or LEM, now byte swap if option set */
       if (opdc == 's')
         { bswap8(wbinp);
         }
     }
 }

/*eject*/
/* test op data type for 'zoned'                                        */
/* ifso - retrieve right adjusted into zero filled work area            */
/*      - test for sign, set sign switch,& remove sign from data        */
/*      - then convert to common format (binary 32/64)                  */
else if (opdt == 'z' || opdt == 'c')
 { memset(w2,zero,20);                /* zero fill w/a ascii/ebcdic*/
   w2[20] = '\0';
   memcpy(&w2[w2b],opptr,oplth);
   tstsignz(w3,w2,carg);              /* test sign, set sw, remove */

/* convert numeric string to integer long or long long depending I32/I64*/
   /* wbin = strtoll(w3,(char**)0,10); May19/11 */
   /* wbin = atol(w3); Oct04/11 chg back for gcc 32 bit HP Itanium */
   wbin = strtoll(w3,(char**)0,10);

   /*Jun00 - option t2 (inhibit recognizing '-' as neg) added in tstsignz*/
   /* - might still be a problem if atoi & strtoll recognize '-' as neg  */
   /*   & they do, BUT only if leading & trailing was my problem OK now  */
   if (sign == '-')
     { wbin = wbin * (-1);                 /* set neg if indicated      */
     }
 }

/* test op data type for 'packed'                                       */
/* ifso - retrieve right adjusted into zero filled work area            */
/*      - test for sign, set sign switch,& remove sign from data        */
/*      - then unpack & convert to common format (binary 32/64)         */
else if (opdt == 'p')
 { memset(w2,'\0',21);                /* null fill for packed retrieve */
   memcpy(&w2[w2b],opptr,oplth);
   tstsignp(w2,carg);   /* test sign, set sw, remove  */

/*990530 - change packed sign handling - signpplast, optn s1/s2, etc    */
/* - tstsignp stores signpplast, setsigns() added at end getop()        */
   unpack(w3,w2,0x01);                    /* unpack signed (ascii zones)*/

/* convert numeric string to integer long or long long depending I32/I64*/
   /* wbin = strtoll(w3,(char**)0,10); May19/11*/
   /* wbin = atol(w3); Oct04/11 chg back for gcc 32 bit HP Itanium */
   wbin = strtoll(w3,(char**)0,10);

   /* if negative sign '-', reverse sign in binary data */
   if (sign == '-')
     { wbin = wbin * (-1);                /* make data absolute value  */
     }
 }
/*9804 - mvn will output from w3 for intypes k,p,z,n & out typs z,c     */

/*eject*/
/*9811 - floating point single/double added                             */
/* test for floating point, 8f=double, 4f=single                        */
else if (opdt == 'f')                     /* float/double 4f/8f ?   */
 { if (oplth == 4)                        /* binary 1 byte char ?   */
     { memcpy((Uchar*)&wflt,opptr,4);     /* retrieve to float w/a  */
       wbin = wflt;                       /* convert float to int   */
     }
   else
     { memcpy((Uchar*)&wdbl,opptr,8);     /* retrieve to double w/a */
       wbin = wdbl;                       /* convert double to int  */
     }
 }
else
 { errmsg("getop typ ERR/bug ?","",carg->cmd,0,0x22);
 }

/*990530 - packed sign handling changed, signpplast, optn s1/s2, etc */
setsigns(carg);                       /* store signpp for next output    */

return(wbin);                     /* return result                   */
}

/*eject*/
/*------------------------------- putop1 -------------------------------*/
/* store op1 output from common binary int to indicated output format */
/* - op1 area may be record output, or work area                        */
/*   (op1ptr already determined by calling function)                    */
/* - output may be various types: zoned/packed/binary,ascii/ebcdic      */

void putop1(char *recd, struct CA *carg, UVi64 binarg)
{
UVi64 fill1 = 0;              /* zero int before wbin for lth >4,I32,BEM*/
UVi64 wbin;                   /* binarg stored here 0 left 0 right     */
UVi64 fill2 = 0;              /* may help if gen I32 & user spcfs >4b  */
UVi64 wbin1;                  /* binarg as + value for zoned/packed out*/
UVi32 fill3 = 0;              /* in case I32 used with 8 byte integers */
UVi32 wint;                   /* 4/8 justified for lth 4 output        */
int  ii;
int w3l2;
float wflt;                    /* conversion w/a for float & double    */
double wdbl;
short wshort;
int opdsp;
int oplth;
char  *opptr;
char opdc;
char opdt;
Uchar *wbinpi;
Uchar *wbinp = (Uchar*)&wbin;
Uchar *wintp = (Uchar*)&wint;
int w1b;        
int w4b;        

/* 1st store field ptr & lth locally to simplify coding this function*/
/*Dec19/10 - getop arg now ptr to cargs structure                */
/*         - for now assume op1, later allow any op 1-6 in cargs */
opdsp = carg->a1d;
opptr = recd + carg->a1d;
oplth = carg->a1l;
opdt = carg->a1dt;
opdc = carg->a1dc;

/* store input arg 4/8 depending on I32/I64 with zeros left & right    */
wbin = binarg;                        /* store input with 0 left&right */

/* test for sign & if neg set +/- indic for zoned/packed ONLY (not binary)*/
/* & reverse sign to positive in wbin1 for zoned/packed conversion      */
wbin1 = wbin;                         /* copy to 2nd area for pos cnvrt */
sign = '+';                           /* presume +                      */
if (wbin1 < 0)
  { sign = '-';                       /* set neg indic for zon/pac rtns */
    wbin1 = wbin1 * (-1);             /* create pos input for zon/pac   */
  }
/*NOTE wbin1 pos used only for zoned/packed, wbin for binary alrdy has sign*/

/* test for & convert to required op1, output format                    */
setcodes(opdc);                     /* setup ascii/ebcdic codes/signs */
setsigns(carg);                     /* set sign codes for output      */

/* calc begin data index in work area for output to op1 area (zon/pac)  */
w1b = 20 - oplth;              /* calc data start byte in w/a    */

/*eject*/
/* 1st test for 'binary' output required                                */
if (opdt == 'b')                         /* binary ? (1,2,or 4)       */
 { if (oplth == 1)                       /* binary 1 byte char ?      */
     { opptr[0] = (char) wbin;
     }
   else if (oplth == 2)                  /* binary short ?            */
     { wshort = (short) wbin;              /* move input to short       */
       if (opdc == 's')
         { bswap2((Uchar*)&wshort);        /* switch big/little ends    */
         }
       memcpy(opptr,(Uchar*)&wshort,2);  /* store short in out area   */
     }
   else if (oplth == 3)                  /* binary 3 bytes ?          */
     { /* 3 bytes out, dont test swap, just BEM/LEM justify left/right  */
       wint = wbin;                        /* cnvt possible 8 bytes to 4*/
       if (BEM)
         { memcpy(opptr,wintp+1,3);      /* store right hand 3 bytes  */
         }
       else
         { memcpy(opptr,wintp,3);        /* store left hand 3 bytes   */
         }
     }
   else if (oplth == 4)                  /* binary 4 bytes ?          */
     { wint = wbin;                        /* justify 4/8 into 4        */
       if (opdc == 's')
         { bswap4((Uchar*)&wint);          /* switch big/little ends    */
         }
       memcpy(opptr,(Uchar*)&wint,4);    /* store int  in out area  */
     }
/*Feb00 - allow lengths 5-8 for UW7 long long, DEC long                 */
   else
    { /* I64 - test byte swap option before BEM/LEM                    */
       if (opdc == 's')
         { bswap8(wbinp);
         }
#if (BEM)
       /* I64+BEM - right justify in output lth                         */
       wbinpi = (wbinp+8-oplth);
       memcpy(opptr,wbinpi,oplth);
#else
       /* I64+LEM - left justify in output lth                          */
       memcpy(opptr,wbinp,oplth);
#endif
     }
 }

/*eject*/
/* test op1 data type for 'zoned'                                       */
/* ifso - convert binary to ascii string via sprintf                    */
/*      - right justify in 20 byte work area in case out field inter    */
/*      - copy replacing zones with ebcdic zones if indicated           */
/*      - set proper sign as indicated by op1 typ/cod/sgn               */
/*      - copy to indicated output area (record out or work area)       */
else if (opdt == 'z' || opdt == 'c')
 { /*Feb27/11/OM/SUN - problem sprintf %lld, changed to %ld OK */
   /* sprintf(w3,"%lld",wbin1); */  
   sprintf(w3,"%ld",wbin1);     
   w3l2 = strlen(w3);                      /* SEE NOTE BELOW 950429     */
   memset(w4,'0',20);                      /* zero fill for sprintf ascii*/
   w4[20] = '\0';
   w4b = (20 - w3l2);                      /* calc start byte in w/a    */
   sncopy(&w4[w4b],w3,w3l2,1);             /* rt adjust sprintf in w/a  */
   setsignz(w1,w4,w1b,carg->a1sgn);        /* set sign via sign code & sw*/
                                           /* also inserts zones asc/ebc*/
   memcpy(opptr,&w1[w1b],oplth);           /* copy to out area   */
 }

/* test op1 data type for 'packed'                                      */
/* ifso - convert binary to ascii string via sprintf                    */
/*      - right justify in 20 byte work area in case out field inter    */
/*      - pack data & set proper sign as indicated by op1 typ/cod/sgn   */
/*      - copy to indicated output area (record out or work area)       */
else if (opdt == 'p')
 { /*Feb27/11/OM/SUN - problem sprintf %lld, changed to %ld OK */
   /* sprintf(w3,"%lld",wbin1); */  
   sprintf(w3,"%ld",wbin1);     
   w3l2 = strlen(w3);                      /* SEE NOTE BELOW 950429     */
   memset(w4,'\0',21);                     /* packed zero fill w/a      */
   w4b = (20 - w3l2);                      /* calc start byte in w/a    */
   sncopy(&w4[w4b],w3,w3l2,1);             /* rt adjust sprintf in w/a  */
   pack(w1,w4);                            /* pack w4 to w1             */
   setsignp(w1);                           /* set sign via sign code & sw*/
   memcpy(opptr,&w1[w1b],oplth);       /* copy to out area          */
 }

/*eject*/
/*9811 - test for floating point single/double 4f/8f                    */
else if (opdt == 'f')                    /* float/double 4f/8f        */
 { if (oplth == 4)                       /* binary 1 byte char ?      */
     { wflt = wbin;                        /* convert int to float      */
       memcpy(opptr,(Uchar*)&wflt,4);    /* copy float to op1 area    */
     }
   else
     { wdbl = wbin;                        /* convert int to double     */
       memcpy(opptr,(Uchar*)&wdbl,8);    /* copy double to op1 area   */
     }
 }
else
 { errmsg("putop1 typ ERR/bug ?","",carg->cmd,0,0x22);
 }
return;
}

/*950428 - problem compiling on SUN ucbcc at MTM Allan Crowther      */
/*       - improper ptr/int combination op "=" on w3l = sprintf(...) */
/*       - does SUN sprintf return a ptr vs an int ??????????????    */
/*       - I replaced the return value of sprintf with sep strlen    */

/*eject*/
/*---------------------------- setcodes -----------------------------*/
/* setup codes for digits, zones, & signs depending on ascii/ebcdic  */
/* arg1 = ascii/ebcdic code a/e (default to ascii if not e)          */
/* setup zoned/packed sign for current field depending on ascii/ebcdic*/

void setcodes(char code)
{
if (code == 'e')
  { zero = zeroebc;
    nine = nineebc;
    signzp = signebczp;
    signzn = signebczn;
    signsepp = signseppe;
    signsepn = signsepne;
  }
else
  { zero = zeroasc;
    nine = nineasc;
    signzp = signasczp;
    signzn = signasczn;
    signsepp = signseppa;
    signsepn = signsepna;
  }
return;
}

/*eject*/
/*---------------------------- setsigns ------------------------------*/
/* setup zoned/packed sign for current field depending on ascii/ebcdic*/
/* set code for packed positive sign, depending on option s0/s1/s2    */
/* on current instruction (or rop=s0/s1/s2 at program init)           */
/* default is to use last input packed positive sign (from last getop)*/
/*9906 - allow instrn optn s0/s1/s2 to override run options           */

void setsigns(struct CA *carg)
{

/*Dec26/10 - disable next 7 lines      */
/* signpp = signpplast;                */
/* if (carg->opi['s'-'a'] & 0x01)      */
/*   { signpp = signpp1;               */
/*   }                                 */
/* else if (carg->opi['s'-'a'] & 0x02) */
/*   { signpp = signpp2;               */
/*   }                                 */

/* store sign to be used on next putop1 depending on sign switch +/-  */
if (sign == '-')
  { signzone = signzn;
    signpack = signpn;
  }
else
  { signzone = signzp;
    signpack = signpp;
  }
return;
}

/*eject*/
/*---------------------------- tstsignp -----------------------------*/
/* test for sign in packed work area                                 */
/* - signcodes to test for predetermined depending on ascii/ebcdic   */
/* - do not modify signs in the data area                            */
/* - set sign indicator to '+' or '-'                                */
/* - if packed sign positive, save for next putop1 packed output     */
/*   unless overridden by run optn s1/s2 or instrn optn s1/s2        */
/*9907 - add options s16 - inhibit storing sign from this instrn op2 */
/*9907 - deflt validate C/F -> C, optn s4 -> F, s8 -> store as is    */

void tstsignp(char *wa, struct CA *carg)
{
Uchar wsign;                       /* rt half nibble isolated here   */

/* setup sign indicator  - presuming ascii positive                  */
sign = '+';

/* extract sign from rt half of units byte                           */
wsign = (Uchar) ((intU) wa[19] & 0x0f); /* isolate sign to sep byte  */

if (wsign == signpn)                 /* sign nibble = packed neg code*/
  { sign = '-';
  }

return;
}

/*eject*/
/*----------------------------- tstsignz -----------------------------*/
/* test for sign in zoned work area & set separate sign ind -/+       */
/* also copy to alt w/a removing any separate sign bytes & nonnums    */
/* & replacing zones with ascii numeric zones                         */

void tstsignz(char *out, char *in, struct CA *carg)
{
int ii,jj;
Uchar wsign;                  /* zone of units isolated here for test */
Uchar wsdig;                  /* units digit isolated here for test   */
char *pp;

sign = '+';                   /* presume sign positive                */

/* 1st test for code 'x' EBCDIC zone signs alrdy converted to ASCII   */
/* pos 0-9 {ABCDEFGHI 0x40-0x49 to 0123456789 0x30-0x39               */
/* neg 0-9 }JKLMNOPQR 0x40-0x49 to pqrstuvwxy 0x70-0x79 (MicroFocus)  */

if (carg->a1dc == 'x')
  { in[19] = EBs2MFs[ (Uchar) in[19] ]; 
  }

/* test zone of units byte to predetermined code for ascii/ebcdic +/- */
wsign = (Uchar) ((intU) in[19] & 0xf0); /* isolate zone sign to w/s */
wsdig = (Uchar) ((intU) in[19] & 0x0f); /* isolate units digit  w/s */
/* test units byte for neg sign x'40' bit if ASCII (common MF or MBP)  */
/* if EBCDIC - test entire zone nibble x'D0'                           */
if (carg->a1dc == 'e')
  { if ((wsign == signebczn) && (wsdig <= 9))
        sign = '-';
  }
else
  { if (((wsign == 0x70) || (wsign == 0x40)) && (wsdig <= 9))
       sign = '-';
  }

if (sign == '-')
  { in[19] = (char) ((intU) in[19] & 0x0f); /* remove sign from input*/
    in[19] = (char) ((intU) in[19] | zero); /* replc w ASC/EBC zone  */
  }                                       /* so it wont get dropped below*/
else if ((wsign == 0xC0) && (wsdig <= 9))
  { in[19] = (char) ((intU) in[19] & 0x0f); /* remove sign from input*/
    in[19] = (char) ((intU) in[19] | zero); /* replc w ASC/EBC zone  */
  }

/* test option i1 to ignore negative sign in zone */
if (carg->opi['i'-'a'] & 0x01)
  { sign = '+';
  }

/*eject*/
/* copy input to output rt adjusted, detecting any sep signs,         */
/* dropping any sep signs & nonnums, inserting ascii numeric zones    */
memset(out,0x30,20);                /* zero fill output area */
out[20] = '\0';
for (ii=19,jj=19; ii >= 0; ii--)
  {  if ((in[ii] == signsepn) && (!(carg->opi['i'-'a'] & 0x02))) 
       { sign = '-'; 
       }
     if ((in[ii] == signsepn) || (in[ii] == signsepp))
       { continue;                       /* drop any separate signs */
       }
     if ((Uchar) in[ii] < zero || (Uchar) in[ii] > nine)
       { continue;                          /* drop any nonnumerics */
       }
     out[jj] = (char) ((intU) in[ii] & 0x0f);   /* clear input zone  */
     out[jj] = (char) ((intU) out[jj] | 0x30);  /* insert ascii zone */
     jj--;
  }

return;
}

/*eject*/
/*----------------------------- setsignp --------------------------*/
/* set sign in packed work area (arg1)                             */
/* - sign determined by +/- indicator already set                  */
/* sign to be inserted already stored depending on ascii/ebcdic    */

void setsignp(char *wa)
{

/* set sign in units byte (right nibble) - already predetermined   */

wa[19] = (char) ((intU) wa[19] & 0xf0);  /* clear right nibble   */
wa[19] = (char) ((intU) wa[19] | (intU) signpack); /* insert sign*/

return;
}

/*eject*/
/*----------------------------- setsignz ---------------------------*/
/* copy zoned data,inserting sign into units zone or sep lead/trail */
/* - depending on sign indicator switch                             */
/* - replace zones in output by predermined ascii/ebcdic value      */

void setsignz(char *out, char *in, int db1, char sgncd)
{
int ii,jj;

/* setup indices for copy from right to left                        */
ii = 19; jj = 19;

/* if sep sign trailing, insert +/- in rt byte of output            */
/* - but not if pos & option to show '-' signs only                 */
if ((sgncd & 0x07) == 5)
     out[jj--] = sign;
else if (((sgncd & 0x07) == 1) && (sign == '-'))
     out[jj--] = sign;

/* copy replacing zones with predermined ascii/ebcdic value          */
while (jj >= 0)
       out[jj--] = (char) (((intU) in[ii--] & 0x0f) | zero);

/* now insert sep sign leading -/+ if indicated by options           */
if ((sgncd & 0x07) == 7)
     out[db1] = sign;
else if (((sgncd & 0x07) == 3) && (sign == '-'))
     out[db1] = sign;

/* if no sep sign byte - insert sign into zone of units byte         */
if ((sgncd & 0x07) == 0)
  {  out[19] = (char) ((intU) out[19] & 0x0f);  /* clear units zone*/
     if (sign == '-')
         out[19] = out[19] | signzn;
     else
         out[19] = out[19] | signzp;
  }

return;
}

/*eject*/
/*------------------------------ pack -----------------------------*/
/* pack work area 'in' to work area 'out'                          */

void pack(char *out, char *in)
{
int ii,jj;                   /* indices for work areas in/out */
intU zz,dd;

memset(out,'\0',21);         /* init output area to all 0x00's*/

/* switch sign from zone of input rt byte with digit of output rt byte */
dd = (intU) (Uchar) in[19] >> 4;
zz = (intU) in[19] << 4;
out[19] = (char) (zz | dd);


/* init indices for loop to cnvrt each pair unpacked to 1 packed byte   */
ii = 19 - 2;                   /* init in index to 100s & 10s digits   */
jj = 19 - 1;                   /* init out index for 100s+10s same byte*/

/* begin loop to pack each pair of input bytes to 1 output until left side */
while (jj > 0)
  { dd = (intU) in[ii+1] & 0x0f;
    zz = (intU) in[ii] << 4;
    out[jj] = (char) (zz | dd);
     ii--; ii--;               /* decrmnt for next pair input bytes    */
     jj--;                     /* decrmnt to next output byte          */
  }

return;
}

/*eject*/
/*------------------------------ unpack ---------------------------*/
/* unpack from work area 'in' to work area 'out'                   */
/* input data is right adjusted in x00 filled work area            */
/* ensure all zones are ascii numeric including units zone (sign)  */
/*9803 - add op3 bit ctl for packed sign/nosign 1/0                */

void unpack(char *out, char *in, short bits)
{
int ii,jj;
intU zz,dd;

memset(out,0x30,20);         /* init out area to ascii zeros */
out[20] = '\0';

/* IF SIGNED - reverse halves of right byte of input                  */
/*           - init indices to start 2nd byte from right side         */
/*      else - init indices to start 1st byte from right side         */
if (bits & 0x01)
  {
    dd = (intU) (Uchar) in[19] >> 4; /* shift units digit to rt half */
    out[19] = (char) (0x30 | dd);      /* force zone to ascii          */
    ii = 19-1;                   /* start input 2nd byte from rt side  */
    jj = 19-2;                   /* start output at 3rd & 2nd byte pair*/
  }
else
  { ii = 19;                     /* start input 1st byte from rt side  */
    jj = 19-1;                   /* start output at 2rd & 1nd byte pair*/
  }

/* begin loop to unpack each byte to 2 output until left end output   */
while (jj > 0)                  /* could shorten to save time ???     */
   {
     dd = (intU) in[ii] & 0x0f;
     zz = (intU) (Uchar) in[ii] >> 4;
     out[jj+1] = (char) ((intU) out[jj+1] | dd);
     out[jj]   = (char) ((intU) out[jj]   | zz);
     ii--;                      /* decrmnt to next packed input byte  */
     jj--; jj--;                /* decrmnt for next pair out bytes    */
  }

return;
}

/*eject*/
/*----------------------------- bswap2 ----------------------------*/
/* convert big-end/little-end if indicated by options              */
/* arg1 - char ptr to short                                        */

short bswap2(Uchar *ptr)
{
short ws;                             /* retrieval w/s for short    */
Uchar *wptr;

/* retrieve callers short data into temp w/s                        */
wptr = (Uchar *) &ws;                 /* setup char ptr to short    */
memcpy(wptr,ptr,2);                   /* copy to w/s unchanged      */

ptr[0] = wptr[1];                     /* copy back with switch      */
ptr[1] = wptr[0];

return(1);
}

/*eject*/
/*----------------------------- bswap3b ---------------------------*/
/* switch big-end/little-end for 3 bytes binary on BEM/RISC        */
/* arg1 - char ptr to int                                        */

short bswap3b(Uchar *ptr)
{
int  wl;                             /* retrieval w/s for int    */
Uchar *wptr;

/* retrieve callers int  data into temp w/s                        */
wptr = (Uchar *) &wl;                  /* setup char ptr to int    */
memcpy(wptr,ptr,4);                    /* copy to w/s unchanged      */

/* copy back with switch for 3 bytes BEM/RISC                        */
ptr[0] = '\0';              /* 1st byte unused for 3 byte BEM switch */
ptr[1] = wptr[3];
ptr[2] = wptr[2];
ptr[3] = wptr[1];

return(1);
}

/*----------------------------- bswap3i ---------------------------*/
/* switch big-end/little-end for 3 bytes binary on INTEL           */
/* arg1 - char ptr to int                                        */

short bswap3i(Uchar *ptr)
{
int  wl;                             /* retrieval w/s for int    */
Uchar *wptr;

/* retrieve callers int  data into temp w/s                        */
wptr = (Uchar *) &wl;                  /* setup char ptr to int    */
memcpy(wptr,ptr,4);                    /* copy to w/s unchanged      */

/* copy back with switch for 3 bytes Intel                           */
ptr[0] = wptr[2];
ptr[1] = wptr[1];
ptr[2] = wptr[0];
ptr[3] = '\0';            /* 4th byte unused for 3 byte INtel switch */

return(1);
}

/*eject*/
/*----------------------------- bswap4  ---------------------------*/
/* convert big-end/little-end if indicated by options              */
/* arg1 - char ptr to int                                        */

short bswap4(Uchar *ptr)
{
int  wl;                             /* retrieval w/s for int    */
Uchar *wptr;

/* retrieve callers int  data into temp w/s                        */
wptr = (Uchar *) &wl;                  /* setup char ptr to int    */
memcpy(wptr,ptr,4);                    /* copy to w/s unchanged      */

ptr[0] = wptr[3];                      /* copy back with switch      */
ptr[1] = wptr[2];
ptr[2] = wptr[1];
ptr[3] = wptr[0];

return(1);
}

/*eject*/
/*----------------------------- bswap8  ---------------------------*/
/* convert big-end/little-end if indicated by options              */
/* arg1 - char ptr to int                                        */

short bswap8(Uchar *ptr)
{
UVi64  wll;                            /* retrieval w/s for int    */
UVi32  xx = 0;                         /* saftey                     */
Uchar *wptr;

/* retrieve callers int  data into temp w/s                        */
wptr = (Uchar *) &wll;                 /* setup char ptr to int    */
memcpy(wptr,ptr,8);                    /* copy to w/s unchanged      */

ptr[0] = wptr[7];                      /* copy back with switch      */
ptr[1] = wptr[6];
ptr[2] = wptr[5];
ptr[3] = wptr[4];
ptr[4] = wptr[3];
ptr[5] = wptr[2];
ptr[6] = wptr[1];
ptr[7] = wptr[0];

return(1);
}

/*eject*/
/*uvhdcob-------------------- atol1 (vs atol1a) -------------------*/
/* convert ascii digit string to int integer                       */
/* - also see atol3 which has multiple stop chars vs atol1a 1 only */
/*Dec21/10 - change uvhdcob atol1a/atol3a back to atol1/atol3      */
/*                                                                 */
/* arg1 - ptr to int where result is to be stored                  */
/*                                                                 */
/* arg2 - pointer to 1st byte of data to be converted              */
/*                                                                 */
/* arg3 - stop character (in addition to NULL if bit 0x01)         */
/*        (if not needed code any dummy nonnumeric char)           */
/*                                                                 */
/* arg4 - max stop count                                           */
/*                                                                 */
/* arg5 - bit codes to modify procedure as follows:                */
/*        0x01 - stop on null, else by stopc or max count          */
/*        0x02 - stop on any nonnumeric except '-'                 */
/*             - return result of calculation so far + or -        */
/*        0x04 - bypass the stop character in ptr returned         */
/*        0x10 - recognize '-' anywhere in input & set result neg  */
/*               (otherwise ignore '-')                            */
/*        0x20 - validate string all numeric digits or '-' signs   */
/*             - if any other char found, return -1                */
/*             - if this bit not on, nonnumerics are bypassed      */
/*                                                                 */
/* return - ptr to the stop char that ends conversion              */
/*          or 1 past the stop char if bit 0x40 present            */
/*          or the current char when max lth is reached            */
/*        - may point to the null char at end of input sring       */

char *atol1(int *result, char *in, char stop, int max, short bits)
{
int nn=0;                /* result to be returned                 */
int ll;                  /* length ctr for max lth chk            */
short sign = 1;           /* neg indicator set -1 if '-' found     */

/*eject*/
/* for loop to search for ascii digits in string & accumulate result */

for (ll=0; ll < max; ll++, in++)
  {
    if ((*in == '\0') && (bits & 0x01))     /* end null reached ?     */
         break;

    if (*in == stop)                        /* stop char reached ?    */
      { if (bits & 0x04)
            in++;                           /* bypass the stop char   */
        break;
      }

    if (*in >= '0' && *in <= '9')
        nn = 10 * nn  + (*in - '0');
    else if ((*in != '-') && (bits & 0x02))
        break;
    else if ((*in == '-') && (bits & 0x10))
      { sign = -1;
        continue;
      }
    else if (bits & 0x20)
      { nn = -1;                     /* set result -1 for invalid digit */
        break;
      }
   }

/* make negative if - found & bit 0x10 & store result in users int    */
/* - return ptr to stop char (or stop+1), max lth char,or null char   */
*result = (nn * sign);
return(in);
}

/*eject*/
/*--------------------------- atol3 (vs atol3a) -------------------*/
/*Dec08/10 - atol3a same as atol3 in srcf/UVatol.c                 */
/*         - to make uvhdcob.c standalone (no UV subfunctions reqd)*/
/* convert ascii digit string to integer Uvint (32 bits)           */
/* - also see atol1 which has only 1 stop char vs multiple         */
/*Dec21/10 - change uvhdcob atol1a/atol3a back to atol1/atol3      */
/*                                                                 */
/* arg1 - ptr to UVint where result is to be stored                */
/* arg2 - pointer to 1st byte of data to be converted              */
/* arg3 - stop characters (in addition to NULL if bit 0x01)        */
/*        (if not needed code any dummy nonnumeric char)           */
/* arg4 - max stop count                                           */
/* arg5 - bit codes to modify procedure as follows:                */
/*        0x01 - stop on null, else by stopc or max count          */
/*        0x02 - stop on any nonnumeric except '-'                 */
/*             - return result of calculation so far + or -        */
/*        0x04 - bypass the stop character in ptr returned         */
/*        0x10 - recognize '-' anywhere in input & set result neg  */
/*               (otherwise ignore '-')                            */
/*        0x20 - validate string all numeric digits or '-' signs   */
/*             - if any other char found, return -1                */
/*             - if this bit not on, nonnumerics are bypassed      */

/* return - ptr to the stop char that ends conversion              */
/*          or 1 past the stop char if bit 0x40 present            */
/*          or the current char when max lth is reached            */
/*        - may point to the null char at end of input sring       */

char *atol3(int *result, char *in, char *stops, int max, short bits)
{
int nn=0;                /* result to be returned                 */
int ll;                  /* length ctr for max lth chk            */
int jj;                  /* index for stops char search           */
short sign = 1;            /* neg indicator set -1 if '-' found     */

/*eject*/
/* for loop to search for ascii digits in string & accumulate result */

for (ll=0; ll < max; ll++, in++)
  { 
    if ((bits & 0x01) && (*in == '\0'))
         break;

    for (jj=0; stops[jj] > '\0'; jj++)
         if (stops[jj] == *in)
             break;
    if (stops[jj] != '\0') 
      { if (bits & 0x04)
            in++;                               /* bypass the stop char   */
        break;
      }

    if (*in >= '0' && *in <= '9')
        nn = 10 * nn  + (*in - '0');
    else if ((*in != '-') && (bits & 0x02))
        break;
    else if ((*in == '-') && (bits & 0x10))
      { sign = -1;
        continue;
      }
    else if (bits & 0x20)
      { nn = -1;                     /* set result 0 for invalid digit */
        break;
      }
   }

/* make negative if - found & bit 0x10 & store result in users outfield */
/* - return ptr to stop char (or stop+1), max lth char,or null char     */
*result = ( nn * sign);
return(in);
}

/*eject*/
/*uvhdcob-------------------- spcopya ----------------------------*/
/* copy op2 to op1 until any of the following occurs:             */
/*     1 - an input character matches the op3 stop character      */
/*         (or does not match if bit 0x10)                        */
/*     2 - the op4 max count is reached                           */
/*     3 - a null is reached in the input (may inhibit by op5)    */
/*                                                                */
/* arg1 - output area                                             */
/* arg2 - input string                                            */
/* arg3 - stop characters string                                  */
/* arg4 - max stop count                                          */
/* arg5 - bit control codes                                       */
/*        0x01 - also stop copy on input null (default does not)  */
/*        0x02 - null terminate the output (default does not)     */
/*        0x04 - if stop by op3 char bypass it in the ptr returned*/
/*        0x08 - if stop by op3 char include it in output         */
/*        0x10 - reverse stop char - copy until we find a nonmatch*/
/*        0x20 - if stop by op3 char, bypass any multiples to non */
/*                                                                */
/* return - pointer to end position in input data                 */
/*          (stop char, char when max count reached, ending NULL) */

char *spcopya(char *out, char *in, char stop, int max, short bits)     
{                   
char *maxp;                          /* ptr to max input address   */

maxp = in + max;                     /* calculate max adrs in input */

/*eject*/
while (in < maxp)
  { if ((bits & 0x01) && (*in == '\0'))
        break;

    /*  stop when stop char reached, or reverse logic ?               */
    /*  - when we reach a data byte not matching the op3 character    */
    if (bits & 0x10)
      { if (*in != stop)   
          { if (bits & 0x08)         /* option to include stopchar ? */
               *out++ = *in;  
            if (bits & 0x04)     
               in++;                 /* bypass stop char in ptr return */
            break;
          }
      }
    else
      { if (*in == stop)   
          { if (bits & 0x08)         /* option to include stopchar ? */
               *out++ = *in;  
            if (bits & 0x04)     
               in++;                 /* bypass stop char in ptr return */
            if ((bits & 0x20) && (*in == stop))
              { while ((*in == stop) && (in < maxp))
                        in++;
              }
            break;
          }
      }

     /* copy the current character, incrmnt ptrs,& repeat loop        */
     *out++ = *in++;       
  }

/* test option to null terminate the output string (usual)            */
if (bits & 0x02)
    *out = '\0';

return(in);                       /* return ptr to new position     */
}

/*eject*/
/*---------------------------- testnp -------------------------------*/
/*Aug04/11 - scan packed field for non-zero digits, return 1, else 0 */
/*Aug23/11 - also test for all ASCII blanks                          */
/*Aug25/11 - testnp/nb passed fdat1/flth1 vs fdat2/flth2 testnn/nc   */

int testnp(char *data, int lth)
{
int ii;

for (ii=0; ii < lth; ii++)
  { if ((data[ii] == 0x00) || ((data[ii] == 0x0C) && (ii == lth-1))
         || (data[ii] == ' '))
      { continue;
      }
    else
      { return(1);
      }
  }
return(0);
}

/*------------------------------ testnb -----------------------------*/
/*Aug04/11 - scan binary field for non-zero digits, return 1, else 0 */
/*Aug23/11 - also test for all ASCII blanks                          */
/*Aug25/11 - testnp/nb passed fdat1/flth1 vs fdat2/flth2 testnn/nc   */

int testnb(char *data, int lth)
{
int ii;

for (ii=0; ii < lth; ii++)
  { if ((data[ii] == 0x00) || (data[ii] == ' '))
      { continue;
      }
    else
      { return(1);
      }
  }
return(0);
}

/*eject*/
/*---------------------------- testnn --------------------------------*/
/*Aug04/11 - scan Numeric field for non-zero digits, return 1, else 0 */
/*Aug25/11 - also test for all blanks in numeric fields               */

int testnn(char *data, int lth)
{
int ii;

for (ii=0; ii < lth; ii++)
  { if ((isdigit(data[ii]) && (data[ii] == '0')) || (data[ii] == ' '))
      { continue;
      }
    else
      { return(1);
      }
  }
return(0);
}

/*---------------------------- testnc ----------------------------------*/
/*Aug04/11 - scan Character field for non-blank chars, return 1, else 0 */
/*Aug21/11 - also test for nulls & EBCDIC blanks                        */
/*         - nulls have been converted to '.'s & EBCDIC blanks to '@'s  */

int testnc(char *data, int lth)
{
int ii;

for (ii=0; ii < lth; ii++)
  { if ((data[ii] == ' ') || (data[ii] == '@') || (data[ii] == '.'))
      { continue;
      }
    else
      { return(1);
      }
  }
return(0);
}

/*eject*/
/*------------------------------ lookmap -------------------------------*/
/*Sep03/11 - lookup maptbl for field bgn <= dsplcmnt matched field      */
/*         - to display matched field on 1st screen of long records     */

int lookmap(int recdsp)
{
int mti;
int mtim;
mtim = mtiend;  /* init return to end of table */

for (mti=mtibgn; mti <= mtiend; mti++)
  { if (maptbl[mti].end == 0)       /* bypass groups & BGN/END OCCURS */
      { continue;
      }
    if (maptbl[mti].bgn == recdsp)
      { mtim = mti;
        break;
      }
    if (maptbl[mti].bgn > recdsp)
      { mti--;                      /* backup to prior entry */
        while(maptbl[mti].end == 0) /* bypass groups & BGN/END OCCURS */
          { mti--;
          }
        mtim = mti;
        if (mtim < 0)
          { mtim = 0;
          }
        break;
      }
  }
return(mtim);
}

/*eject*/
/*---------------------------------------------------------------------*/
/*Mar07/09 - following functions included in program for internet share*/
/*         - originally linked in from uvlib.a archive                 */

/*uvhdcob-------------------- atol2 -------------------------------*/
/* atol2.c - convert ascii string to int integer                  */
/*  - older version, may phase out sometime                        */
/* arg1 - pointer to 1st byte of data to be converted              */
/* arg2 - alternate stop character (in addition to NULL)           */
/*        (if not needed code any dummy nonnumeric char)           */
/* arg3 - max stop count                                           */
/* arg4 - bit codes to modify procedure as follows:                */
/*        0x01 - stop on null, else by stopc or max count          */
/*        0x02 - stop on any nonnumeric except '-'                 */
/*             - return result of calculation so far + or -        */
/*        0x04 - recognize '-' anywhere in input & set result neg  */
/*               (otherwise ignore '-')                            */
/*        0x08 - validate string all numeric digits or '-' signs   */
/*             - if any other char found, return 0                 */
/*             - if this bit not on, nonnumerics are bypassed      */

int atol2(char *str, char stopc, int max, short bits)
{
int num=0;               /* result to be returned                 */
int j;                   /* work index                            */
short sign = 1;          /* neg indicator set -1 if '-' found     */

for (j=0; j < max && str[j] != stopc; j++)
   {
     if ((bits & 0x01) && (str[j] == '\0'))
          break;
     if (str[j] >= '0' && str[j] <= '9')
         num= 10 * num + (str[j] - '0');
     else if ((str[j] != '-') && (bits & 0x02))
              break;
     else if ((str[j] == '-') && (bits & 0x04))
           { sign = -1;
             continue;
           }
     else if (bits & 0x08)
             return(0);
   }
return(num * sign);
}

/*eject*/
/*uvhdcob-------------------- sncopy --------------------------*/
/* copy op2 to op1 until the op3 max count reached             */
/* or until a null is reached if op4 has a 1 bit               */
/* - null terminate the output if op4 has a 2 bit              */
/* - return the actual length copied                           */

int sncopy(
char out[],              /* output string           */
char in[],               /* input string            */
int max,                 /* no of chars to copy     */
short bits)              /* stop on null if 1 bit   */
{                        /* null terminate if 2 bit */
int i;

for (i=0; i < max; i++)
  {  if ((bits & 0x01) && (in[i] == '\0'))
         break;             /* stop on null if op4 1 bit  */
     out[i] = in[i];        /* copy the current character */
  }

if (bits & 0x02)            /* if indicated by op4 = 2      */
    out[i] = '\0';          /* null terminate output string */

return(i);
}

/*eject*/
/*uvhdcob-------------------- stncopy ----------------------------*/
/* copy op2 to op1 until any of the following occurs:             */
/*     1 - an input character matches the op3 stop character      */
/*     2 - the op4 max count is reached                           */
/*     3 - a null is reached in the input (may inhibit by op5)    */
/* op5 is bit coded to control the following:                     */
/*     0x01 - also stop copy on input null (default does not)     */
/*     0x02 - null terminate the output (default does not)        */
/*     0x04 - if copy is stopped by op3 char include it in output */
/* - return the actual data byte count copied                     */

int stncopy(
char *out,                /* output string                    */
char *in,                 /* input string                     */
char stopc,               /* stop character                   */
int max,                  /* max bytes to copy                */
short bits)               /* options (see above)              */
{
int i;

for (i=0; i < max; i++)
   { if ((bits & 0x01) && (in[i] == '\0'))
         break;
     if (in[i] == stopc)
         break;
     out[i] = in[i];      /* copy the current character   */
   }

if ((bits & 0x04) && (in[i] == stopc))
      out[i++] = stopc;
if (bits & 0x02)
    out[i] = '\0';

return(i);              /* return actual bytes copied   */
}

/*eject*/
/*uvhdcob-------------------- stmcopy ----------------------------*/
/* copy op2 to op1 until any of the following occurs:             */
/*     1 - an input character matches any char in op3 string      */
/*     2 - the op4 max count is reached                           */
/*     3 - a null is reached in the input (may inhibit by op5)    */
/* return the actual data byte count copied                       */

/* op5 is bit coded to control the following:                     */
/*     0x01 - also stop copy on input null (default does not)     */
/*     0x02 - null terminate the output (default does not)        */
/*     0x04 - if copy is stopped by op3 char include it in output */
/*     0x08 - inhibit match on 1st byte of data                   */

/*Oct11/07 - add bits to inhibit char detect in quotes & parens   */
/*     0x10 - inhibit char detect within single quotes            */
/*     0x20 - inhibit char detect within single quotes            */
/*     0x40 - inhibit char detect within (parens)                 */

int stmcopy(
char *out,                /* output string                    */
char *in,                 /* input string                     */
char *stops,              /* stop characters                  */
int max,                  /* max bytes to copy                */
short bits)               /* options (see above)              */
{                   
int ii,jj,kk,q1,q2,pl,pr;

kk=0;q1=0;q2=0;pl=0;pr=0;

if (bits & 0x08)
  { kk = 1; 
  }

/*eject*/
/*Oct11/07 - inhibit char detect if in quotes or parens       */
/* - count special chars to inhibit detections                */
/* - when target detected, ignore/continue if counts indicate */
for (ii=0,jj=0; ii < max; ii++)
   { if (in[ii] == '\'') q1++;
     if (in[ii] == '\"') q2++;
     if (in[ii] == '(')  pl++;
     if (in[ii] == ')')  pr++;

     if ((bits & 0x01) && (in[ii] == '\0'))
       { break;
       }

     for (jj=0; stops[jj] > 0; jj++)
        { /* ignore match on 1st byte if bits 0x08 (kk set 1 above) */
          if ((stops[jj] == in[ii]) && (ii >= kk))
            { /*Oct11/07 - inhibit char detect if in quotes or parens */
              if ((bits & 0x10) && (q1 % 2 == 1)) { ; }
              else if ((bits & 0x20) && (q2 % 2 == 1)) { ; }
              else if ((bits & 0x40) && (pl != pr)) { ; }
              else { break; }
            }
        }
     if (stops[jj] != '\0')
       { break;
       }
     out[ii] = in[ii];      /* copy the current character   */
   }

if ((bits & 0x04) && (in[ii] == stops[jj]))
  { out[ii++] = stops[jj];
  }
if (bits & 0x02)
  { out[ii] = '\0';
  }

return(ii);              /* return actual bytes copied   */
}

/*eject*/
/*uvhdcob-------------------- sdscopy -------------------------------*/
/* copy function controlled by dsplcmnt allowing bypass & stop chars */
/*                                                                   */
/* arg1 - the output area (should be as big as the input area)       */
/* arg2 - the input data string                                      */
/* arg3 - max length of input area                                   */
/* arg4 - pointer/displacement to current position in input area     */
/*      - updated to the stop char position or end op2 if nofind     */
/* arg5 - bypass or stop character string (always 4 chars)           */
/*      - 1,2 are bypass chars active if bit code 0x0300 present     */
/*      - 3,4 are stop chars always active, post bypass if 0x0030    */
/* arg6 - bit control codes                                          */
/*        0x1000 - init the displacement before this copy begins     */
/*        0x2000 - inhibit testing stop chars within single quotes   */
/*        0x0100 - bypass char#1 if present, then char#2 if present  */
/*        0x0200 - bypass multiples of #1, then multiples of #2      */
/*        0x0010 - if stopped by char #3, bypass it in dsplcmt update*/
/*               - then check for char #4,& bypass if present        */
/*        0x0020 - if stopped by char #3, bypass multiples to non #3 */
/*               - then bypass any multiple occurrences of char #4   */
/*        0x0002 - null terminate the output string                  */
/*        0x0001 - if stop search on input string null               */
/*                 dont set dsplcmnt to max                          */
/*                 (default sets dsplcmnt to max on nofind stopchar) */
/*                                                                   */
/* return - the length of the data copied                            */
/*        - note that arg4 dsplcmnt is also updated                  */
/*        - stop char nofinds, set the dsplcmnt to the max (arg3)    */

int sdscopy(char *out,char *in,int max,int *sds,char *stop,short bits)
{
int ii;
int sdi;            /* dsplcmnt retrvd to local, will update at end */
int qq=0;           /* quote counter (to inhibit stop within)       */

/* retrieve the dsplcmnt to a local var & init if bit 0x1000         */
sdi = *sds;                    /* retrieve current dsplcmnt to local */
if (bits & 0x1000)
    sdi = 0;

/* test bit controls for pre-copy bypass option single or multiple   */
if (bits & 0x0300)
  { while ((in[sdi] == stop[0]) && (sdi < max))
      { sdi++;
        if ((bits & 0x0200) == 0)       /* multi bypass bit ?        */
           break;
      }
    /* test pre-copy bypass for char #2 single or multiple           */
    while ((in[sdi] == stop[1]) && (sdi < max))
      { sdi++;
        if ((bits & 0x0200) == 0)       /* multi bypass bit ?        */
           break;
      }
  }

/*eject*/
/* copy input to output until NULL, max lth, or either stop char found*/
ii = 0;
while (sdi < max)
  { if (in[sdi] == '\'')
        qq++;                           /* count qts for stop inhibit */
    if ((bits & 0x2000) && (qq % 2))
      { ;
      }
    else
      { if (in[sdi] == stop[2])
           break;
        if (in[sdi] == stop[3])
           break;
      }
    if (in[sdi] == '\0')                /* null reached, no stop char   */
      { if ((bits & 0x0001) == 0)       /* stop null & dont set dsp max */
          { sdi = max;                  /* yes - set dsp max for nofind */
          }
        break;
      }
    out[ii++] = in[sdi++];              /* copy current byte, up to next*/
  }

/* bypass stop chars single or multiple depending on bit ctls          */
if (bits & 0x0030)                     /* bypass stop char requested ? */
  { while ((in[sdi] == stop[2] && sdi < max))
      { sdi++;
        if ((bits & 0x0020) == 0)
           break;
      }
    while ((in[sdi] == stop[3] && sdi < max))
      { sdi++;
        if ((bits & 0x0020) == 0)
           break;
      }
  }

/* null terminate the output if bit 0x0002                            */
if (bits & 0x0002)
   out[ii] = '\0';

/* store the new displacement & return lth of data copied            */
*sds = sdi;
return(ii);
}

/*eject*/
/*uvhdcob----------------------- searchcm -----------------------------*/
/* search a string for 1st character that matches any character        */
/* within a 2nd string                                                 */
/* - return the index of the found char within the string              */
/*   or return -1 if nomatch found                                     */
/* arg1 - points to the string to be searched                          */
/* arg2 - points to the string of characters to be searched for        */
/* arg3 - max length of string 1 to search                             */
/* arg4 - max length of string 2 to search                             */
/* arg5 - bit codes                                                    */
/*        1 - stop on null in string 1 (else on max length)            */
/*        2 - stop on null in string 2 (else on max length)            */

int searchcm(char *s1, char *s2, int max1, int max2, short bits)
{
int i,j;

for (i=0; i < max1; i++)
  {  if ((bits & 0x01) && (s1[i] == '\0'))
         break;
     for (j=0; j < max2; j++)
       { if ((bits & 0x02) && (s2[j] == '\0'))
            return (-1);
         if (s2[j] == s1[i])
            return(i);
       }
  }
return(-1);
}

/*eject*/
/*uvhdcob--------------------- errmsg.c ----------------------------*/
/* errmsg.c - display error message on stderr                       */
/* arg1 = msg text, may include \n if arg2 to be on 2nd line        */
/* arg2 = addtnl info such as filename or error data string         */
/* arg3 = addtnl info#2 (null if not needed)                        */
/*      - by convention msg2=logical & msg3=physical filename       */
/* arg4 = integer to be converted to ascii numeric                  */
/*        to replace underscores '_'s in the arg1 string (if any)   */
/*        or column# for * error marker to be displayed on next line*/
/*        if bitcode 0x04 present                                   */
/* arg5 = bitcodes to modify behaviour as follows:                  */
/*        0x000_ - info msg, display no prefix, return after msg    */
/*        0x001_ - display 'ERR -' prefix, return after msg         */
/*        0x002_ - display 'FATAL ERR -' prefix, exit program       */
/*        0x004_ - display 'SYSTEM ERR -' prefix, exit program      */
/*        0x00_1 - insert LF after msg1                             */
/*        0x00_2 - insert LF after msg2                             */
/*               - will always insert LF after msg3                 */
/*        0x00_4 - use arg4 as col# for '*' marker on next line     */
/*        0x0100 - wait for operator reply before returning         */

void errmsg(char *msg1, char *msg2, char *msg3, int num, short bits)
{
char prefix[16];
char msga[80];                   /* arg1 copied here for insert of num*/
char msgb[80];                   /* arg2,3 copied to ensure null term */
char msgc[80];
char numasc[8];                  /* arg4 converted to ascii numeric */
char lf1[2] = "\n";              /* LF or blank insert after msg1   */
char lf2[2] = "\n";              /* LF or blank insert after msg2   */
int i,j;

/* 1st setup prefix depending on severity bit code                  */
prefix[0] = '\0';               /* presume info, no prefix desired */
if (bits & 0x10)
    strcpy(prefix,"ERR -");
if (bits & 0x20)
    strcpy(prefix,"FATAL ERR -");
if (bits & 0x40)
    strcpy(prefix,"SYSTEM ERR -");

/*eject*/
/* setup LFs/blanks for insert before msg2/msg3   depending on bits*/
lf1[0] = '\0';                    /* presume blank                */
lf2[0] = '\0';
if (bits & 0x01)
    lf1[0] = '\n';
if (bits & 0x02)
    lf2[0] = '\n';

/* copy users strings to w/s & ensure null terminated             */
memset(msga,'\0',80);
memset(msgb,'\0',80);
memset(msgc,'\0',80);
sncopy(msga,msg1,79,1);
sncopy(msgb,msg2,79,1);
sncopy(msgc,msg3,79,1);

/* convert arg4 integer to ascii numeric to replace any '_'s in arg1*/
sprintf(numasc,"%6d",num);
for (i=79,j=5; i >= 0; i--)
    if (msga[i] == '_')
        msga[i] = numasc[j--];

/* now display the constructed message                            */
printf("%s %s %s %s %s %s \n",prefix,msga,lf1,msgb,lf2,msgc);

/* display error marker line if bit 0x04 & arg4 col# > 0 & < 80   */
if ((bits & 0x04) && (num > 0) && (num < 78))
  { memset(msga,' ',78);           /* fill flagline with blanks   */
    msga[78] = '\n';               /* line feed at col 79         */
    msga[79] = '\0';               /* null term at col 80         */
    msga[num] = '*';               /* insert '*' at flag column#  */
    printf(msga);
  }

/*eject*/
/* if syserr bit 0x40 & system errno is valid - display errno alpha */
/* if ((bits & 0x40) && (errno > 0) && (errno < sys_nerr))          */
/*     printf("%d %s\n",errno,sys_errlist[errno]);                  */
/* above replaced by perror - July 93 (undefs on svr5r4)            */
if (bits & 0x40)
    perror("FATAL ERR ");

/* return to caller if severity bits 0 or 1, exit program if 2/6    */
if (bits & 0x60)
    exit(99);
else
  { /* wait for oprtr reply if bit 0x100                            */
    if (bits & 0x100)
      { printf(" - reply to continue (or kill job) \n");
        fgets(msgc,80,stdin);
      }
  }
return;
}

/*eject*/
/*uvhdcob-------------------- showhelp ------------------------------*/
/* showhelp.c - display "help" screen - by O Townsend aug 92         */
/* - arg1 is ptr to array of char ptrs to strings                    */
/* - strings will be displayed on stderr until '!' is found          */
/*   in 1st char of any string or a null pointer is reached          */
/*Jan18/06 - OR until max lines displayed                            */
/*         - if bits 0x01, display blank lines up to max lines       */

int showhelp(char **msgs, int max, short bits)
{
int ii,nn;
nn = 0;
for (ii=0; ii < max; ii++)
  { if ((!msgs[ii]) || (msgs[ii][0] == '!') || (msgs[ii][0] == '\0'))
      { if (bits & 0x01)
          { while (ii < max)
              { printf(" \n");
                ii++;
              }
          }
        break;
      }
    else
      { printf("%s\n",msgs[ii]);
      }
  }
return(ii);
}

/*eject*/
/*------------- convert unix time to date/time string------------*/
/* arg2 points to a unix time (secs since 1970)                  */
/* converts unix time to "ccyymmddhhmmss" & stores in arg1       */
/* arg1 = ptr to 14 byte char array to receive "ccyymmddhhmmss"  */
/*        (not null terminated)                                  */

void cnvdttm(char *dtp, time_t unixtm)
{
struct tm *p;
int month;
char dtws[16];

p = localtime(&unixtm);
month = p->tm_mon + 1;

sprintf(dtws,"%04d%02d%02d%02d%02d%02d",
p->tm_year+1900,month,p->tm_mday,
p->tm_hour,p->tm_min,p->tm_sec);

memcpy(dtp,dtws,14);

return;
}

/*eject*/
/*uvhdcob-------------------- hex2data -------------------------------*/
/* hex2data.c - function to convert hex representation to true data   */
/*            - by Owen Townsend, ARC, AUG92, updt NOV92              */
/* - returns count of output data length converted                    */
/* arg1 - points to output area  (input data will be twice as int)   */
/* arg2 - points to input hex rep (either upper or lower case a-f)    */
/* arg3 - optional stop char (if not needed code an unlikely char)    */
/* arg4 - max length of output (stop if reached)                      */
/* arg5 - bit options                                                 */
/*        0x01 - stop if null reached in input                        */
/*        0x02 - null terminate the output string                     */

int hex2data(char *out, char *in, char stopc, int max, short bits)
{
int i,j;
intU z,d;                              /* work areas for zone & digit */

for (i=0,j=0; j < max; i++,i++,j++)
 {  if ((bits & 0x01) && (in[i] == '\0'))
        break;
    if (in[i] == stopc)
        break;

   z = (intU)(in[i] & 0x7f);          /* remove any high bit of zone rep  */
   if (z > 'Z') z = z & 0x5f;         /* if upper, convert to lower       */
   if (z > '9') z = z -7;             /* if a-f convert low 4 bits to a-f */
                                      /* 0x41:0xf4 - 7 = 0x3a:0x3f        */
   z = z << 4;                        /* shift result to zone & clr digit */

   d = (intU)(in[i+1] & 0x7f);        /* remove any high bit of digit rep */
   if (d > 'Z') d = d & 0x5f;         /* if upper, convert to lower       */
   if (d > '9') d = d -7;             /* if a-f convert low 4 bits to a-f */
                                      /* 0x41:0xf4 - 7 = 0x3a:0x3f        */
   d = d & 0x0f;                      /* clear zone bits                  */

   out[j] = (char)(z | d);            /* combine zone & digit into output */
 }

if (bits & 0x02)                      /* option to null term output ?     */
    out[j] = '\0';

return(j);                            /* return the data length converted */
}

/*eject*/
/*uvhdcob--------------------- sortops ---------------------------------*/
/* sortops.c - process options into alpha position                      */
/*               in character,& integer arrays                          */
/* - this subrtn is commonly used to process an option string from the  */
/*   command line into sorted forms easily accessed by the user programs*/
/* - options must be contiguous as in following examples:               */
/*                                                                      */
/*  abc                 - no spaces between option letters              */
/*  cba                 - not necessarily in sequence                   */
/*  b512e512r256        - option letters may have numeric args          */
/*  b512,e512,r256      - may use , separators if desired               */
/*                                                                      */
/* arg1 - input string                                                  */
/* arg2 - output sorted array of characters (or Nulls)                  */
/* arg3 - output sorted array of int ints                              */
/* arg4 - control bits - 0x00 arrays will be cleared to nulls           */
/*        0x01 - arrays will not be cleared (any prior optns remain)    */
/*        0x10 - return success/fail (+1/-1) indication to caller       */
/*               rather than errmsg&exit if invalid input detected      */

int sortops(char *opsu, char *opsc, int *opsi, short bits)
{
int ui;                    /* index to the input raw option string    */
char c;                    /* current option letter being processed   */
int ci;                    /* index to the character array            */
int j;                     /* misc index                              */
char nums[16];             /* numerics following current optn ltr     */
int ni;                    /* index to numeric array                  */

/* 1st clear the output arrays - unless inhibited by bits 0x01         */
if ((bits & 0x01) == 0)
  {  for (j=0; j < 26; j++)
        { opsc[j] = 0;             /* init the character array to nulls */
          opsi[j] = 0;             /* init integer array to zeros       */
        }
  }

/* bypass any leading '-' option identifier                             */
ui = 0;                        /* init index to 1st char                */
if (opsu[ui] == '-')
    ui++;                      /* bypass any leading '-'                */

/*eject*/
/* begin loop to extract each optn letter into opsc[] alpha sorted array*/
/* & to convert any appended digits to binary & store in opsi[] array   */
while (opsu[ui] > ' ')         /* until end string null/blank ?         */
  { c = opsu[ui++];            /* save current option letter            */
    if (c < 'a' || c > 'z')
       { printf("sortops invalid at byte# %d %s \n",ui,opsu);
         if (bits & 0x10)      /* return fail code or exit here ?       */
             return(-1);
         else
             exit(-1);
       }
    ci = c - 'a';              /* index into sorted options array       */
    opsc[ci] = c;              /* store optn letter into sorted array   */

    /* now isolate optional numeric string following alpha letter       */
    /*  convert to binary & store in integer array                      */
    ni = 0;
    while (opsu[ui] >= '0' && opsu[ui] <= '9')
           nums[ni++] = opsu[ui++];      /* store current digit        */
    nums[ni] = '\0';                     /* null terminate num string  */
    opsi[ci] = atol2(nums,'~',16,3);     /* cnvrt numstring to integer */

    /* bypass any comma ',' separator before next alpha option letter  */
    if (opsu[ui] == ',')
        ui++;
  }
return(1);
}

/*eject*/
/*uvhdcob--------------------- sortops4 --------------------------------*/
/* sortops4.c - process options into alpha position                     */
/*               in character, integer,& string arrays                  */
/* This subrtn is commonly used to process an option string from the    */
/* command line into sorted forms easily accessed by the user programs  */
/* Options must be contiguous as in following examples:                 */
/*                                                                      */
/*  option input string - example description                           */
/*  ------------------------------------------------------              */
/*  abc                 - no spaces between option letters              */
/*  cba                 - not necessarily in sequence                   */
/*  b512e512-r256       - option letters may have numeric args&trlng sign*/
/*  b512,e512,r256      - may use , separators if desired               */
/*  b=512,e=512,r=256   - may use = separators if desired               */
/*                        (must use if any alpha in args)               */
/*  a=jkl,b=xyz         - must use = sep to assign non-numeric strings  */
/*  a='cat',b='c t'     - may enclose value in single quotes            */
/*                        (must do if any embedded blanks)              */
/*  a=^01ef^            - indicates hexadecimal string                  */
/*                      - converted to true hex when stored             */
/*                 note - must enclose hex strigs in '^'s (circumflexes)*/
/*                        because quotes are removed by the shell       */
/*                                                                      */
/* bit control arg#6                                                    */
/*     0x10 - return success/fail (+1/-1) indication to caller          */
/*            rather than exit here if invalid input detected           */
/*                                                                      */
/* note - also see sortops.c which provides only the char sorted array  */
/*        & the integer array, but not the string ptrs & string buffer  */
/*      - used by programs not requiring the strings (less overhead)    */

int sortops4(char*opsu,char*opsc,int*opsi,char**opsp,char*opsb,short bits)
{
/*       opsu[];           pointer to unsorted raw options input      */
/*       opsc[];           ptr to 26 sorted character options         */
/*       opsi[];           ptr to 26 integer options                  */
/*       *opsp[];          ptr to 26 ptrs to option strings           */
/*       opsb[];           buffer for option strings                  */

char *opsbp;               /* ptr to current position in buffer        */
int i;                     /* index to the input raw option string     */
char c;                    /* current option letter being processed    */
int cp;                    /* index to the character array             */
int j,k;                   /* work indexes                             */
char temp[128];            /* temp w/s if hex a=^hexchars^             */

/*eject*/
/* 1st init the output arrays */
for (j=0; j < 26; j++)
   { opsc[j] = 0;             /* init the sorted result to blanks      */
     opsp[j] = (char *) 0;    /* init string ptrs to null              */
     opsi[j] = 0;             /* init integer array to zeros           */
   }
opsbp = opsb;                 /* init buffer ptr to 1st byte           */

/* bypass any leading '-' option identifier                            */
i = 0;                         /* init index to 1st char                */
if (opsu[i] == '-') i++;       /* bypass any leading '-'                */

/* begin loop to extract optn letters into opsc[] alpha sorted array   */
/*  & store any following optn prmtr/args into opsb[] array            */
while (opsu[i] > ' ')          /* until end string null/blank ?        */
  { c = opsu[i++];             /* save current option letter            */
    if (c < 'a' || c > 'z')
       { printf("sortops4 invalid at byte# %d %s \n",i,opsu);
         if (bits & 0x10)
             return(-1);
         else
             exit(-1);
       }
    cp = c - 'a';              /* index into sorted options array         */
    opsc[cp] = c;              /* store optn letter into sorted array     */

/* 1st store the data following the option letter into the string buffer*/
/* (will then convert any numeric digits from strings into integer optns*/
/*  following data of 2 types - numeric or nonnumeric                   */
/* numeric data - stored until nonnum or non '-' sign reached           */
/* nonnum data  - must have begin with '=' sep & end with ',' sep       */
/* - may be enclosed in quotes for char 'xx x' or circs for hex ^xxxx^  */
  if (((opsu[i] >= '0') && (opsu[i] <= '9')) || (opsu[i] == '-'))
    { opsp[c-'a'] = opsbp;               /* store ptr to 1st digit      */
      while (((opsu[i] >= '0') && (opsu[i] <= '9')) || (opsu[i] == '-'))
             *opsbp++ = opsu[i++];        /* store numeric digits       */
      *opsbp++ = (char) 0;               /* null terminate              */
    }

/*eject*/
/* non-num follows optn ltr - test for '=' sep & char string            */
  else if (opsu[i] == '=' && opsu[i+1] != '^')  /* =charstring ?         */
    { i++;                              /* bypass the '=' separator     */
      if (opsu[i] == '\'')              /* if enclosed in quotes ?      */
          i++;                          /* bypass opening quote         */
      opsp[c-'a'] = opsbp;              /* store ptr to 1st char string */
      while ( opsu[i] != ',' && opsu[i] != '\0')
          *opsbp++ = opsu[i++];          /* store a/n string char       */
      *opsbp++ = '\0';                  /* null terminate               */
   }

/* non-num follows optn ltr - test for '=^' sep & hex string             */
  else if (opsu[i] == '=' && opsu[i+1] == '^')  /* =charstring ?         */
    { opsp[c-'a'] = opsbp;              /* store ptr to 1st char string */
      i++; i++;                         /* bypass the leading '=^' sep  */
      j = 0;                            /* init index for temp w/s copy */
      while ( opsu[i] != ','&& opsu[i] != '^' && opsu[i] != '\0')
          temp[j++] = opsu[i++];        /* copy hex chars to temp w/s   */
      temp[j] = '\0';                   /* null terminate temp w/s      */
      k = hex2data(opsbp,temp,'~',64,1);
                                        /* cnvrt to true hex in buffer  */
      opsbp = opsbp + k;                /* incrmnt buf ptr by hex lth   */
      *opsbp++ = '\0';                  /* null term hex data in buffer */
   }

  /* end current option letter - bypass any trailing separators b4 next */
   while (opsu[i] == ','|| opsu[i] == '\'' || opsu[i] == '^')
          i++;                         /* bypass , & ^ seps b4 next op  */
 }
/* we have completed extraction of optn characters & strings            */
/* - now convert any numeric strings to integers                        */
for (k=0; k < 26; k++)
   if ((opsp[k]) && (opsp[k][0] >= '0') && (opsp[k][0] <= '9'))
       opsi[k] = atol2(opsp[k],'~',16,0x07);
return(1);
}

/*eject*/
/*uvhdcob----------------- toascii2 ---------------------------*/
/* convert a string from EBCDIC to ASCII                       */
/* arg1 - string to be translated                              */
/* arg2 - max length of string                                 */
/* arg3 - bit control codes                                    */
/*        0x01 - stop on NULL                                  */
/*        0x02 - terminate output string (if max with no null) */
/*        0x04 - convert non-printable EBCDIC chars to periods */
/* return -  length of string (or max count)                   */

/*Apr04/06 - changed 0x4B (EBCDIC period) to 0x5F (EBCDIC carat) */
/*Apr04/06 - dont like it change it back to period               */

int toascii2(Uchar *str, int max, short bits )
{
int ii;
for (ii=0; ii < max; ii++)
  { if ((str[ii] == '\0') & (bits & 0x01))
        break;
    if (((unsigned char)str[ii] < 0x40) && (bits & 0x04))
        str[ii] = 0x4B;    /*Apr04/06 change 0x4B to 0x5F & back */
    str[ii] = ebc2asc[(unsigned char)(str[ii])];
  }
if ((ii == max) && (bits & 0x02))
    str[max] = '\0';
return(ii);                            /* return lth of string  */
}

/*uvhdcob----------------- toebcdic2 ---------------------------*/
/* convert a string from ASCII to EBCDIC                       */
/* arg1 - string to be translated                              */
/* arg2 - max length of string                                 */
/* arg3 - bit control codes                                    */
/*        0x01 - stop on NULL                                  */
/*        0x02 - terminate output string (if max with no null) */
/* return -  length of string (or max count)                   */

int toebcdic2(Uchar *str, int max, short bits )
{
int ii;
for (ii=0; ii < max; ii++)
  { if ((str[ii] == '\0') & (bits & 0x01))
        break;
    str[ii] = asc2ebc[(unsigned char)(str[ii])];
  }
if ((ii == max) && (bits & 0x02))
    str[max] = '\0';
return(ii);                            /* return lth of string  */
}

/*eject*/
/*uvhdcob------------------ getline -----------------------------*/
/* get the next record from a file                               */
/* return the record size read or -1 if EOF or I/O error occurs  */
/* - return lth will be 1 higher than data lth if stopchar nofind*/
/*                                                               */
/* arg1 - the file pointer                                       */
/* arg2 - points to the 1st byte of data to be written           */
/* arg2 - the count to be written, or max if stops not found     */
/* arg4 - the stop character (usually a LineFeed)                */
/* arg5 - bitcodes to control procedures as follows              */
/*                                                               */
/*default - read the count specified (ignore NULLs, LFs,CRs)     */
/*        - dont convert any chars to blanks or NULLs            */
/*        - dont null terminate                                  */
/*                                                               */
/* stop read options - dflt stop on LF                           */
/* 0x0010 - bypass any LF's (use when stopchar is CR)            */
/* 0x0020 - stop reading when the stopchar (arg4) detected       */
/* 0x0040 - stop reading when a NULL is encountered              */
/* 0x0080 - n/u                                                  */
/*                                                               */
/* 0x0001 - convert CR's to blanks                               */
/* 0x0002 - convert LF's to blanks                               */
/* 0x0004 - convert NULL's to blanks                             */
/* 0x0008 - convert tabs to blanks (anywhere in record)          */
/*                                                               */
/* 0x0100 - remove any trailing blanks                           */
/* 0x0200 - terminate record with the stopchar (arg4)            */
/*          (stops read but is not put in data automatically)    */
/* 0x0400 - null terminate the record before returning           */
/*        - would follow the stopchar if 0x0200 on               */


int getlin0(FILE *fp, char *rec, int count, int stop, short bits)
{
int cc,ii,nn;

/*eject*/
/* stop read when max count reached if no stop chars spcfd (CR,LF,NULL) */
/*  if any stop char spcfd, read 1 extra byte                           */
/*  - if extra byte stop char - ok just return count requested          */
/*  - if extra byte not stop char return length count+1 to signal error */

ii = 0; nn = 0;
while (ii <= count)
   { cc = fgetc(fp);
     if (cc == EOF)
        return(-1);
     nn++;

     if ((bits & 0x0010) && (cc == '\n'))
         continue;

     if ((bits & 0x0020) && (cc == stop))
         break;
     if ((bits & 0x0040) && (cc == '\0'))
         break;

     if (((bits & 0x0060) == 0) && (nn == count))
         break;

     if ((bits & 0x0001) && (cc == '\r'))
         cc = ' ';
     if ((bits & 0x0002) && (cc == '\n'))
         cc = ' ';
     if ((bits & 0x0004) && (cc == '\0'))
         cc = ' ';
     if ((bits & 0x0008) && (cc == '\t'))
         cc = ' ';

     rec[ii++] = (char) cc;
   }

/*eject*/
/* remove trailing blanks or 0x00's if bitcode present                */
if (bits & 0x0100)
  { for (ii--; ii > 0; ii--)
      { if ((rec[ii] != ' ') && (rec[ii] != '\0'))
             break;
      }
    ii++;                    /* correct ii to byte after last data*/
  }

/* ensure we return at least 1 blank (EOF already checked above)   */
/* - converts lines with LF only to 1 blank (& LF maybe on output) */
/* - but only if stop-char is an LF                                */
/*   to allow copying binary files with alt stop chars             */
if ((ii == 0) && (stop == '\n'))
  { rec[ii++] = ' ';
  }

/* terminate with stopchar if indicated by bitcodes                */
if (bits & 0x0200)
    rec[ii++] = stop;

/* null terminate if indicated by bitcodes                         */
if (bits & 0x0400)
    rec[ii] = '\0';

return ii;
}

/*eject*/
/*uvhdcob------------------ getdatetime --------------------------*/
int getdatetime(void)
{
/* get system date & time & convert to "yyyymmdd_hhmm" format     */
tmsecs = time(0);              /* get time in secs since 1970     */
cnvdttm(today,tmsecs);         /* convert to "yyyymmddhhmm"       */
sncopy(date6,today+2,6,0x03);  /* create today in 6 digits yymmdd */
sncopy(time6,today+8,6,0x03);  /* create time in 6 digits hhmmss  */

return(1);
}

/*uvhdcob------------------ toprint ---------------------------*/
/* convert a string to printable characters                    */
/* - replace any unprintable characters with '.' periods       */
/* arg1 - string to be translated                              */
/* arg2 - max length of string                                 */
/* arg3 - translate table (allow ASCII or EBCDIC)              */
/* arg4 - bit control codes                                    */
/*        0x01 - stop on NULL                                  */
/*        0x02 - terminate output string (if max with no null) */
/*        0x04 - convert non-numeric chars to periods          */
/* return -  length of string (or max count)                   */

int toprint2(Uchar *str, int max, Uchar *trt, short bits)
{
int ii;
for (ii=0; ii < max; ii++)
  { if ((str[ii] == '\0') & (bits & 0x01))
      { break;
      }
    if (!(isdigit(str[ii])) && (bits & 0x04))
      { str[ii] = '.';
      }
    str[ii] = trt[(unsigned char)(str[ii])];  
  }
if ((ii == max) && (bits & 0x02))
  { str[max] = '\0';
  }
return(ii);                            /* return lth of string  */
}

/*eject*/
/*uvhdcob-------------------- data2hex -------------------------------*/
/* data2hex.c - function to convert data to hex representation        */
/*            - by Owen Townsend - ARC - aug 92                       */
/*Feb02/09 - add options to suppress trailing blanks (ASCII or EBCDIC)*/
/* - arg1 is the output data area (should be 2 times input length)    */
/* - arg2 is the input data (can be anything including nulls)         */
/* - arg3 is the length of the output area (2x input data)            */
/* - arg4 is bit codes modifying operation                            */
/*           bit 0x02 - null terminate the output area                */
/*           bit 0x04 - suppress trailing ASCII blanks                */
/*           bit 0x08 - suppress trailing EBCDIC blanks               */

void data2hex(char *out, char *in, int outlth, short bits)
{
int ii,jj;
unsigned int zz,dd;                       /* work areas for zone & digit */

for (ii=0,jj=0; jj < outlth; ii++,jj++,jj++)
  {
    zz = (unsigned int)(in[ii] >> 4);     /* shift zone to digit of w/s   */
    zz = zz & 0x0f;                       /* ensure zone bits clear       */
    if (zz < 10)                          /* if binary value 0 to 9       */
        out[jj] = (char)(zz + 0x30);      /* add 0x30 to get ascii value  */
    else                                  /* if binary value a to f       */
        out[jj] = (char)(zz + 0x37);      /* add 0x37 to get ascii value  */
                                          /* ex: 0x0a + 0x37 = 0x41 = 'A' */

    dd = (unsigned int)(in[ii] & 0x0f);   /* remove zone of digit rep     */
    if (dd < 10)                          /* if binary value 0 to 9       */
        out[jj+1] = (char)(dd + 0x30);    /* add 0x30 to get ascii value  */
    else                                  /* if binary value a to f       */
        out[jj+1] = (char)(dd + 0x37);    /* add 0x37 to get ascii value  */
                                          /* ex: 0x0a + 0x37 = 0x41 = 'A' */
  }

/*eject*/
/* test option to suppress trailing ASCII blanks */
if (bits & 0x04)
  { for (jj -= 2; jj > 3; jj -= 2)
     { if (memcmp(out+jj,"20",2) == 0)
         { memset(out+jj,' ',2);
         }
       else
         { jj += 2;
           break;
         }
     }
  }

/* test option to suppress trailing EBCDIC blanks */
if (bits & 0x08)
  { for (jj -= 2; jj > 3; jj -= 2)
     { if (memcmp(out+jj,"40",2) == 0)
         { memset(out+jj,' ',2);
         }
       else
         { jj += 2;
           break;
         }
     }
  }

if (bits & 0x02)
    out[jj] = '\0';                       /* null terminate the output    */
return;
}

/*eject*/
/*uvhdcob--------------------- uvedit ---------------------------------*/
/* edit function for the Vancouver Utilitity programs                  */
/*                                                                     */
/* arg1 - ptr to output area (result will be right justified in it)    */
/* arg2 - length of output area                                        */
/* arg3 - input value to be edited (a binary int)                     */
/* arg4 - ptr to edit mask                                             */
/*      - lth determined by 1st null or 1st blank                      */
/*      - will be rt justified in a work area same lth as output area  */
/*        & automatically left 'z' filled                              */
/* arg5 - control bits                                                 */
/*        0x02 - null terminate outarea in byte after spcfd arg1 length*/
/* return - the significant length of the edited output                */
/*        - output area lth less number of zero suppressed digits      */
/*sign handling:                                                       */
/*   non-leading '-' in mask will remain if value neg, else set blank  */
/*   non-leading '+' in mask will remain if value pos, else set '-'    */
/*       leading '-' or '+' will cause leading floating sign as above  */
/* Sep10/08 - change return no of non-blank chars in output area       */
/*          - add optn 0x01 to left adjust data in output area         */

int uvedit(char *out, int lth, int vals, char *mask, short bits)
{
int dd,ii,jj,kk,ll,nn,ss,zz;
int vala;                        /* data value absolute               */
char edw1[22];                    /* output work area                  */
char edw2[22];                    /* input digits rt adjusted in 0 fill*/
char edw3[22];                    /* edit mask rt adjusted in 'z' fill */
char sign;                        /* set '-' or '+' depending on vals  */
char fsign;                       /* float sign blank '-' or '+'       */

/* determine absolute value of input data & set sign indicator -/+     */
if (vals < 0) 
  { vala = vals * (-1);  
    sign = '-';
  }
else
  { vala = vals; 
    sign = '+';
  }

/* determine floating sign in case required later                     */
/* blank - if no leading -/+, or if leading '-', but value pos        */
/* '+'   - if leading '+' & value pos                                 */
/* '-'   - if leading '-/+' & value neg                               */
fsign = ' ';                    /* default float sign blank           */
if (mask[0] == '+')
  { fsign = sign;
  }
else if ((mask[0] == '-') && (sign == '-'))
  { fsign = '-';
  }

/*eject*/
/* initialize the output area to all zeros (will later zero suppress)  */
memset(edw1,'0',20);              /* zero fill the output area         */

/* convert to zoned numeric rt justified in 20 byte work area          */
sprintf(edw2,"%020d",vala);       /* convert binary absolute to zoned  */

/* determine length of edit mask - terminated by 1st blank or 1st null */
for (ll=0; ll < 20; ll++)
  { if ((mask[ll] == ' ') || (mask[ll] == '\0'))
        break;
  }

/* if leading '-' or '+' replace with 'z' now, later insert -/+/b      */
if ((mask[0] == '-') || (mask[0] == '+'))
  { edw3[ss] = 'z';
  }

/* right justify the edit mask in a 'z' filled 20 byte work area       */
memset(edw3,'z',20);
ss = 20 - ll;                        /* calc start byte in mask w/a    */
memcpy(&edw3[ss],mask,ll);           /* copy mask into work area       */

/*Dec10/08 - store dsplcmnt to last byte of edit mask */
/*         - will check for trailing +/- sign         */
dd = 19;

/* if leading '-' or '+' replace with 'z' now, later insert -/+/b      */
if ((mask[0] == '-') || (mask[0] == '+'))
  { edw3[ss] = 'z';
  }

/*Nov07/08 - if trailing '-', OK if value -, replace with blank if value+ */
if (edw3[dd] == '-')
  { if (vals >= 0)
      { edw3[dd] = ' ';  
      }
  }
/*Nov07/08 - if trailing '+', OK if value +, replace with '-' if value - */
/* if (edw3[kk] == '+')   <--Nov23/08 fixed bug 'kk' to 'dd' */
if (edw3[dd] == '+')
  { if (vals < 0)
      { edw3[dd] = '-';  
      }
  }

/*eject*/
/* now merge the data & any edit symbols into the zero filled output area*/
/* - if mask byte 9 or z, move input digit to output area current position*/
/*   else move the mask byte to the output area                          */
/* if mask '-' & value neg, set '-',  else set ' '                       */
/* if mask '+' & value neg, set '-',  else set '+'                       */
/* also save the zero suppress stop index - leftmost '9' or '.9' in mask */
/* set indices to rt hand byte of data,mask,& output areas               */
ii = 19; jj = 19; kk = 19;              /* set indices to right all areas*/
zz = 20;                                /* presume complete zero suppress*/
for ( ;ii > 0 && kk > 0; kk--)
  { if ((edw3[kk] == '9') || ((edw3[kk] == '.') && (edw3[kk+1] == '9')))
        zz = ii;                              /* save zup stop point     */
    if (edw3[kk] == '9' || edw3[kk] == 'z')
        edw1[ii--] = edw2[jj--];              /* move data to output area*/
    else
        edw1[ii--] = edw3[kk];                /* move mask edit to output*/
  }

/* now zero suppress - determined by index saved above or 1st sig digit  */
/* - blank out bytes until we reach the stop zup index or digit > 1 <= 9 */
for (ii=0,jj=0; ii < zz; ii++)
  { if (edw1[ii] >= '1' && edw1[ii] <= '9')
        break;
    edw1[ii] = ' ';
    jj = ii;
  }

/* insert leading floating sign determined & stored earlier             */
edw1[jj] = fsign;

/*Sep10/08 - correct index to 1st non-blank if sign blank */
if (edw1[jj] == ' ')
  { jj++;
  }

/*Sep10/08 - calc no of non-blank chars in dited output */
for (nn=0,ii=0; ii < 20; ii++)
  { if (edw1[ii] != ' ')
      { nn++;
      }
  }

/*eject*/
/* now move the result to the op1 output area                           */
/*Sep10/08 - test optn 0x01 to left adjust data in output area */
memset(out,' ',lth);                /* init out area to blanks */
if (bits & 0x01)
  { memcpy(out,&edw1[jj],nn);
  }
else
  { ss = 20 - lth;                      /* calc data start in work area  */
    memcpy(out,&edw1[ss],lth);
  }

/* test option to null terminate in byte after spcfd lth (arg2)         */
if (bits & 0x02)
   out[lth] = '\0';

return(nn);
}

/*eject*/
/*uvhdcob------------------------ uvfgets -----------------------------*/
/* uvfgets - UV version of fgets (assumes stdin) July 2003             */
/*         - converts any LineFeed to null (like gets being replaced)  */
/*         - returns the length of data entered (omitting LF)          */

int uvfgets(char *area, int max)
{
int ll;

memset(area,'\0',max);        /* init input area all nulls  */

fgets(area,max,stdin);

ll = strlen(area);

if ((ll > 0) && (area[ll-1] == '\n'))
  { area[ll-1] = '\0';
    ll--;
  }

return(ll);
}

/*eject*/
/*uvhd---------------------- putline ------------------------------*/
/* write a  record to a file                                       */
/* return the record size written or 0 if I/O error occurs         */
/*                                                                 */
/* arg1 - the file pointer                                         */
/* arg2 - points to the 1st byte of data to be written             */
/* arg3 - the count to be written or max if LF or null determined  */
/* arg4 - the stop-write-character (usually a LineFeed)            */
/* arg5 - bitcodes to control procedure as follows:                */
/*                                                                 */
/*default - write spcfd number of bytes (ignore NULLs,CRs,& LFs)   */
/*        - termination controlled by bitcodes & arg4 stop-char    */
/*                                                                 */
/* 0x0100 - remove any trailing blanks in the record (calc new rcsz)*/
/*                                                                 */
/* 0x0020 - stop writing on stop-character (arg4)                  */
/* 0x0040 - stop writing on NULL                                   */
/*                                                                 */
/*        - termination after max count written                    */
/* 0x0001 - write a CR after last data byte                        */
/* 0x0002 - write the stop-char (follows CR if 0x0001)             */
/* 0x0004 - write a NULL (follows CR & stopchar if indicated)      */

int putlin0(FILE *fp, char *rec, int count, int stop, short bits)
{
int ii,ll;

ll = count;                         /* presume count determines EOR */

/* 1st test for option to remove trailing blanks & adjust max count */
if (bits & 0x0100)
  { for (ll=count-1; ll > 0; ll--)
      { if (rec[ll] > ' ')
          { ll++;               /* include the last nonblank in count*/
            break;
          }
      }
    /* correct out lth for NULL records & force output to 1 blank    */
    /* - but only if stop-char is LineFeed                           */
    if ((ll == 0) && (stop == '\n'))
      { if (rec[ll] == '\0')
            rec[ll] = ' ';
        ll++;
      }
  }

/*eject*/
/* now write characters until any of following occurs:               */
/* - 1st CR   reached  & control bit present                         */
/* - 1st LF   reached  & control bit present                         */
/* - 1st NULL reached  & control bit present                         */
/* - max count (or last nonblank count) reached                      */
ii = 0;
while (ii < ll)
  { if ((bits & 0x0020) && (rec[ii] == stop))
        break;
    if ((bits & 0x0040) && (rec[ii] == '\0'))
        break;
    if (fputc(rec[ii++],fp) < 0)
        return(-1);                  /* return -1 if write err occurs*/
   }

/* append CR if indicated by bitcodes                               */
if (bits & 0x0001)
  { if (fputc('\r',fp) < 0)
        return(-1);                   /* return -1 if write err occurs*/
    ii++;
  }

/* append stop-char if indicated by bitcodes                        */
if (bits & 0x0002)
  { if (fputc(stop,fp) < 0)
        return(-1);                   /* return -1 if write err occurs*/
    ii++;
  }

/* append NULL if indicated by bitcodes                               */
if (bits & 0x0004)
  { if (fputc('\0',fp) < 0)
        return(-1);                   /* return -1 if write err occurs*/
    ii++;
  }

return(ii);                            /* return length written       */
}

/*eject*/
/*--------------------------- data2vhx -------------------------------*/
/* data2vhx.c - convert data to vertical hex representation           */
/*            - by Owen Townsend - ARC - aug 92                       */
/*  arg1 = output area for char data with unprntbl cnvrtd to periods  */
/*  arg2 = output data area for zones representation                  */
/*  arg3 = output data area for digits representation                 */
/*  arg4 = input data (can be anything including nulls)               */
/*  arg5 = length of input data to be converted                       */
/*  arg6 = address of EBCDIC to ASCII translate table                 */
/*  arg7 = control bits                                               */
/*         0x00 - does not terminate output areas                     */
/*         0x01 - null terminates output areas                        */
/*         0x02 - translate chars from EBCDIC to ASCII                */
/*                before converting any unprintables to periods       */
/*                                                                    */
/*Apr04/06 - change '.' to '^' to represent unprintable characters    */
/*Nov14/07 - change '^' back to '.'                                   */

void data2vhx(char *chars,char *zons,char *digs,char *data,int lth
               ,char *ebc2asc, short bits)
{
int ii;
intU zz,dd;

for (ii=0; ii < lth; ii++)
  {
    chars[ii] = data[ii];                   /* copy data to chars out     */
    if (bits & 0x02)                         /* translate EBCDIC to ASCII? */
        chars[ii] = ebc2asc[(Uchar)chars[ii]];   

    if (chars[ii] < ' ' || chars[ii] > '~') /* if unprintable ?       */
        chars[ii] = '.';                    /* - convert to carats    */

    zz = (intU)(data[ii] >> 4);             /* shift zone to digit of w/s   */
    zz = zz & 0x0f;                         /* ensure zone bits clear       */
    if (zz < 10)                            /* if binary value 0 to 9       */
        zons[ii] = (char)(zz + 0x30);       /* add 0x30 to get ascii value  */
    else                                    /* if binary value a to f       */
        zons[ii] = (char)(zz + 0x37);       /* add 0x37 to get ascii value  */
                                            /* ex: 0x0a + 0x37 = 0x41 = 'A' */

    dd = (intU)(data[ii] & 0x0f);           /* remove zone of digit rep     */
    if (dd < 10)                            /* if binary value 0 to 9       */
        digs[ii] = (char)(dd + 0x30);       /* add 0x30 to get ascii value  */
    else                                    /* if binary value a to f       */
        digs[ii] = (char)(dd + 0x37);       /* add 0x37 to get ascii value  */
                                            /* ex: 0x0a + 0x37 = 0x41 = 'A' */
  }
if (bits & 0x01)
  { chars[ii] = '\0';                       /* null terminate char data     */
    zons[ii] = '\0';                        /* null terminate zones         */
    digs[ii] = '\0';                        /* null terminate digits        */
  }
return;
}
/*--------------------------- end uvhdcob.c -------------------------*/

