home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progasm / asmlib1.arj / ROUTINES.8 < prev    next >
Encoding:
Text File  |  1991-06-01  |  36.5 KB  |  848 lines

  1. ; ╔═════════════════════════════════════════════════════════════╗
  2. ; ║░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░║
  3. ; ║░░░░░░░░░░░░░░░░╔═╗░╔═╗░╦░╦░═╦═░╦░╦═╗░╔══░╔═╗░░░░░░░░░░░░░░░░║
  4. ; ║░░░░░░░░░░░░░░░░╠╦╝░║░║░║░║░░║░░║░║░║░╠═░░╚═╗░░░░░░░░░░░░░░░░║
  5. ; ║░░░░░░░░░░░░░░░░╩╚═░╚═╝░╚═╝░░╩░░╩░╩░╩░╚══░╚═╝░░░░░░░░░░░░░░░░║
  6. ; ║░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░║
  7. ; ╚═════════════════════════════════════════════════════════════╝
  8. ;╔════════════════╗
  9. ;║     SETEVAR    ╟─────────────────────────────────────────────┐
  10. ;╚╤═══════════════╝                                             │
  11. ; │     Set a system environment variable                       │
  12. ; │                                                             │
  13. ; │     DS:SI - location of variable name (input)               │
  14. ; │                                                             │
  15. ; │     CARRY set if not done                                   │
  16. ; └─────────────────────────────────────────────────────────────┘
  17. #IF @@SETEVAR
  18. $SETEVAR: PUSH  AX,BX,CX,DX,ES,DI
  19.         DELEVAR                 ;delete the old variable first
  20.         GETENV                  ;find the environment
  21.         JC      >L2
  22.         MOV     BX,CX           ;save the length of the environment
  23.         XOR     AX,AX           ;clear AX
  24. L1:     REPNZ   SCASB           ;find the next variable
  25.         ES CMP  B[DI],0         ;are we at the very end?
  26.         JNZ     L1              ;no - keep going
  27.         CALL    >L3             ;swap DS:SI <--> ES:DI
  28.         MOV     DX,DI           ;DX = start of new variable
  29.         MOV     CX,0100         ;CX = a long length
  30.         REPNZ   SCASB           ;find the null
  31.         SUB     DI,DX           ;DX = length of new variable
  32.         XCHG    DI,DX
  33.         CALL    >L3             ;swap back
  34.         SUB     BX,DI           ;BX = leftover in environment
  35.         SUB     BX,12           ;reduce by twelve bytes
  36.         CMP     BX,DX           ;is there enough room ?
  37.         JC      >L2             ;no - jump as error
  38.         PUSH    SI,DI,DS
  39.         MOV     SI,DI           ;align source and destination
  40.         ADD     DI,DX           ;point to new end
  41.         MOV     DS,ES           ;align segments
  42.         MOV     CX,DX           ;set up the length
  43.         REP     MOVSB           ;move the tail upward
  44.         MOV     CX,DX           ;set up length again
  45.         POP     DS,DI,SI
  46.         REP     MOVSB           ;move in the new value
  47.         CLC                     ;everything is all right
  48. L2:     POP     DI,ES,DX,CX,BX,AX
  49.         RET
  50. L3:     PUSH    DS,SI,ES,DI     ;swap DS:SI <--> ES:DI
  51.         POP     SI,DS,DI,ES
  52.         RET
  53. #ENDIF
  54. ;╔════════════════╗
  55. ;║     DELEVAR    ╟─────────────────────────────────────────────┐
  56. ;╚╤═══════════════╝      Delete a system environment variable   │
  57. ; │                                                             │
  58. ; │                      DS:SI - location of variable name      │
  59. ; │                                                             │
  60. ; └─────────────────────────────────────────────────────────────┘
  61. #IF @@DELEVAR
  62. $DELEVAR: PUSH  AX,BX,CX,DS,SI,ES,DI
  63.         GETENV                  ;find the environment
  64.         JC      >L2             ;exit if it isn't found
  65.         MOV     BX,CX           ;save the displacement of end
  66.         GETEVAR                 ;find the variable
  67.         JC      >L2             ;exit if it doesn't exist now
  68. L0:     DEC     DI              ;back up one character
  69.         JZ      >L1             ;stop if at beginning of environment
  70.         ES CMP  B[DI-1],0       ;are we back at the null ?
  71.         JNZ     L0              ;no - keep going
  72. L1:     PUSH    ES,DI           ;save location
  73.         XOR     AX,AX           ;AX=0
  74.         MOV     CX,0100         ;length=256 bytes
  75.         REPNZ   SCASB           ;look forward for a null
  76.         MOV     DS,ES           ;DS:SI <-- next part of environment
  77.         MOV     SI,DI           ;ES:DI <-- deletable part
  78.         POP     DI,ES
  79.         MOV     CX,BX           ;save the environment length
  80.         SUB     CX,SI           ;calculate length left
  81.         REP     MOVSB           ;delete the item
  82. L2:     POP     DI,ES,SI,DS,CX,BX,AX
  83.         RET
  84. #ENDIF
  85. ;╔════════════════╗
  86. ;║     GETEVAR    ╟─────────────────────────────────────────────┐
  87. ;╚╤═══════════════╝                                             │
  88. ; │     Get address of a system environment variable            │
  89. ; │                                                             │
  90. ; │     DS:SI - location of variable name (input)               │
  91. ; │                                                             │
  92. ; │     ES:DI - location of environment's variable              │
  93. ; │     CX    - available room in environment                   │
  94. ; │     CARRY set if variable not found                         │
  95. ; └─────────────────────────────────────────────────────────────┘
  96. #IF @@GETEVAR
  97. $GETEVAR:GETENV                 ;find the environment
  98.         JC      >L4             ;reject if not found
  99.         PUSH    AX
  100. L1:     PUSH    SI              ;tuck it in the stack
  101. L2:     LODSB                   ;get a letter
  102.         SCASB                   ;does it match ?
  103.         JNZ     >L3             ;no - drop this
  104.         CMP     AL,"="          ;is it the end of variable ?
  105.         JNZ     L2              ;no - vanish
  106.         PUSH    DI              ;save this displacement
  107.         GETENVT                 ;get the size
  108.         POP     DI,SI,AX        ;reset the stack
  109.         RET
  110. L3:     XOR     AX,AX           ;look for a null
  111.         REPNZ   SCASB           ;have we found it ?
  112.         POP     SI              ;reset stack
  113.         ES CMP  B[DI],0         ;is this the end of environment ?
  114.         JNZ     L1
  115.         POP     AX              ;reset the stack
  116. L4:     GETENVT                 ;get remainder
  117.         STC                     ;mark problem
  118.         RET
  119. #ENDIF
  120. ;╔════════════════╗
  121. ;║     GETENVT    ╟─────────────────────────────────────────────┐
  122. ;╚╤═══════════════╝                                             │
  123. ; │     Get address of system environment tail                  │
  124. ; │                                                             │
  125. ; │     ES:DI - location of environment's tail                  │
  126. ; │     CX    - available room in environment                   │
  127. ; │     CARRY set if no room found                              │
  128. ; └─────────────────────────────────────────────────────────────┘
  129. #IF @@GETENVT
  130. $GETENVT: PUSH  AX              ;save AX
  131.         GETENV                  ;get address of environment
  132.         JC      RET             ;exit if not found
  133.         XOR     AX,AX           ;looking for a NULL
  134. L1:     REPNZ   SCASB           ;stop at the null
  135.         ES CMP  B[DI],0         ;is it the double-null ?
  136.         JNZ     L1              ;no - keep looking
  137.         POP     AX              ;restore AX
  138.         SUB     CX,12           ;allow distance of twelve
  139.         JA      RET             ;jump if enough room
  140.         XOR     CX,CX           ;clear down to zero
  141.         STC                     ;set carry (error)
  142.         RET
  143. #ENDIF
  144. ;╔════════════════╗
  145. ;║     GETENV     ╟─────────────────────────────────────────────┐
  146. ;╚╤═══════════════╝      Get address of system environment      │
  147. ; │                                                             │
  148. ; │                      ES:DI - location of environment        │
  149. ; │                      CX - length of environment             │
  150. ; │                      CARRY set if environment not found     │
  151. ; └─────────────────────────────────────────────────────────────┘
  152. #IF @@GETENV
  153. $GETENV: PUSH   AX,BX,DX,SI
  154.         MOV     DX,CS           ;point to own PSP
  155.         MOV     CX,10           ;max depth = ten
  156. L0:     MOV     ES,DX           ;point to a PSP
  157.         CMP     DX,0A000        ;is it in high memory ?
  158.         JA      >L1             ;yes - should be DRDOS
  159.         ES CMP  DX,[016]        ;is this its own father ?
  160.         ES MOV  DX,[016]        ;(regardless - activate father)
  161.         LOOPNZ  L0              ;not father - go deeper
  162.         JCXZ    >L9             ;problem if too deep
  163. L1:     MOV     DI,DX           ;point to the PSP
  164.         ES MOV  BX,[02C]        ;pick up pointer to environment
  165.         CMP     BX,0            ;is it blank ?
  166.         JZ      >L7             ;yes - jump (still might be good)
  167.         PUSH    BX,DX,DI        ;(save registers)
  168.         MOV     AH,030          ;get DOS version number
  169.         INT     021             ;DOS service interrupt
  170.         CMP     AX,0A03         ;is this version 3.10 ?
  171.         JZ      >L4             ;yes - problems!
  172.         CS MOV  ES,[02C]        ;pick up pointer to own environment
  173.         MOV     SI,O >K0        ;we shall look for proof of DRDOS
  174.         XOR     DI,DI           ;start at beginning of environment
  175.         MOV     CX,2000         ;max length to search
  176. L2:     XOR     BX,BX           ;start at displacement zero
  177. L3:     MOV     AL,[SI+BX]      ;pick up a byte from footprint
  178.         ES CMP  AL,[DI+BX]      ;is this byte a match ?
  179.         JNZ     >L6             ;no - keep looking
  180.         INC     BX              ;increment
  181.         CMP     BX,5            ;have we found all the toes ?
  182.         JB      L3              ;not yet - keep looking
  183. L4:     POP     DI,DX,BX        ;(restore registers)
  184.         MOV     DX,BX           ;this is the (putative) environment
  185.         DEC     DX              ;back up to its arena
  186. L5:     MOV     ES,DX           ;activate arena
  187.         ES CMP  DI,[1]          ;does this "belong" to the PSP ?
  188.         JNZ     >L8             ;no  - we must go searching
  189.         ES CMP  B[010],020      ;yes - is the first byte alphabetic ?
  190.         JB      >L8             ;not alphabetic - go searching again
  191.         ES MOV  CX,[3]          ;pick up length of this partition
  192.         INC     DX              ;go back to putative environment
  193.         MOV     ES,DX           ;this IS the environment
  194.         MOV     AX,16           ;multiply paragraphs by sixteen..
  195.         MUL     CX              ;..to establish environment size in AX
  196.         MOV     CX,AX           ;store the environment size
  197.         JMP     S >L9           ;exit now
  198. L6:     XOR     AX,AX           ;(clear AX)
  199.         REPNZ   SCASB           ;look for the next operand
  200.         ES CMP  AL,[DI]         ;are we at the end of environment ?
  201.         JNZ     L2              ;no - keep looking for footprint
  202.         POP     DI,DX,BX        ;(restore regs) now at end of environment
  203. L7:     DEC     DX              ;back up to arena
  204.         MOV     ES,DX           ;activate it
  205. L8:     ES ADD  DX,[3]          ;point to end of this partition
  206.         INC     DX              ;bump to next partition
  207.         MOV     BX,CS           ;pick up current PSP
  208.         CMP     DX,BX           ;have we arrived yet ?
  209.         JNA     L5              ;not yet - keep trying
  210.         XOR     CX,CX           ;troubles - not found
  211. L9:     POP     SI,DX,BX,AX
  212.         XOR     DI,DI
  213.         STC
  214.         JCXZ    RET
  215.         CLC
  216.         RET                     ;go out
  217. K0              DB      'OS=DR'
  218. #ENDIF
  219. ;╔════════════════╗
  220. ;║     ERROR      ╟─────────────────────────────────────────────┐
  221. ;╚╤═══════════════╝Errors are accessed in "ERRORS" via BP.      │
  222. ; │                This routine reports and then resigns with   │
  223. ; │                ERRORLEVEL = BP.   "Conditional" entry via   │
  224. ; │                     ERRIFccc < Z, NZ, C, NC, B, A >.        │
  225. ; └─────────────────────────────────────────────────────────────┘
  226. #IF @@ERROR
  227. @@ERRDFT = 1
  228. $ERRIFZ: JZ     $ERROR
  229.         RET
  230. $ERRIFNZ:JNZ    $ERROR
  231. $ERRIFA: JA     $ERROR
  232.         RET
  233. $ERRIFB: JC     $ERROR
  234.         RET
  235. $ERRIFNC:JC     RET
  236. $ERROR: MOV     DX,O >E9-14     ;point to start of default msg
  237.         MOV     SI,O $$ERRORS   ;point to error table
  238.         MOV     AX,BP           ;set the error into AX
  239.         CALL    $ERRDFT         ;look up the error
  240.         ABORT                   ;abort
  241. #ENDIF
  242. ;╔════════════════╗
  243. ;║     PRIOERR    ╟─────────────────────────────────────────────┐
  244. ;╚╤═══════════════╝        Print I/O error (if Cflag on)        │
  245. ; │                          input = AX                         │
  246. ; └─────────────────────────────────────────────────────────────┘
  247. #IF @@PRIOERR
  248.   @@ERRDFT = 1
  249. $PRIOERR:JNC    RET
  250.         PUSH    CX,DX,BP,SI
  251.         MOV     DX,O >E9-18     ;point to start of default msg
  252.         MOV     SI,O >L1        ;point to error table
  253.         MOV     BP,AX           ;synchronise BP and AX
  254.         CALL    $ERRDFT         ;look up the error & print it
  255.         POP     SI,BP,DX,CX
  256.         STC
  257.         RET
  258. L1:
  259.         ASCIIZ "Invalid function"               ;01
  260.         ASCIIZ "File not found"                 ;02
  261.         ASCIIZ "Path not found"                 ;03
  262.         ASCIIZ "No available handle"            ;04
  263.         ASCIIZ "Access denied"                  ;05
  264.         ASCIIZ "Unauthorised function"          ;06
  265.         ASCIIZ "MCB destroyed"                  ;07
  266.         ASCIIZ "Insufficient memory"            ;08
  267.         ASCIIZ "Invalid address"                ;09
  268.         ASCIIZ "Invalid environment"            ;0A
  269.         ASCIIZ "Invalid format"                 ;0B
  270.         ASCIIZ "Invalid access mode"            ;0C
  271.         ASCIIZ 0FF                              ;0D
  272.         ASCIIZ 0FF                              ;0E
  273.         ASCIIZ "Invalid device"                 ;0F
  274.         ASCIIZ
  275. #ENDIF
  276. ;╔════════════════╗
  277. ;║     ERRDFT     ╟─────────────────────────────────────────────┐
  278. ;╚╤═══════════════╝     DX <-- message nnn from table at SI     │
  279. ; │ or default "ERROR nnn" AX=nnn      (registers not saved)    │
  280. ; └─────────────────────────────────────────────────────────────┘
  281. #IF @@ERRDFT
  282.   @@CRLF = 1
  283. $ERRDFT :PUSH   SI              ;save addr of error table
  284.         MOV     SI,O >E9        ;point to bin store
  285.         MOV     W[SI],AX        ;store nnn
  286.         LEA     DI,[SI-8]       ;point to decimal expansion
  287.         MOV     ES,DS           ;synchronise segments
  288.         WBINTODEC               ;conv to dec
  289.         POP     SI              ;get addr of error table
  290.         LOOKUP                  ;lookup entry nnn
  291.         JC      >L1             ;jump if not found
  292.         CMP     W[SI],0FF       ;empty entry ?
  293.         IF NZ MOV DX,SI         ;if found, DX = message
  294. L1:
  295.         NLPRINT                 ;print it
  296.         JMPL    $CRLF           ;line feed
  297.         DB      "I/O ERROR "
  298.         DB      8 DUP 0
  299. E9      DW      0
  300. #ENDIF
  301. ;╔════════════════╗
  302. ;║     LOOKUP     ╟─────────────────────────────────────────────┐
  303. ;╚╤═══════════════╝  Lookup into table (DS:SI) to item N        │
  304. ; │                  BP = item number (N) - starts at 1         │
  305. ; │                  SI updated  -  carry set if not found      │
  306. ; └─────────────────────────────────────────────────────────────┘
  307. #IF @@LOOKUP
  308. $LOOKUP: PUSH   AX,CX
  309.         LEA     CX,[BP-1]
  310.         JCXZ    >L2
  311. L1:     LODSB
  312.         TEST    AL
  313.         JNZ     L1
  314.         TEST    B[SI]
  315.         JZ      >L2
  316.         LOOP    L1
  317. L2:     CMP     B[SI],1
  318.         POP     CX,AX
  319.         RET
  320. #ENDIF
  321. ;╔════════════════╗
  322. ;║    DBINTODEC   ╟─────────────────────────────────────────────┐
  323. ;╚╤═══════════════╝         DOUBLEWORD Binary to Decimal        │
  324. ; │  i/p : DX | AX                                              │
  325. ; │  o/p : at DI with length CX (not counting 0,$)              │
  326. ; │        max space taken up is 15 bytes: max CX=000D (13)     │
  327. ; └─────────────────────────────────────────────────────────────┘
  328. #IF @@DBINTODEC
  329.   @@WBINTODEC = 1
  330. $DBINTODEC: PUSH DX
  331.         JMP     S >L0
  332. #ENDIF
  333. ;╔════════════════╗
  334. ;║    WBINTODEC   ╟─────────────────────────────────────────────┐
  335. ;╚╤═══════════════╝            WORD Binary to Decimal           │
  336. ; │  i/p : AX                                                   │
  337. ; │  o/p : at DI with length CX (not counting 0,$)              │
  338. ; │        max space taken up is 8 bytes: max CX=0006           │
  339. ; └─────────────────────────────────────────────────────────────┘
  340. #IF @@WBINTODEC
  341. $WBINTODEC: PUSH DX             ;save registers on input
  342.         XOR     DX,DX           ;no HIGH part to doubleword
  343. L0:     PUSH AX,BX,SI,DI
  344.         MOV     SI,O >L9        ;point to the table
  345.         MOV     CX,10           ;putative decimal counter
  346.         XOR     BX,BX           ;clear significance pointer
  347. L1:     XOR     BL,BL           ;clear the low byte
  348. L2:     CMP     DX,[SI+2]       ;is the table entry too large ?
  349.         JZ      >L4             ;probably - try the other side!
  350.         JNA     >L5             ;yes - so jump
  351. L3:     SUB     AX,[SI]         ;reduce DX.AX by D[SI]
  352.         SBB     DX,[SI+2]
  353.         INC     BL              ;count this
  354.         JMP     L2              ;repeat testing
  355. L4:     CMP     AX,[SI]         ;is the table entry too large ?
  356.         JNB     L3              ;no - jump to reduce
  357. L5:     PUSH    AX,DX           ;save the residue
  358.         CMP     CX,1            ;are we at the end of digits ?
  359.         JZ      >L6             ;yes - this is significant ANYWAY
  360.         TEST    BH              ;has significance been found ?
  361.         JNZ     >L6             ;yes - no zero-suppression
  362.         TEST    BL              ;is the digit a leading zero ?
  363.         JZ      >L8             ;yes - finished this iteration
  364.         MOV     BH,1            ;indicate significance started
  365. L6:     ADD     BL,'0'          ;make it printable
  366.         MOV     AL,BL           ;set it for storing to output
  367.         STOSB
  368.         CMP     CL,4            ;are we at a comma-break ?
  369.         JZ      >L7
  370.         CMP     CL,7
  371.         JZ      >L7
  372.         CMP     CL,10
  373.         JNZ     >L8
  374. L7:     MOV     AL,','          ;arrange a comma character
  375.         STOSB
  376. L8:     POP     DX,AX           ;restore residue
  377.         ADD     SI,4            ;move down table
  378.         LOOP    L1              ;keep going for all digits
  379.         MOV     W[DI],'$' by 0  ;append terminators
  380.         MOV     CX,DI           ;pick up current location
  381.         POP     DI              ;retrieve original location
  382.         SUB     CX,DI           ;calculate length
  383.         POP     SI,BX,AX,DX     ;retrieve registers
  384.         RET
  385. L9:     DD      1000000000
  386.         DD      100000000
  387.         DD      10000000
  388.         DD      1000000
  389.         DD      100000
  390.         DD      10000
  391.         DD      1000
  392.         DD      100
  393.         DD      10
  394.         DD      1
  395. #ENDIF
  396. ;╔════════════════╗
  397. ;║    WDECTOBIN   ╟─────────────────────────────────────────────┐
  398. ;╚╤═══════════════╝            WORD Decimal to Binary           │
  399. ; │                         i/p : at SI                         │
  400. ; │   cf if error           o/p : AX                            │
  401. ; └─────────────────────────────────────────────────────────────┘
  402. #IF @@WDECTOBIN
  403. $WDECTOBIN:PUSH CX,DX,SI
  404.         XOR     CX,CX   ;clear the result
  405. L1:     LODSB           ;pick up one byte
  406.         CMP     AL,0    ;are we at the end?
  407.         JZ      >L3     ;yes - finished
  408.         CMP     AL,","  ;is it a comma?
  409.         JZ      L1      ;yes - omit
  410.         VALIDNUM        ;test whether valid numeric
  411.         JC      >L2     ;no - finished with error
  412.         CBW             ;extend AL into AX
  413.         XCHG    AX,CX   ;get the result
  414.         MUL     W >L4   ;multiply by ten
  415.         ADD     CX,AX   ;accumulate
  416.         OR      DX,DX   ;was there overflow?
  417.         JZ      L1      ;no - keep going
  418. L2:     XOR     CX,CX   ;clear total
  419.         STC             ;set error
  420. L3:     MOV     AX,CX
  421.         POP     SI,DX,CX
  422.         RET
  423. L4      DW      10
  424. #ENDIF
  425. ;╔════════════════╗
  426. ;║    VALIDHEX    ╟─────────────────────────────────────────────┐
  427. ;╚╤═══════════════╝   VALIDHEX:  validate a byte as HEX         │
  428. ; │                     i/p - AL                                │
  429. ; │                     o/p - AL (binary equivalent)            │
  430. ; │                     Zflag set if good                       │
  431. ; └─────────────────────────────────────────────────────────────┘
  432. #IF @@VALIDHEX
  433. $VALIDHEX:
  434.         VALIDNUM                ;SEE IF IT IS NUMERIC
  435.         JZ      RET             ;IF SO, THIS IS GOOD
  436.         AND     AL,0DF          ;CONVERT TO UPPERCASE
  437.         CMP     AL,011
  438.         JB      RET
  439.         CMP     AL,016
  440.         JA      >L2
  441.         SUB     AL,7
  442.         JMP     >L1
  443. #ENDIF
  444. ;╔════════════════╗
  445. ;║    VALIDNUM    ╟─────────────────────────────────────────────┐
  446. ;╚╤═══════════════╝   VALIDNUM:  validate a byte as NUMERIC     │
  447. ; │                     i/p - AL                                │
  448. ; │                     o/p - AL (binary equivalent)            │
  449. ; │                     Zflag set if good                       │
  450. ; └─────────────────────────────────────────────────────────────┘
  451. #IF @@VALIDNUM
  452. $VALIDNUM:SUB   AL,030          ;CONVERT TO BINARY
  453.         JB      RET
  454.         CMP     AL,9
  455.         JA      >L2
  456. L1:     CMP     AL,AL           ;FORCE Z FLAG ON
  457.         RET
  458. L2:     STC
  459.         RET
  460. #ENDIF
  461. ;╔════════════════╗
  462. ;║    FRJULIAN    ╟─────────────────────────────────────────────┐
  463. ;╚╤═══════════════╝  Calculate day/month/year from Julian date  │
  464. ; │                                                             │
  465. ; │ i/p: BX = "Julian" date                                     │
  466. ; │                                                             │
  467. ; │ o/p: AL = day (0=Sunday, 1=Monday..)                        │
  468. ; │      CX = year (including century)                          │
  469. ; │      DH = month                                             │
  470. ; │      DL = day                                               │
  471. ; ├─────────────────────────────────────────────────────────────┤
  472. ; │     The "Julian" date here is the number of days since      │
  473. ; │     20th November 1937: it applies to all dates from then   │
  474. ; │     up to 31st December 2099.  It is related to the         │
  475. ; │     Clarion date and to Scaliger's date function.           │
  476. ; │                                                             │
  477. ; │                Clarion  = Julian +    50,000                │
  478. ; │                Scaliger = Julian + 2,428,858                │
  479. ; └─────────────────────────────────────────────────────────────┘
  480. #IF @@FRJULIAN
  481. $FRJULIAN:
  482.         WEEKDAYJ
  483.         PUSH    AX,BX,BP
  484.         MOV     AX,BX
  485.         XOR     DX,DX
  486.         ADD     AX,0360E        ;adjust for later division
  487.         ADC     DX,0
  488.         PUSH    AX              ;save (low part only!)
  489.         DSAL    DX,AX           ;calculate "yyyy" -> mult by 4
  490.         DSAL    DX,AX
  491.         MOV     CX,365*4 + 1    ;divide by 365.25 to find year
  492.         DIV     CX
  493.         MOV     BP,1900         ;use 20th century
  494.         ADD     BP,AX           ;BP <- "yyyy"
  495.         MUL     CX
  496.         SHR     AX,1
  497.         SHR     AX,1
  498.         POP     CX
  499.         SUB     CX,AX           ;isolate "B" (days into year)
  500.         AND     CX,01FF
  501.         CMP     CX,60           ;before 60 ?
  502.         JNB     >L2             ;no  - jump
  503.         TEST    BP,3            ;leap year ?
  504.         IF Z INC CL             ;yes - adjust working number
  505.         CMP     CL,32           ;before 32 ?
  506.         MOV     CH,1            ;assume January
  507.         IF NB ADD CX,0100 - 31  ;no - adjust
  508. L1:     MOV     DX,CX           ;DX <- mm & dd
  509.         MOV     CX,BP           ;CX <- yyyy
  510.         POP     BP,BX,AX
  511.         RET
  512. L2:     MOV     AX,100          ;calculate "mm"
  513.         MUL     CX
  514.         ADD     AX,3225
  515.         MOV     BX,3060
  516.         XOR     DX,DX
  517.         DIV     BX              ;AX <- "mm"
  518.         PUSH    AX              ;save it
  519.         MUL     BX              ;calculate "C"
  520.         SUB     AX,3240
  521.         MOV     BX,100
  522.         DIV     BX              ;AX <- "C"
  523.         SUB     CX,AX           ;CX <- "dd"
  524.         POP     AX              ;retrieve "mm"
  525.         MOV     CH,AL           ;CX <- "mm" & "dd"
  526.         JMP     L1
  527. #ENDIF
  528. ;╔════════════════╗
  529. ;║    TOJULIAN    ╟─────────────────────────────────────────────┐
  530. ;╚╤═══════════════╝  Calculate Julian date from day/month/year  │
  531. ; │                                                             │
  532. ; │ i/p: CX = year (including century)                          │
  533. ; │      DH = month                                             │
  534. ; │      DL = day                                               │
  535. ; │                                                             │
  536. ; │ o/p: AL = day (0=Sunday, 1=Monday..)                        │
  537. ; │      BX = "Julian" date                                     │
  538. ; ├─────────────────────────────────────────────────────────────┤
  539. ; │     The "Julian" date here is the number of days since      │
  540. ; │     20th November 1937: it applies to all dates from then   │
  541. ; │     up to 31st December 2099.  It is related to the         │
  542. ; │     Clarion date and to Scaliger's date function.           │
  543. ; │                                                             │
  544. ; │                Clarion  = Julian +    50,000                │
  545. ; │                Scaliger = Julian + 2,428,858                │
  546. ; └─────────────────────────────────────────────────────────────┘
  547. #IF @@TOJULIAN
  548.   @@WEEKDAYJ = 1
  549. $TOJULIAN: PUSH AX,CX,DX,BP
  550.         XOR     AX,AX
  551.         XCHG    AL,DH                   ;AX <-- month
  552.         PUSH    AX
  553.         MOV     BP,DX                   ;BX <-- term1
  554.         MOV     DX,306
  555.         MUL     DX
  556.         ADD     AX,26
  557.         MOV     BX,10
  558.         DIV     BX
  559.         ADD     BP,AX                   ;BP += term2
  560.         POP     AX                      ;retrieve month
  561.         CMP     AL,2                    ;JAN or FEB ?
  562.         JA      >L1                     ;no
  563.         ADD     BP,AX                   ;yes - add on factor
  564.         TEST    CL,3                    ;leap year ?
  565.         IF NZ INC BP                    ;no  - bump up BP
  566. L1:     SUB     CX,1900                 ;calculate term3
  567.         MOV     AX,365                  ;days in year
  568.         MUL     CX
  569.         SHR     CX,1                    ;..plus the quarter-day
  570.         SHR     CX,1
  571.         ADD     AX,CX
  572.         ADD     AX,0C9CF                ;add corrective factor
  573.         ADD     AX,BP                   ;accumulate the extra
  574.         MOV     BX,AX                   ;BX <-- result
  575.         POP     BP,DX,CX,AX
  576. ;>> fall through
  577. #ENDIF
  578. ;╔════════════════╗
  579. ;║    WEEKDAYJ    ╟─────────────────────────────────────────────┐
  580. ;╚╤═══════════════╝     Calculate weekday from a Julian date    │
  581. ; │                                                             │
  582. ; │ i/p: BX = "Julian" date                                     │
  583. ; │ o/p: AL = day (0=Sunday, 1=Monday..)                        │
  584. ; ├─────────────────────────────────────────────────────────────┤
  585. ; │     The "Julian" date here is the number of days since      │
  586. ; │     20th November 1937: it applies to all dates from then   │
  587. ; │     up to 31st December 2099.  It is related to the         │
  588. ; │     Clarion date and to Scaliger's date function.           │
  589. ; │                                                             │
  590. ; │                Clarion  = Julian +    50,000                │
  591. ; │                Scaliger = Julian + 2,428,858                │
  592. ; └─────────────────────────────────────────────────────────────┘
  593. #IF @@WEEKDAYJ
  594. $WEEKDAYJ: PUSH BX,CX
  595.         MOV     CH,AH           ;save AH
  596.         LEA     AX,[BX+6]       ;adjust BX result by six days
  597. L1:     XOR     BX,BX           ;AX =(date%256) and BX =(date/256)
  598.         XCHG    AH,BL           ;calculate effect of BX
  599.         SHL     BX,1
  600.         SHL     BX,1
  601.         ADD     AX,BX
  602.         MOV     BH,7            ;set up divisor
  603.         CMP     AH,BH           ;is dividend small enough yet ?
  604.         JNB     L1              ;no  - go around once again
  605.         DIV     BH              ;yes - calculate modulo 7
  606.         MOV     AL,AH           ;record the result in AL
  607.         MOV     AH,CH           ;retrieve AH
  608.         POP     CX,BX
  609.         RET
  610. #ENDIF
  611. ;╔════════════════╗
  612. ;║     SWAPSCR    ╟─────────────────────────────────────────────┐
  613. ;╚╤═══════════════╝                                             │
  614. ; │         Swap memory (DS:SI) with screen (segment ES)        │
  615. ; │ 1st word = row/col    2nd word = rows/cols    others = bytes│
  616. ; └─────────────────────────────────────────────────────────────┘
  617. #IF @@SWAPSCR
  618. $SWAPSCR: PUSH  BX,CX,DX,SI,DI,BP,AX
  619.         LODSW                   ;PICK UP LOCATION
  620.         PUSH    AX
  621.         LODSW                   ;PICK UP DIMENSIONS
  622.         MOV     BX,AX           ;BX = DIMENSIONS
  623.         POP     AX              ;AX = LOCATION
  624.         XOR     DX,DX
  625.         XCHG    BH,DL
  626.         MOV     BP,BX           ;BP = BOXWIDTH
  627.         MOV     BX,80
  628.         XCHG    AL,BL
  629.         MUL     AH              ;AX = ROW * 80
  630.         ADD     AX,BX           ;ADD ON COL
  631.         ADD     AX,AX           ;DOUBLE FOR WORDS
  632.         MOV     DI,AX           ;DI = OFFSET ON SCREEN
  633. L1:     PUSH    DI
  634.         MOV     CX,BP           ;SET UP BOXWIDTH
  635. L2:     MOV     BX,ES:[DI]      ;SWAP A WORD
  636.         LODSW
  637.         MOV     W [SI-2],BX
  638.         STOSW
  639.         LOOP    L2              ;DO A WHOLE LINE
  640.         POP     DI
  641.         ADD     DI,160          ;BUMP TO NEXT ROW
  642.         DEC     DX              ;COUNT DOWN LINES
  643.         JNZ     L1
  644.         POP     AX,BP,DI,SI,DX,CX,BX
  645.         RET
  646. #ENDIF
  647. ;╔════════════════╗
  648. ;║      PARSE     ╟─────────────────────────────────────────────┐
  649. ;╚╤═══════════════╝           Parse filename                    │
  650. ; │             DS:SI - pointer to ASCIIZ filename              │
  651. ; │         o/p 5D-64 major name parsed                         │
  652. ; │         o/p 65-67 minor name parsed                         │
  653. ; │         -CF set if ambiguity involved                       │
  654. ; └─────────────────────────────────────────────────────────────┘
  655. #IF @@PARSE
  656. $PARSE: PUSH    AX,SI,DI,ES,SI
  657. L1:     POP     AX              ;ignore the old directory break
  658.         PUSH    SI              ;this is new directory break
  659. L2:     LODSB                   ;pick up a byte
  660.         CMP     AL,":"          ;is it drive terminator?
  661.         JZ      L1              ;yes - set as directory break
  662.         CMP     AL,"\"          ;is it a level terminator?
  663.         JZ      L1              ;yes - set as directory break
  664.         CMP     AL,0            ;is it the ASCIIZ terminator?
  665.         JNZ     L2              ;no - keep looking
  666.         POP     SI              ;go back to last break
  667.         MOV     AX,02900        ;get FCB parse command
  668.         MOV     ES,DS           ;align segments
  669.         MOV     DI,O PSPFCB1    ;point to FCB1
  670.         INT     021
  671.         PUSH    AX              ;set result..
  672.         PUSHF                   ;..into flags
  673.         POP     ES,DI,SI,AX
  674.         RET
  675. #ENDIF
  676. ;╔════════════════╗
  677. ;║     LENSTR     ╟─────────────────────────────────────────────┐
  678. ;╚╤═══════════════╝           Length of ASCIIZ string           │
  679. ; │               input pointer DS:SI       output CX           │
  680. ; └─────────────────────────────────────────────────────────────┘
  681. #IF @@LENSTR
  682. $LENSTR: PUSH   AX,SI
  683.         XOR     CX,CX           ;clear counter
  684. M1:     INC     CX              ;bump counter
  685.         LODSB                   ;pick up one byte
  686.         CMP     AL,0            ;is it the ASCIIZ null?
  687.         JNZ     M1              ;no - repeat
  688.         POP     SI,AX
  689.         RET
  690. #ENDIF
  691. ;╔════════════════╗
  692. ;║     SETPOS     ╟─────────────────────────────────────────────┐
  693. ;╚╤═══════════════╝     Set position as $$VIDPOS                │
  694. ; └─────────────────────────────────────────────────────────────┘
  695. #IF @@SETPOS
  696.   @@GETADR = 1
  697. $SETPOS:PUSH    AX,BX,DX
  698.         MOV     BH,B $$VIDPAGE
  699.         MOV     AH,02
  700.         MOV     DX,W $$VIDPOS
  701.         INT     010
  702.         POP DX,BX,AX
  703.         JMPS    $GETADR
  704. #ENDIF
  705. ;╔════════════════╗
  706. ;║     SETPAGE    ╟─────────────────────────────────────────────┐
  707. ;╚╤═══════════════╝            Set page as $$VIDPAGE            │
  708. ; └─────────────────────────────────────────────────────────────┘
  709. #IF @@SETPAGE
  710.   @@GETPAGE = 1
  711. $SETPAGE:
  712.         PUSH    AX
  713.         MOV     AL,B $$VIDPAGE
  714.         INT     010
  715.         POP     AX
  716. ;  (fall through)
  717. #ENDIF
  718. ;╔════════════════╗
  719. ;║     GETPAGE    ╟─────────────────────────────────────────────┐
  720. ;╚╤═══════════════╝      Establish Video mode and addresses     │
  721. ; │                                                             │
  722. ; │             output: ES:DI --> $$VIDSEG, $$VIDADR            │
  723. ; │                   $$VIDMODE  - current mode                 │
  724. ; │                   $$VIDCOLS  - number of cols in this mode  │
  725. ; │                   $$VIDPAGE  - current active page          │
  726. ; │                   $$VIDSHAPE - cursor shape                 │
  727. ; │                   $$VIDPOS   - [$VIDROW, $VIDCOL]           │
  728. ; │             CF if not correct mode                          │
  729. ; └─────────────────────────────────────────────────────────────┘
  730. #IF @@GETPAGE
  731.   @@GETPOS = 1
  732. $GETPAGE:PUSH AX,BX
  733.         MOV     AH,0F
  734.         INT     010
  735.         XOR     BX,BX                   ;clear BX
  736.         MOV     B $$VIDPAGE,BH          ;store page
  737.         MOV     W $$VIDMODE,AX          ;store mode & $$VIDCOLS
  738.         CMP     B $$VIDCOLS,80          ;is the rowlength = 80 ?
  739.         IF NZ SHR BX,1                  ;if not, shift the length
  740.         ADD     BH,0B0                  ;add on for the segment
  741.         CMP     AL,07                   ;is it MDA text?
  742.         JZ      >L1                     ;yes - jump
  743.         ADD     BH,08                   ;go higher in memory
  744.         CMP     AL,04                   ;is mode 00-03 ?
  745.         CMC                             ;change response
  746. L1:     POP BX,AX
  747.         JC      RET
  748. ;  (fall through)
  749. #ENDIF
  750. ;╔════════════════╗
  751. ;║     GETPOS     ╟─────────────────────────────────────────────┐
  752. ;╚╤═══════════════╝  Get $$VIDPOS and $$VIDADR,  ES:DI          │
  753. ; └─────────────────────────────────────────────────────────────┘
  754. #IF @@GETPOS
  755.   @@POS2ADR = 1
  756. $GETPOS:PUSH AX,BX,CX,DX
  757.         MOV     BH,B $$VIDPAGE
  758.         MOV     AH,03
  759.         INT     010
  760.         MOV     W $$VIDSHAPE,CX
  761.         MOV     W $$VIDPOS,DX
  762.         MOV     AX,DX
  763.         CALL    $POS2ADR
  764.         MOV     W $$VIDADR,DI
  765.         POP DX,CX,BX,AX
  766.         RET
  767. #ENDIF
  768. ;╔════════════════╗
  769. ;║     POS2ADR    ╟─────────────────────────────────────────────┐
  770. ;╚╤═══════════════╝      Convert row/col AH/AL to offset DI     │
  771. ; └─────────────────────────────────────────────────────────────┘
  772. #IF @@POS2ADR
  773.   @@VIDDATA = 1
  774. $POS2ADR:PUSH   AX,BX
  775.         MOV     BX,AX
  776.         MOV     BH,0
  777.         MOV     AL,AH
  778.         MUL     B $$VIDCOLS     ;calculate displacement
  779.         ADD     AX,BX           ;add column number
  780.         MOV     ES,W $$VIDSEG   ;set video segment
  781.         MOV     DI,AX           ;set in DI
  782.         CLC                     ;prevent carry
  783.         POP     BX,AX
  784.         RET
  785. #ENDIF
  786. ;╔════════════════╗
  787. ;║     VIDDATA    ╟─────────────────────────────────────────────┐
  788. ;╚╤═══════════════╝   VIDEO DATA (called by several routines)   │
  789. ; └─────────────────────────────────────────────────────────────┘
  790. #IF @@VIDDATA
  791. $$VIDMODE DB 0          ;mode
  792. $$VIDCOLS DB 0          ;width of screen (columns)
  793. $$VIDPAGE DB 0          ;current page
  794. $$VIDSHAPE DW 0         ;shape of cursor
  795. $$VIDPOS  DW            ;cursor position
  796.  $$VIDCOL DB 0                  ;column
  797.  $$VIDROW DB 0                  ;row
  798. $$VIDADR  DW 0          ;address (for DI)
  799. $$VIDSEG  DW 0          ;segment (for ES)
  800. #ENDIF
  801. ;╔════════════════╗
  802. ;║      CRLF      ╟─────────────────────────────────────────────┐
  803. ;║     NLPRINT    ║  CRLF    : print CR/LF only                 │
  804. ;║      PRINT     ║  NLPRINT : print new line + message (DS:DX) │
  805. ;╚════════════════╝  PRINT   : print message (DS:DX)            │
  806. ; │                   << NULL terminates a message >>           │
  807. ; └─────────────────────────────────────────────────────────────┘
  808. #IF @@CRLF
  809. $CRLF:  PUSH    DX
  810.         MOV     DX,O CARRET + 2
  811.         NLPRINT
  812.         POP     DX
  813.         RET
  814. #ENDIF
  815. #IF @@NLPRINT
  816. $NLPRINT:PUSH   DX
  817.         MOV     DX,O CARRET
  818.         PRINT
  819.         POP     DX
  820. #ENDIF
  821. #IF @@PRINT
  822. $PRINT: PUSH    AX,SI,DX
  823.         XCHG    DX,SI
  824.         MOV     AH,02
  825. L1:     LODSB
  826.         MOV     DL,AL
  827.         OR      AL,AL
  828.         JZ      >L2
  829.         INT     021
  830.         JMPS    L1
  831. L2:     POP     DX,SI,AX
  832.         RET
  833. #ENDIF
  834. ;╔════════════════╗
  835. ;║     RESIGN     ╟─────────────────────────────────────────────┐
  836. ;║     ABORT      ║    Exit program: RESIGN: (ERRORLEVEL = 00)  │
  837. ;╚╤═══════════════╝                  ABORT : (ERRORLEVEL = AL)  │
  838. ; │                                                             │
  839. ; └─────────────────────────────────────────────────────────────┘
  840. #IF @@RESIGN
  841.   @@ABORT = 1
  842. $RESIGN: XOR    AL,AL
  843. #ENDIF
  844. #IF @@ABORT
  845. $ABORT: MOV     AH,04C
  846.         INT     021
  847. #ENDIF
  848.