home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / JSAGE / ZSUS / WORDPACK / ROMAN03A.LBR / ROMAN03A.MZC / ROMAN03A.MAC
Text File  |  1990-04-06  |  9KB  |  358 lines

  1. ; ROMAN.MAC
  2. ;
  3. ; Converts decimal numbers to Roman numerals.
  4. ;
  5. Vers    equ    03
  6. SubVers    equ    'a'
  7. ;
  8. ; Version 0.3a -- April 7, 1990 -- Gene Pizzetta
  9. ;    Fixed minor bug, discovered by Howard Goldstein, that caused
  10. ;    strange behavior if a character less than '0' was entered.
  11. ;
  12. ; Version 0.3 -- April 1, 1990 -- Gene Pizzetta
  13. ;    Converted to ZCPR3 utility.  Extensively modified screen displays.
  14. ;    Added command line mode and usage message.
  15. ;
  16. ; Version 0.2a -- February 13, 1983 -- D. McLanahan, Marlow, NH
  17. ;    Modified for CP/M.
  18. ;
  19. ; Version 0.2 -- October 10, 1978 -- M. Pedder
  20. ;    From SIG/M disk volume 75
  21. ;
  22. ; Original code copyright (c) 1978 M. Pedder.
  23. ;
  24. ; Definitions . . .
  25. ;
  26. WBoot    equ    00h        ; warm boot
  27. Bdos    equ    05h        ; BDOS entry
  28. DmaBuf    equ    80h        ; default DMA buffer
  29. ;
  30. CtrlC    equ    03h
  31. CR    equ    0Dh
  32. LF    equ    0Ah
  33. ;
  34.     MACLIB    Z80
  35. ;
  36.     ext    z3init,gzmtop,getefcb,cin,cout,epstr,phl4hc
  37. ;
  38. ; TYP3HDR.MAC, Version 1.1  --  Extended Intel Mnemonics
  39. ;    This code has been modified as suggested by Charles Irvine so that
  40. ;    it will function correctly with interrupts enabled.
  41. ; Extended Intel mnemonics by Gene Pizzetta, April 30, 1989.
  42. ;
  43. ; This is header code that can be used at the beginning of a type-3-environment
  44. ; program so that it will abort with an error message when not loaded to the
  45. ; correct address (such as when a user tries to run it under CP/M or Z30).
  46. ;
  47. Entry:    jr    start0        ; Must use relative jump
  48.     db    0        ; Filler
  49.     db    'Z3ENV',3    ; Type-3 environment
  50. Z3EAdr:    dw    0        ; Filled in by Z33
  51.     dw    entry        ; Intended load address
  52. ;
  53. start0:    lxi    h,0        ; Point to warmboot entry
  54.     mov    a,m        ; Save the byte there
  55.     di            ; Protect against interrupts
  56.     mvi    m,0c9h        ; Replace warmboot with a return opcode
  57.     rst    0        ; Call address 0, pushing RETADDR onto stack
  58. retaddr:
  59.     mov    m,a        ; Restore byte at 0
  60.     dcx    sp        ; Get stack pointer to point
  61.     dcx    sp        ; ..to the value of RETADDR
  62.     pop    h        ; Get it into HL and restore stack
  63.     ei            ; We can allow interrupts again
  64.     lxi    d,retaddr    ; This is where we should be
  65.     xra    a        ; Clear carry flag
  66.     push    h        ; Save address again
  67.     dsbc    de        ; Subtract -- we should have 0 now
  68.     pop    h        ; Restore value of RETADDR
  69.     jz    Start        ; If addresses matched, begin real code
  70. ;
  71.     lxi    d,notz33msg-retaddr ; Offset to message
  72.     dad    d
  73.     xchg            ; Switch pointer to message into DE
  74.     mvi    c,9
  75.     jmp    0005h        ; Return via BDOS print string function
  76. ;
  77. notz33msg:
  78.     db    'Not Z33+$'    ; Abort message if not Z33-compatible
  79. ;
  80. ; Messages . . .
  81. ;
  82. MsgSOn:    db    'ROMAN   Version '
  83.     db    Vers/10+'0','.',Vers mod 10+'0',SubVers
  84.     db    '  (loaded at ',0
  85. MsgSO1:    db    'h)',CR,LF,0
  86. MsgUse:    db    'Converts decimal numbers to Roman numerals.',CR,LF
  87.     db    'Syntax:',CR,LF,'   ',0
  88. MsgNam:    db    'ROMAN',0
  89. MsgUs1:    db    ' {decimal number}',CR,LF
  90.     db    'Decimal number may be from 1-3999.  If no number',CR,LF
  91.     db    'is given, ROMAN will enter interactive mode.',0
  92. MsgInf:    db    CR,LF,'Enter number (1-3999).  ^C to exit.',CR,LF,0
  93. MsgSpc:    db    '     ',0
  94. MsgPpt:    db    CR,LF,'>> ',0
  95. Msg2Lg:    db    '  Too Large!',0
  96. MsgInv:    db    '  Invalid character!',0
  97. RomNum:    db    0,0,'IVXLCDM'
  98. ;
  99. ; Start of program . . .
  100. ;
  101. Start:    lhld    Z3EAdr        ; set up environment
  102.     call    Z3init
  103.     sspd    OldStk        ; save old stack pointer
  104.     call    gzmtop        ; get top of memory
  105.     sphl            ; ..and set new stack
  106.     lxi    d,DmaBuf    ; see if there's a command tail
  107.     ldax    d
  108.     ora    a
  109.     jrz    NoTail
  110.     inx    d
  111.     call    EatSpc
  112.     ani    7Fh        ; strip parity bit
  113.     cpi    0
  114.     jrz    NoTail
  115.     cpi    '/'        ; request for help?
  116.     jz    Help        ; (yes)
  117.     lxi    h,MsgSpc    ; space over
  118.     call    epstr
  119.     lxi    b,DecBuf    ; point to decimal buffer
  120.     lxi    h,DecCnt    ; point to decimal counter
  121.     mvi    m,0        ; zero counter
  122. GetCLp:    cpi    ' '
  123.     jrz    GetCL1
  124.     cpi    0
  125.     jrz    GetCL1
  126.     call    Echo        ; check and echo each character
  127.     jp    Exit
  128.     inx    d
  129.     ldax    d
  130.     jr    GetCLp
  131. ;
  132. GetCL1:    mvi    a,' '        ; print space, equal, space
  133.     call    cout
  134.     mvi    a,'='
  135.     call    cout
  136.     mvi    a,' '
  137.     call    cout
  138.     mvi    a,0        ; mark end of string
  139.     stax    b
  140.     call    Encode        ; output Roman
  141.     jmp    Exit
  142. ;
  143. NoTail:    lxi    h,MsgSOn    ; print sign-on message
  144.     call    epstr
  145.     lxi    h,Entry        ; print load address
  146.     call    phl4hc
  147.     lxi    h,MsgSO1
  148.     call    epstr
  149.     lxi    h,MsgInf    ; print interactive instructions
  150.     call    epstr
  151. Ready:    call    PrtPpt        ; print prompt
  152.     call    Input        ; get number from keyboard
  153.     jrc    Ready
  154.     call    Encode        ; encode and output it
  155.     jr    Ready
  156. ;
  157. ; PrtPpt -- set up and print interactive prompt
  158. ;
  159. PrtPpt:    lxi    h,MsgPpt    ; print prompt
  160.     call    epstr
  161.     lxi    b,DecBuf    ; point to decimal buffer
  162.     lxi    h,DecCnt    ; point to counter
  163.     mvi    m,0        ; clear counter
  164.     ret
  165. ;
  166. ; Input -- get input from console into DecBuf, checking validity
  167. ;
  168. Input:    call    cin
  169.     ani    7Fh        ; strip parity bit
  170.     cpi    CtrlC        ; abort?
  171.     jrz    Exit        ; (yes)
  172.     cpi    CR        ; is it a carriage return?
  173.     cnz    Echo        ; (no, echo it to screen)
  174.     jm    Input        ; (continue)
  175.     rc            ; (error)
  176.     mvi    a,' '        ; print a space, equal, space
  177.     call    cout
  178.     mvi    a,'='
  179.     call    cout
  180.     mvi    a,' '
  181.     call    cout
  182.     mvi    a,0        ; mark end of string
  183.     stax    b
  184.     ora    a        ; and clear flag
  185.     ret
  186. ;
  187. Exit:    lspd    OldStk        ; restore old stack pointer
  188.     ret
  189. ;
  190. ; Help -- print help message and exit
  191. ;
  192. Help:    lxi    h,MsgSOn    ; print sign-on
  193.     call    epstr
  194.     lxi    h,Entry        ; print load address
  195.     call    phl4hc
  196.     lxi    h,MsgSO1
  197.     call    epstr
  198.     lxi    h,MsgUse    ; print usage
  199.     call    epstr
  200.     call    getefcb        ; get program name
  201.     jrz    NoEFcb        ; (no external fcb)
  202.     mvi    b,8
  203. CNamLp:    inx    hl
  204.     mov    a,m
  205.     ani    7Fh
  206.     cpi    ' '
  207.     cnz    cout
  208.     djnz    CNamLp
  209.     jr    Help2
  210. ;
  211. NoEFcb:    lxi    h,MsgNam
  212.     call    epstr
  213. Help2:    lxi    h,MsgUs1
  214.     call    epstr
  215.     jr    Exit
  216. ;
  217. Echo:    call    cout        ; echo character
  218.     cpi    '0'        ; is it zero or more?
  219.     jm    InvChr        ; (no)
  220.     cpi    ':'        ; is it nine or less?
  221.     jp    InvChr        ; (no)
  222.     inr    m        ; count it
  223.     stax    b        ; store it
  224.     inx    b        ; advance pointer
  225.     mov    a,m        ; check count
  226.     cpi    5        ; is it less than 5
  227.     rm            ; (yes)
  228.     lxi    h,Msg2Lg    ; print "too large"
  229.     jr    OutMsg
  230. ;
  231. InvChr:    lxi    h,MsgInv    ; print "invalid character"
  232. OutMsg:    call    epstr
  233.     ora    a        ; reset sign flag
  234.     stc            ; set error flag
  235.     ret
  236. ;
  237. ; Encode -- encodes numbers and then outputs Roman numerals
  238. ;
  239. Encode:    lxi    b,DecBuf    ; point to decimal buffer
  240.     lxi    d,RomNum    ; point to Roman numerals
  241.     lxi    h,DecCnt    ; point to decimal counter
  242.     mov    a,m        ; check count
  243.     cpi    4        ; is it 4?
  244.     jrnz    Cont        ; (no, continue)
  245.     ldax    b        ; get first character
  246.     cpi    '4'        ; is it a "4"?
  247.     jm    Cont        ; (no, continue)
  248.     lxi    h,Msg2Lg    ; print "too large"
  249.     call    epstr
  250.     ret
  251. ;
  252. Cont:    mov    l,m        ; get count to HL
  253.     mvi    h,0
  254.     dad    h        ; double it
  255.     dad    d        ; add to list
  256.     xchg            ; and restore list
  257.     lxi    h,RomBuf    ; point to Roman character buffer
  258. ;
  259. ; encode character stream in DecBuf
  260. ;
  261. Encod1:    ldax    b        ; get a character
  262.     inx    b        ; update pointer
  263.     cpi    0        ; is it end marker?
  264.     rz            ; (yep)
  265.     cpi    '9'        ; is it a nine?
  266.     jrz    Nine        ; (it is)
  267.     cpi    '5'        ; is it five or more?
  268.     jp    Five        ; (you bet)
  269.     cpi    '4'        ; is it four?
  270.     jrz    Four        ; (uh-huh)
  271. EncAgn:    cpi    '0'        ; a zero?
  272.     jrnz    One        ; (nope)
  273. EncExt:    dcx    d        ; decrement Roman pointer
  274.     dcx    d
  275.     lda    DecCnt        ; decrement count
  276.     dcr    a
  277.     sta    DecCnt
  278.     jrnz    Encod1        ; (loop until zero)
  279.     mvi    a,0        ; mark end
  280.     call    Store        ; ..and store it
  281.     jr    ROut        ; we're done
  282. ;
  283. ;
  284. ; One -- 1 = I, 10 = X, 100 = C, 1000 = M or more
  285. ;
  286. One:    push    psw        ; save number
  287.     ldax    d        ; get Roman character
  288.     call    Store        ; store it
  289.     pop    psw        ; get back number
  290.     dcr    a        ; subtract one
  291.     jr    EncAgn        ; ..and try again
  292. ;
  293. ; Four -- 4 = IV, 40 = XL, 400 = CD
  294. ;
  295. Four:    ldax    d        ; get Roman character I, X, or C
  296.     call    Store        ; store it
  297.     inx    d        ; get next Roman character V, L, or D
  298.     ldax    d
  299.     call    Store        ; store it
  300.     dcx    d        ; restore pointer
  301.     jr    EncExt        ; ..and exit
  302. ;
  303. ; Five -- 5 = V, 50 = L, 500 = D or more
  304. ;
  305. Five:    push    psw        ; save number
  306.     inx    d        ; move pointer
  307.     ldax    d        ; get Roman character V, L, or D
  308.     call    Store        ; store it
  309.     dcx    d        ; restore pointer
  310.     pop    psw        ; get back number
  311.     sui    05h        ; subtract five
  312.     jr    EncAgn        ; ..and try again
  313. ;
  314. ; Nine -- 9 = IX, 90 = XC, OR 900 = CM
  315. ;
  316. Nine:    ldax    d        ; get Roman character I, X, or C
  317.     call    Store        ; store it
  318.     inx    d        ; move pointer
  319.     inx    d
  320.     ldax    d        ; get Roman character X, C, or M
  321.     call    Store        ; store it
  322.     dcx    d        ; restore pointer
  323.     dcx    d
  324.     jr    EncExt        ; ..and exit
  325. ;
  326. ;
  327. ; Store -- store Roman character in RomBuf for output
  328. ;
  329. Store:    mov    m,a        ; store data in buffer
  330.     inx    h        ; move pointer
  331.     ret
  332. ;
  333. ; ROut -- Roman output to console
  334. ;
  335. ROut:    lxi    h,RomBuf    ; point to Roman buffer
  336.     call    epstr        ; and output it
  337.     ret
  338. ;
  339. ; EatSpc -- eats spaces
  340. ;
  341. EatSpc:    ldax    d
  342.     cpi    ' '        ; space?
  343.     inx    d
  344.     jrz    EatSpc        ; (yes)
  345.     dcx    d
  346.     ret
  347. ;
  348.     DSEG
  349. ;
  350. ; Workspace . . .
  351. ;
  352. DecBuf:    ds    5        ; decimal buffer
  353. RomBuf:    ds    16        ; Roman buffer
  354. DecCnt:    ds    1        ; decimal count
  355. OldStk:    ds    2        ; old stack pointer
  356. ;
  357.     end
  358.