Chead

From Pickwiki
Jump to navigationJump to search

Back to BasicSource

This is a QM-only utility to display information about compiled code. It can display the header information and the flags set in the header.

It can also show the local and common variables used, the line concordance, and a dump of the code using decimal or hexadecimal output, but these are not accurate if the DEBUGGING compile option was used.

It can also be used to display the opcodes QM uses (as at version 2.6).

     program chead
*
* To investigate QMBASIC object code. Version 1.0
*

     copyright = 'Copyright Keith Robert Johnson 2008'

*v This data is from the open source OPCODES.H - Version 2.6
* Simple opcodes
     opcodes = "STOP]ABORT]RETURN]JMP]JPO]JPZ]JNG]JZE"
     opcodes := "]JNZ]]GOSUB]RETURNTO]CALL]ONGOTO]ONGOSUB]RUN"
     opcodes := "]LDSINT]LDLINT]LDSTR]LDNULL]LDLCL]LDCOM]STOR]POP"
     opcodes := "]DUP]LDSLCL]LDSYS]LD0]LD1]NULL]EXCH]VALUE"
     opcodes := "]ADD]SUB]MUL]DIV]NEG]INT]INC]DEC"
     opcodes := "]MOD]PWR]ABS]REM]LN]EXP]REUSE]IDIV"
     opcodes := "]DSP]DSPNL]LDUNASS]AT]PROFF]PRON]PAGE]BREAKCT"
     opcodes := "]KEYRDY]KEYIN]PRINTERR]PROMPT]GETPROMPT]KEYINC]BREAK]LOCATE"
     opcodes := "]LEN]SUBSTR]SUBSTRE]CAT]REMOVE]CHAR]SEQ]EXTRACT"
     opcodes := "]REPLACE]INS]DEL]LOCATES]SPACE]STR]DNCASE]UPCASE"
     opcodes := "]RMVTKN]INSERT]FIELD]COL1]COL2]FLDSTOR]FMT]ICONV"
     opcodes := "]OCONV]SUBSTRA]TRIM]TRIMF]TRIMB]COUNT]DCOUNT]INDEX"
     opcodes := "]EQ]NE]GT]LT]NOT]AND]OR]BITAND"
     opcodes := "]BITOR]BITNOT]GE]LE]SHIFT]BITXOR]BITSET]BITRESET"
     opcodes := "]OPEN]READ]READV]WRITEV]DELETE]WRITE]CLOSE]QUOTIENT"
     opcodes := "]FORLOOPS][[FOR1S]]]KEYINR]OPENPATH]SYSDIR]KEYINT]KEYINCT]TRANS"
     opcodes := "]DIMLCL]DIMCOM]INDX1]INDX2]INMAT]INMATA]KEYINRT]MATCOPY"
     opcodes := "]MATFILL]MATPARSE]MATBUILD]DELCOM]MATREAD]GETREM]SETREM]COMMON"
     opcodes := "]STATUS]ONERROR]NOWAIT]SETMODE]CLRMODE]SETSTAT]SWAP]FOLD3"
     opcodes := "]FILEINFO]OSPATH]TIME]DATE]TIMEDATE]EXECUTE]]ITYPE"
     opcodes := "]ALPHA]NUM]APPEND]TRIMX]SOUNDEX]MATCHES]RAISE]LOWER"
     opcodes := "]SUM]CONVERT]FCONVERT]COMPARE]FLDSTORF]MATCHFLD]QUOTE]RMVF"
     opcodes := "]SELECT]CLEARSEL]CLEARALL]SLCTINFO]READNEXT]RDNXEXP]RDNXPOS]SSELECT"
     opcodes := "]FORMLIST]READLIST]SYSMSG]]]]JFALSE]JTRUE"
     opcodes := "]ACOS]ASIN]ATAN]COS]SIN]TAN]SQRT]RND"
     opcodes := "]LDFLOAT]REP]STZ]STNULL]LDSYSV]UNASS]BITTEST]PREFIX"
     opcodes := "]FORINIT]FORLOOP]FOR1]SLEEP]CLRFILE]QUIT]LOCK]UNLOCK"
     opcodes := "]RELEASE]RECLCKD]FILELOCK]FLUNLOCK]LOCKREC]RLSALL]GETLOCKS]FOLD"
     opcodes := "]SAVESCRN]RSTSCRN]TRACE]PRECISION]CHKCAT]CLEAR]CLRCOM]CHAIN"
     opcodes := "]ULOCK]LLOCK]MVD]MVDS]MVDSS]MVDSSS]ASS]MVDD"
     opcodes := "]CLRINPUT]HUSH]DATA]TESTLOCK]HEADING]FOOTING]PRNT]PRNL"
     opcodes := "]PSET]PRCLOSE]PRFILE]SH]DEBUG]DBGINF]DBGBRK]KERNEL"
     convert ']' to @vm in opcodes

* Extended opcodes
     excodes = "PABORT]NAP]TOTAL]IFS]SETNLS]GETNLS]ITYPE2]CALLV"
     excodes := "]ABORTMSG]PWCRYPT]LOGIN]UMASK]TERMINFO]KEYCODE]ERRMSG]VARTYPE"
     excodes := "]CROP]FIND]CHANGE]VSLICE]FINDSTR]SUBSTRNG]SWAPCASE]REPADD"
     excodes := "]REPSUB]REPMUL]REPDIV]REPCAT]MAXIMUM]MINIMUM]CHANGED]REPSUBST"
     excodes := "]DBGON]DBGOFF]UNLOAD]CAPTURE]PHANTOM]RTNLIST]SYSTEM]ABTCAUSE"
     excodes := "]LOGOUT]USERNO]ISSUBR]LISTCOM]DBGWATCH]EVENTS]DBGSET]PCONFIG"
     excodes := "]TTYGET]TTYSET]INPUTAT]INPUT]PRNAME]PRDISP]COMO]PTERM"
     excodes := "]HEADINGN]PRRESET]EBCDIC]ASCII]DTX]GETLIST]SAVELIST]GETPU"
     excodes := "]RDIV]SUMMATION]SEED]SETPU]OPTION]ENV]CONFIG]SENDMAIL"
     excodes := "]SQUOTE]DELLIST]SORTDATA]SELECTV]SELECTE]PASSLIST]BINDKEY]CHECKSUM"
     excodes := "]SEEK]READBLK]WRITEBLK]ANALYSE]CONFIGFL]FLUSH]CREATESQ]UNLK"
     excodes := "]UNLKFL]OSRENAME]GRPSTAT]SETTRIG]KEYCODET]KEYEDIT]KEYEXIT]KEYTRAP"
     excodes := "]OPENSEQ]READSEQ]WRITESEQ]WEOFSEQ]WRITESEQF]OPENSEQP]CREATEAK]AKRELEASE"
     excodes := "]AKWRITE]AKREAD]AKDELETE]DELETEAK]SELINDX]SELINDXV]AKCLEAR]AKENABLE"
     excodes := "]CREATEDH]CREATET1]MAPMARKS]SELLEFT]SELRIGHT]SETLEFT]SETRIGHT]INDICES1"
     excodes := "]INDICES2]TXNBGN]TXNCMT]TXNEND]TXNRBK]OSERROR]NOBUF]XTD"
     excodes := "]BTINIT]BTADD]BTSCAN]BTRESET]BTADDA]BTMODIFY]BTFIND]BTSCANA"
     excodes := "]LOADOBJ]LOADED]SPLICE]PACKAGE]LOCATEF]LISTINDX]MIN]MAX"
     excodes := "]SORTINIT]SORTADD]SORTNEXT]SORTCLR]RLSFILE]DIR]PMATRIX]DIMLCLP"
     excodes := "]LOGMSG]SHCAP]PROCREAD]DEREF]IADD]ISUB]IMUL]SCALE"
     excodes := "]READPKT]WRITEPKT]CHGPHANT]ONGOTOP]ONGOSUBP]READONLY]PICKREAD]STORSYS"
     excodes := "]SUBST]PSUBSTRA]SAVEADDR]COMPREP]COMPINS]COMPINSRT]COMPREPLC]FCONTROL"
     excodes := "]GETPORT]SETPORT]CCALL]ENTER]SETFLAGS]GETMSG]CSVDQ]OJOIN"
     excodes := "]EXPANDHF]LOCAL]DELLCL]AKMAP]SRVRADDR]OBJECT]OBJMAP]OBJREF"
     excodes := "]OPENSKT]CLOSESKT]READSKT]WRITESKT]SRVRSKT]ACCPTSKT]SKTINFO]SETSKT"
     excodes := "]FORMCSV]ISMV]SETUNASS]TIMEOUT]IN]ME]GET]SET"
     excodes := "]ARGCT]ARG]RTRANS]PAUSE]WAKE]PSUBSTRB]DELSEQ]CNCTPORT"
     excodes := "]LGNPORT]OBJINFO]INHERIT]DISINH]CREATESH]LDLSTR]RDNXINT]ENCRYPT"
     excodes := "]DECRYPT]CRYPT]INPUTBLK]NEGS]ABSS]LENS]SPACES]TRIMS"
     excodes := "]TRIMFS]TRIMBS]NOTS]NUMS]SOUNDEXS]STRS]FMTS]ICONVS"
     excodes := "]OCONVS]COUNTS]FOLDS]INDEXS]FOLDS3]TRIMXS]FIELDS]MODS"
     excodes := "]CATS]EQS]NES]GTS]LTS]ANDS]ORS]GES"
     excodes := "]LES"
     convert ']' to @vm in excodes

* Extended opcode values
     values = "52992]52993]52994]52995]52996]52997]52998]52999"
     values := "]53000]53001]53002]53003]53004]53005]53006]53007"
     values := "]53008]53009]53010]53011]53012]53013]53014]53015"
     values := "]53016]53017]53018]53019]53020]53021]53022]53023"
     values := "]53024]53025]53026]53027]53028]53029]53030]53031"
     values := "]53032]53033]53034]53035]53036]53037]53038]53039"
     values := "]53040]53041]53042]53043]53044]53045]53046]53047"
     values := "]53048]53049]53050]53051]53052]53053]53054]53055"
     values := "]53056]53057]53058]53059]53060]53061]53062]53063"
     values := "]53064]53065]53066]53067]53068]53069]53070]53071"
     values := "]53072]53073]53074]53075]53076]53077]53078]53079"
     values := "]53080]53081]53082]53083]53084]53085]53086]53087"
     values := "]53088]53089]53090]53091]53092]53093]53094]53095"
     values := "]53096]53097]53098]53099]53100]53101]53102]53103"
     values := "]53104]53105]53106]53107]53108]53109]53110]53111"
     values := "]53112]53113]53114]53115]53116]53117]53118]53119"
     values := "]53120]53121]53122]53123]53124]53125]53126]53127"
     values := "]53128]53129]53130]53131]53132]53133]53134]53135"
     values := "]53136]53137]53138]53139]53140]53141]53142]53143"
     values := "]53144]53145]53146]53147]53148]53149]53150]53151"
     values := "]53152]53153]53154]53155]53156]53157]53158]53159"
     values := "]53160]53161]53162]53163]53164]53165]53166]53167"
     values := "]53168]53169]53170]53171]53172]53173]53174]53175"
     values := "]53176]53177]53178]53179]53180]53181]53182]53183"
     values := "]53184]53185]53186]53187]53188]53189]53190]53191"
     values := "]53192]53193]53194]53195]53196]53197]53198]53199"
     values := "]53200]53201]53202]53203]53204]53205]53206]53207"
     values := "]53208]53209]53210]53211]53212]53213]53214]53215"
     values := "]53216]53217]53218]59940]59946]59968]59980]59994"
     values := "]59995]59996]60004]60065]60068]60237]60246]60247"
     values := "]60248]60253]60383]60511]60567]60579]60754]61224"
     values := "]61251]61280]61281]61282]61283]61285]61286]61290"
     values := "]61291"
     convert ']' to @vm in values

* Simple and extended opcode modes
     smodes = "AAABBBBBB.BBCMMACDFAEHAAANCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAC.AAAAAAAAAAAAAAAAAAAAAAAAAAAC...BBAAAAAAAAGAAACAAKABBAAAAAAAAAAAAAAAAAAAAAAALLLLALAAAAAAAAAAAAJAAA"
     xmodes = "AACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAMMAAAAAAAAAAAAAAAPAAAAQEAACRCAAAAAAAAAAAAAACCAAAAAAAAAAAAASAAAAA............................."

*^ End of data derived from OPCODES.H

* Parse the command line
     comd = @sentence
     comd = trim(comd)
     convert ' ' to @am in comd
     loop
        this = comd<1>
        del comd<1>
     until upcase(this) eq 'CHEAD' or comd eq '' do
     repeat

* Help
     if comd<2> eq '' then
        crt
        crt 'Program to display information about compiled code.'
        crt '---------------------------------------------------'
        crt 'syntax: [RUN file] CHEAD FILE ITEM'
        crt
        crt 'This program will display information about'
        crt 'the object code and about QMBASIC opcodes.'
        crt
        crt 'The output can be printed using P toggle.'
        crt
        crt 'NOTE: Incorrect if DEBUGGING option used.'
        crt
        stop
     end

     namf = comd<1>
     name = comd<2>

* Get the source code if possible
     if namf[4] eq '.OUT' then namf = namf[1,len(namf)-4]
     sourcode = ''
     open namf to srs.file then
        read sourcode from srs.file,name else null
     end


* Get the object code
     namf = namf:'.OUT'
     open namf to obj.file else
        crt 'Cannot open object file ':namf
        stop
     end

     read this from obj.file,name else
        crt 'Cannot read object code ':name
        stop
     end
* Calculate the object size from the header information
* NOTE: LEN(THIS) is too short for big programs!
     blen = oconv(this[25,4],'IL')

* The standard read converts char(10) to attribute marks
* Get item with a block sequential read to avoid this
     openseq namf,name to code then
        readblk this from code,blen else null
        closeseq code
     end
     crt

* Get the header
     lenh = 164
     head = this[1,lenh]
     begn = lenh+2

* Get the various variables we are interested in
     nolocvar = oconv(head[13,2],'IS')
     nosubarg = oconv(head[11,2],'IS')
     symtabof = oconv(head[17,4],'IL')
     lcordoff = oconv(head[21,4],'IL')
     code.len = oconv(head[25,4],'IL')
     hdrflags = oconv(head[29,2],'IS')
     compiled = oconv(head[31,4],'IL')
     d = int(compiled/86400)
     t = rem(compiled,86400)
     compiled = oconv(d,'D'):' ':oconv(t,'MTS')

* Change for later version
     vers = seq(this[2,1])
     if vers > 0 and symtabof then
        lcordoff = symtabof + 4
        symtabof += oconv(this[symtabof+2,2],'is')+4
     end

* Some more for thoroughness
     hdroffst = oconv(head[7,4],'IL')
     stakdeep = oconv(head[15,2],'IS')
     headrefs = oconv(head[35,2],'IS')
     progname = head[37,128]
     progname = trim(progname)
     progname = trim(progname,char(0))

* Get the symbol table
     symtable = ''
     if symtabof then symtable = this[symtabof+1,blen]
     symtable = trim(symtable,char(1),'T')

* Get the line table
     lintable = ''
     if lcordoff then
        if symtabof
           then lintable = this[lcordoff+2,symtabof-lcordoff-1]
           else lintable = this[lcordoff+2,blen]
     end

     loclvars = ''
     commvars = ''
     commnumb = ''
     if symtable ne '' then
        loclvars = trim(symtable<1>,@vm,'T')
        commvars = symtable
        del commvars<1>
        xxno = dcount(commvars,@am)
        for xx = 1 to xxno
           commnumb<-1> = commvars<xx,1>+1
        next xx
     end

* Get the code
     begin case
        case lcordoff
           this = this[begn,lcordoff-lenh-1]
        case symtabof
           this = this[begn,symtabof-lenh-1]
        case 1
           this = this[begn,blen]
     end case


* Present the user with a menu
     prompt ''
     pout = @false
     plen = system(3) - 1
     loop
        crt @(-1),namf,name
        crt
        crt '  H - Header information'
        crt '  F - Flags set in header'
        crt '  V - Variables (local)'
        crt '  C - Common variables'
        crt '  L - Line concordance'
        crt '  O - Opcodes'
        crt '  E - Extended opcodes'
        crt '  D - Dump of code'
        crt '  X - heXadecimal code dump'
        crt
        if pout
           then crt '  P - Print output now ON  turn OFF'
           else crt '  P - Print output now OFF turn ON'
        crt
        crt '  Q - Quit'
        crt
        loop
           crt @(0):@(-3):
* You can take the boy out of Mangere...
           if rnd(20)
              then crt '  Press choice key :':
              else crt '  Cuzzy Bro - Press [[C_H_O_I_C_E]] key, eh?':
           answ = upcase(keycode())
        until answ ne '' and index('DXVCLHFPQOE',answ,1) do repeat
        crt
        if answ eq 'D' then gosub show.code
        if answ eq 'X' then gosub show.code
        if answ eq 'V' then gosub show.local
        if answ eq 'C' then gosub show.common
        if answ eq 'L' then gosub show.lines
        if answ eq 'H' then gosub show.header
        if answ eq 'F' then gosub show.flags
        if answ eq 'P' then pout = not(pout)
        if answ eq 'O' then gosub show.opcodes
        if answ eq 'E' then gosub show.extended.opcodes
     until answ eq 'Q' do repeat
     crt
     stop

************************ SUBROUTINES ********************************
show.code:
     if answ eq 'D' then decm = @true else decm = @false
     if this eq ''
        then disp = 'THERE IS NO CODE TO SHOW'
        else disp = 'DUMP OF CODE':@am
     cntr = 0
     size = 16
     loop
        part = this[cntr+1,size]
     until part eq '' do
        line = cntr 'R%4':':'
        for xx = 1 to size
           bite = part[xx,1]
           if bite = '' then
              bite = '   '
           end else
              if decm
                 then bite = seq(bite) 'R#3'
                 else bite = ' ':(dtx(seq(bite)) 'R%2')
           end
           line := bite
        next xx
        line := ' - ':oconv(part,'MCP')
        disp<-1> = line
        cntr += size
     repeat
     gosub display
     return


show.local:
     disp = '      Local Variables':@am
     xxno = dcount(loclvars,@vm)
     for xx = 1 to xxno
        varb = loclvars<1,xx>
        void = space(14-rem(len(varb),10))
        locate(xx,commnumb;posn) then
           if varb = '$'
              then varb := void:'******* common block *******'
              else varb := void:'****** labelled common ******'
        end
        begin case
           case varb matches '"__"1[[N0X]]'
              varb := void:'***** Temporary Variable ****'
           case varb[1,2] eq '__'
              varb := void:'******* FILE Variable *******'
           case varb[1,1] eq '_'
              varb := void:'***** Call to Subroutine ****'
           case varb[1,1] eq '~'
              varb := void:'******** Object code ********'
           case varb[1,1] eq '*'
              varb := void:'****** Object Argument ******'
        end case
        disp<-1> = xx 'R#5':' ':varb
     next xx
     if loclvars eq '' then disp = 'THERE IS NO VARIABLE INFORMATION'
     gosub display
     return


show.common:
     disp = 'COMMON BLOCK DISPLAY':@am
     xxno = dcount(commvars,@am)
     for xx = 1 to xxno
        line = commvars<xx>
        comm = line<1,1>
        del line<1,1>
        comm += 1
        comm = loclvars<1,comm>
        if comm = '$'
           then disp<-1> = '  Common Block'
           else disp<-1> = '  ':comm:' - Labelled common'
        yyno = dcount(line,@sm)
        for yy = 1 to yyno
           disp<-1> = yy 'R#5':' ':line<1,1,yy>
        next yy
        if xx ne xxno then disp<-1> = ' '
     next xx
     if commvars eq '' then disp = 'THERE ARE NO COMMON BLOCKS, OR THERE IS NO INFORMATION'
     gosub display
     return


show.lines:
     disp = 'LINE CONCORDANCE TABLE'
     disp<-1> = ' Line# Length of object in line'
     xx = 0
     line = 0
     loop
        xx += 1
        part = lintable[xx,1]
     until part eq '' do
        seqn = seq(part)
        if seqn = 255 then
           xx += 1 ; seqn = seq(lintable[xx,1])
           xx += 1 ; seqn += seq(lintable[xx,1])*256
        end
        line += 1
        if seqn then disp<-1> =  line 'R#6':' ':seqn
     repeat
     if lintable eq '' then disp = 'THERE IS NO LINE INFORMATION'
     gosub display
     return


show.header:
     disp = 'HEADER INFORMATION - ':progname:@am
     disp<-1> = 'Endian hint' 'R#35':' ': seq(head[1,1])
     disp<-1> = 'Header Revision' 'R#35':' ': seq(head[2,1])
     disp<-1> = 'Header Offset' 'R#35':' ': hdroffst
     disp<-1> = 'Number of local variables' 'R#35':' ': nolocvar
     disp<-1> = 'Number of subroutine arguments' 'R#35':' ': nosubarg
     disp<-1> = 'Stack Depth' 'R#35':' ': stakdeep
     disp<-1> = 'Symbol table offset' 'R#35':' ': symtabof
     disp<-1> = 'Line concordance offset' 'R#35':' ': lcordoff
     disp<-1> = 'Line concordance table size' 'R#35':' ': len(lintable)
     disp<-1> = 'Object size' 'R#35':' ': code.len
     disp<-1> = 'Code size' 'R#35':' ': len(this)
     disp<-1> = 'When compiled' 'R#35':' ': compiled
     disp<-1> = 'Header References' 'R#35':' ': headrefs
     gosub display
     return


show.flags:
     disp = 'FLAG INFORMATION':@am
     disp<-1> = 'Command processor' 'R#35':' ':  bittest(hdrflags,0)
     disp<-1> = 'Internal mode program' 'R#35':' ':  bittest(hdrflags,1)
     disp<-1> = 'Compiled in debug mode' 'R#35':' ':  bittest(hdrflags,2)
     disp<-1> = 'Debugger' 'R#35':' ':  bittest(hdrflags,3)
     disp<-1> = 'Case insensitive string operations' 'R#35':' ':  bittest(hdrflags,4)
     disp<-1> = 'Basic function' 'R#35':' ':  bittest(hdrflags,5)
     disp<-1> = 'Variable arg count (hdr.args = max)' 'R#35':' ':  bittest(hdrflags,6)
     disp<-1> = 'Is a recursive program' 'R#35':' ':  bittest(hdrflags,7)
     disp<-1> = 'Is an A[[/S/C/I]]-type' 'R#35':' ':  bittest(hdrflags,8)
     disp<-1> = 'Allow break in recursive' 'R#35':' ':  bittest(hdrflags,9)
     disp<-1> = 'Trusted program' 'R#35':' ':  bittest(hdrflags,10)
     disp<-1> = 'Allow remote files by NFS' 'R#35':' ':  bittest(hdrflags,11)
     disp<-1> = 'Program uses case sensitive names' 'R#35':' ':  bittest(hdrflags,12)
     disp<-1> = 'Can be called using QMCall()' 'R#35':' ':  bittest(hdrflags,13)
     disp<-1> = 'Is a C-type' 'R#35':' ':  bittest(hdrflags,14)
     disp<-1> = 'Is CLASS module' 'R#35':' ':  bittest(hdrflags,15)
     gosub display
     return


show.opcodes:
     disp = 'Simple OPCODES':@am
     xxno = dcount(opcodes,@vm)
     for xx = 1 to xxno
        numb = xx-1
        hexn = dtx(numb) 'R%2'
        mode = smodes[xx,1]
        gosub get.mode.show
        disp<-1> = numb 'R#5':'   ':hexn:' ':opcodes<1,xx> 'l#10':show
     next xx
     if opcodes eq '' then disp = 'THERE ARE NO SIMPLE OPCODES'
     gosub display
     return


show.extended.opcodes:
     disp = 'Extended OPCODES':@am
     xxno = dcount(excodes,@vm)
     for xx = 1 to xxno
        numb = values<1,xx>
        hexn = dtx(numb) 'R%4'
        mode = xmodes[xx,1]
        gosub get.mode.show
        line = numb:' ':hexn:' ':excodes<1,xx> 'L#10':show
        disp<-1> =  line
     next xx
     if excodes eq '' then disp = 'THERE ARE NO EXTENDED OPCODES'
     gosub display
     return


get.mode.show:
     begin case
        case mode eq 'A' ; show = 'Opcode Byte' ; show = '' ; * Tidier
        case mode eq 'B' ; show = 'Jump Address'
        case mode eq 'C' ; show = 'One Byte Value'
        case mode eq 'D' ; show = 'Four Byte Value'
        case mode eq 'E' ; show = 'Local Variable'
        case mode eq 'F' ; show = 'String Value'
        case mode eq 'G' ; show = 'Float Value'
        case mode eq 'H' ; show = 'Common Variable'
        case mode eq 'I' ; show = 'Common Dcl'
        case mode eq 'J' ; show = 'Debug Reference'
        case mode eq 'K' ; show = 'Opcode Prefix'
        case mode eq 'L' ; show = 'Multivalue Opcode'
        case mode eq 'M' ; show = 'Address List'
        case mode eq 'N' ; show = 'Short Local'
        case mode eq 'O' ; show = 'Pmatdata'
        case mode eq 'P' ; show = 'Two Byte Value'
        case mode eq 'Q' ; show = 'Local Dcl'
        case mode eq 'R' ; show = 'Object Map Data'
        case mode eq 'S' ; show = 'Long String Value'
        case 1 ; show = ''
     end case
     return


display:
     xxno = dcount(disp,@am)
     if pout and xxno gt 1 then gosub print.output ; return

     pags = int(xxno/plen)
     last = pags * plen
     pags += (rem(xxno,plen) ne 0)
     dawn = 1
     loop
        dusk = dawn + plen - 1
        for here = dawn to dusk
           crt disp<here>
        next here
        begin case
           case xxno le plen
              crt 'Press any key to retun to menu ':
              wait = upcase(keycode())
              return
           case here gt last
              crt 'Press any key to return to menu or <T>op <P>revious ':
              wait = upcase(keycode())
              if wait ne 'T' and wait ne 'P' then return
           case dusk le plen
              crt 'Press any key to continue or <Q> to return to menu ':
              wait = upcase(keycode())
              if wait eq 'T' or wait eq 'P' then wait = 'C'
           case 1
              crt 'Press any key to continue or <T>op <P>revious <Q>uit to return to menu ':
              wait = upcase(keycode())
        end case
        begin case
           case wait eq 'T' ; dawn = 1
           case wait eq 'P' ; dawn -= plen
           case 1           ; dawn += plen
        end case
        crt
     until dawn gt xxno or wait eq 'Q' do repeat
     return


print.output:
     crt
     crt disp<1>
     loop
        crt 'ARE YOU SURE YOU WANT TO PRINT?':
        answ = upcase(keycode())
     until answ eq 'Y' or answ eq 'N' do
        crt 'Please answer "Y" or "N"'
     repeat
     if answ eq 'Y' then
        printer on
        print 'Details for ':name:' in ':namf
        print
        for xx = 1 to xxno
           print disp<xx>
        next xx
        printer off
     end
     return

  end