diff options
| author | 2024-04-25 21:24:10 +0100 | |
|---|---|---|
| committer | 2024-04-25 22:32:27 +0000 | |
| commit | 2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch) | |
| tree | 80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/MAPPER/GETMSG.ASM | |
| parent | Merge pull request #430 from jpbaltazar/typoptbr (diff) | |
| download | ms-dos-main.tar.gz ms-dos-main.tar.xz ms-dos-main.zip | |
Diffstat (limited to 'v4.0/src/MAPPER/GETMSG.ASM')
| -rw-r--r-- | v4.0/src/MAPPER/GETMSG.ASM | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/v4.0/src/MAPPER/GETMSG.ASM b/v4.0/src/MAPPER/GETMSG.ASM new file mode 100644 index 0000000..12dfaa3 --- /dev/null +++ b/v4.0/src/MAPPER/GETMSG.ASM | |||
| @@ -0,0 +1,586 @@ | |||
| 1 | ; | ||
| 2 | page 80,132 | ||
| 3 | ; | ||
| 4 | title CP/DOS DosGetMessage mapper | ||
| 5 | ; | ||
| 6 | messages segment word public 'messages' | ||
| 7 | |||
| 8 | OurMessage db 0dh,0ah,"DosGetMessage returning ->",'$' | ||
| 9 | |||
| 10 | ErrorMessageFlag db 0 | ||
| 11 | MessageToGo dw 0 | ||
| 12 | MessageLength dw 0 | ||
| 13 | NextVarPointer dd 0 | ||
| 14 | VarsToGo dw 0 | ||
| 15 | |||
| 16 | MaxMessageNumber = 0 | ||
| 17 | |||
| 18 | ; This macro is used to define/declare all of the messages | ||
| 19 | |||
| 20 | ; We will have four macros, msg -> defines a complete message | ||
| 21 | ; msgStart -> defines the first part of a message | ||
| 22 | ; msgContinue -> continues a started message | ||
| 23 | ; msgEnd -> ends a message | ||
| 24 | |||
| 25 | MacroState = 0 | ||
| 26 | |||
| 27 | ;---------------------------------------------- | ||
| 28 | |||
| 29 | MsgError macro text ; message string error | ||
| 30 | |||
| 31 | if1 | ||
| 32 | else | ||
| 33 | %out | ||
| 34 | %out $ERROR - &text | ||
| 35 | endif | ||
| 36 | |||
| 37 | $ERROR - &text | ||
| 38 | |||
| 39 | endm | ||
| 40 | |||
| 41 | ;---------------------------------------------- | ||
| 42 | |||
| 43 | msg macro number,text | ||
| 44 | |||
| 45 | if MacroState NE 0 | ||
| 46 | MsgError <Cannot use the 'Msg' Macro when inside a message definition.> | ||
| 47 | mexit | ||
| 48 | endif | ||
| 49 | |||
| 50 | Message&Number db text | ||
| 51 | db 0 | ||
| 52 | |||
| 53 | if MaxMessageNumber lt &number | ||
| 54 | MaxMessageNumber = &Number | ||
| 55 | endif | ||
| 56 | |||
| 57 | MacroState = 0 | ||
| 58 | |||
| 59 | endm | ||
| 60 | |||
| 61 | ;---------------------------------------------- | ||
| 62 | |||
| 63 | msgStart macro number,text ; start of a message string | ||
| 64 | |||
| 65 | if MacroState NE 0 | ||
| 66 | MsgError <Cannot use the 'MsgStart' macro when inside a message definition.> | ||
| 67 | mexit | ||
| 68 | endif | ||
| 69 | |||
| 70 | Message&Number db text | ||
| 71 | |||
| 72 | if MaxMessageNumber lt &number | ||
| 73 | MaxMessageNumber = &Number | ||
| 74 | endif | ||
| 75 | |||
| 76 | MacroState = 1 | ||
| 77 | |||
| 78 | endm | ||
| 79 | |||
| 80 | ;---------------------------------------------- | ||
| 81 | |||
| 82 | msgContinue macro text ; messgage string contination | ||
| 83 | |||
| 84 | if MacroState EQ 0 | ||
| 85 | MsgError <Cannot use the 'MsgContinue' macro unless inside a message definition.> | ||
| 86 | mexit | ||
| 87 | endif | ||
| 88 | |||
| 89 | db text | ||
| 90 | |||
| 91 | MacroState = 1 | ||
| 92 | |||
| 93 | endm | ||
| 94 | |||
| 95 | ;---------------------------------------------- | ||
| 96 | |||
| 97 | msgEnd macro ; end of message string | ||
| 98 | |||
| 99 | if MacroState EQ 0 | ||
| 100 | MsgError <Cannot use the 'MsgEnd' macro unless inside a message definition.> | ||
| 101 | mexit | ||
| 102 | endif | ||
| 103 | |||
| 104 | db 0 | ||
| 105 | |||
| 106 | MacroState = 0 | ||
| 107 | |||
| 108 | endm | ||
| 109 | |||
| 110 | |||
| 111 | ;----------------------------------------------- | ||
| 112 | |||
| 113 | ; Define/declare the messages first! | ||
| 114 | |||
| 115 | include messages.inc | ||
| 116 | |||
| 117 | NotFoundNumber = -2 | ||
| 118 | |||
| 119 | NotFoundMessage label byte | ||
| 120 | msg NotFoundNumber,<'We could not find your message #'> | ||
| 121 | |||
| 122 | ; Now, for each defined message, generate an index | ||
| 123 | |||
| 124 | msgidx macro number | ||
| 125 | ifdef Message&Number | ||
| 126 | dw &Number | ||
| 127 | dw offset messages:Message&Number | ||
| 128 | endif | ||
| 129 | endm | ||
| 130 | |||
| 131 | even | ||
| 132 | |||
| 133 | MessageIndex label word | ||
| 134 | |||
| 135 | ThisMessageNumber = 0 | ||
| 136 | rept MaxMessageNumber + 1 | ||
| 137 | msgidx %ThisMessageNumber | ||
| 138 | ThisMessageNumber = ThisMessageNumber + 1 | ||
| 139 | endm | ||
| 140 | |||
| 141 | dw -1 | ||
| 142 | |||
| 143 | NotFoundIndex dw -2 | ||
| 144 | dw offset messages:NotFoundMessage | ||
| 145 | |||
| 146 | messages ends | ||
| 147 | ; | ||
| 148 | dosxxx segment byte public 'dos' | ||
| 149 | assume cs:dosxxx,ds:nothing,es:nothing,ss:nothing | ||
| 150 | ; | ||
| 151 | ;********************************************************************** | ||
| 152 | ;* | ||
| 153 | ;* MODULE: dosgetmessage | ||
| 154 | ;* | ||
| 155 | ;* FILE NAME: dos029.asm | ||
| 156 | ;* | ||
| 157 | ;* CALLING SEQUENCE: | ||
| 158 | ;* | ||
| 159 | ;* push@ other insert variable table | ||
| 160 | ;* push word insert variable count | ||
| 161 | ;* push@ other message buffer address | ||
| 162 | ;* push word buffer length | ||
| 163 | ;* push word message number | ||
| 164 | ;* push@ asciiz message file name | ||
| 165 | ;* push@ word returned message length | ||
| 166 | ;* call dosgetmessage | ||
| 167 | ;* | ||
| 168 | ;* MODULES CALLED: None (preliminary version) | ||
| 169 | ;* | ||
| 170 | ;********************************************************************* | ||
| 171 | ; | ||
| 172 | public dosgetmessage | ||
| 173 | .sall | ||
| 174 | .xlist | ||
| 175 | include macros.inc | ||
| 176 | .list | ||
| 177 | |||
| 178 | str struc | ||
| 179 | old_bp dw ? | ||
| 180 | return dd ? | ||
| 181 | ReturnLengthPtr dd ? ; length of returned message | ||
| 182 | MessageFileName dd ? ; message file name | ||
| 183 | MessageNumber dw ? ; number of the message | ||
| 184 | MessageBufferLen dw ? ; length of the message buffer | ||
| 185 | MessageBufferPtr dd ? ; buffer address to return message | ||
| 186 | VariablesCount dw ? ; number of variables | ||
| 187 | VariableTablePtr dd ? ; table of variables to insert | ||
| 188 | str ends | ||
| 189 | |||
| 190 | |||
| 191 | dosgetmessage proc far | ||
| 192 | |||
| 193 | Enter Dosgetmessage ; push registers | ||
| 194 | mov ax,messages ; setup message buffer | ||
| 195 | mov ds,ax | ||
| 196 | assume ds:messages | ||
| 197 | mov ErrorMessageFlag,0 ; reset error message flag | ||
| 198 | |||
| 199 | mov bx,[bp].MessageNumber ; get message number | ||
| 200 | mov si,offset messages:MessageIndex | ||
| 201 | |||
| 202 | SearchForMessageLoop: ; search for message in table | ||
| 203 | lodsw | ||
| 204 | cmp ax,bx ; found ?? | ||
| 205 | je FoundMessage ; jump if true | ||
| 206 | |||
| 207 | add si,2 ; if not serach continues | ||
| 208 | cmp ax,-1 | ||
| 209 | jne SearchForMessageLoop | ||
| 210 | |||
| 211 | mov si,offset messages:NotFoundIndex + 2 | ||
| 212 | mov ErrorMessageFlag,1 | ||
| 213 | |||
| 214 | ; Here, ds:[si] -> word message number, followed by word message offset | ||
| 215 | |||
| 216 | FoundMessage: | ||
| 217 | mov si,ds:[si] | ||
| 218 | |||
| 219 | ; Here, ds:[si] -> message text bytes | ||
| 220 | |||
| 221 | les di,[bp].VariableTablePtr ; get variable address | ||
| 222 | mov word ptr NextVarPointer+0,di ; save it | ||
| 223 | mov word ptr NextVarPointer+2,es | ||
| 224 | |||
| 225 | mov di,[bp].VariablesCount ; get variable count | ||
| 226 | mov VarsToGo,di ; save it | ||
| 227 | |||
| 228 | les di,[bp].MessageBufferPtr ; get return message buffer | ||
| 229 | ; address | ||
| 230 | mov ax,[bp].MessageBufferLen ; get return message buffer | ||
| 231 | mov MessageToGo,ax ; length | ||
| 232 | |||
| 233 | cmp ax,0 ; length = 0 ?? | ||
| 234 | jne HaveLengthToCopy ; if not, jump | ||
| 235 | |||
| 236 | jmp GetMessageDone ; done | ||
| 237 | |||
| 238 | HaveLengthToCopy: | ||
| 239 | mov MessageLength,0 ; initialize counter | ||
| 240 | |||
| 241 | MoveCharsLoop: | ||
| 242 | lodsb ; get next character | ||
| 243 | cmp al,'%' ; is it a % sign | ||
| 244 | je DoSubstitution ; if so, need substitution | ||
| 245 | |||
| 246 | cmp al,0 ; end of string ?? | ||
| 247 | jne RealCharacter ; if not look for real chars | ||
| 248 | |||
| 249 | jmp GetMessageDone ; else, jump to update | ||
| 250 | ; return message length | ||
| 251 | |||
| 252 | RealCharacter: ; look for real character | ||
| 253 | stosb | ||
| 254 | inc MessageLength ; update message length counter | ||
| 255 | dec MessageToGo | ||
| 256 | jnz MoveCharsLoop ; branch if not all done | ||
| 257 | |||
| 258 | jmp GetMessageDone ; else alldone, branch | ||
| 259 | |||
| 260 | DoSubstitution: ; do substitution | ||
| 261 | lodsb ; get character | ||
| 262 | cmp al,'%' ; check for %% | ||
| 263 | je RealCharacter ; if so, get next character | ||
| 264 | |||
| 265 | |||
| 266 | |||
| 267 | ; skip the numbers that indicate field width! | ||
| 268 | |||
| 269 | SkipFieldWidth: ; check for field width digit | ||
| 270 | cmp al,'0' ; indicator digits | ||
| 271 | jc CheckChar | ||
| 272 | |||
| 273 | cmp al,'9'+1 | ||
| 274 | jnc CheckChar | ||
| 275 | ; if field width indicator | ||
| 276 | lodsb ; jump to examine next char | ||
| 277 | jmp SkipFieldWidth | ||
| 278 | |||
| 279 | ;----------------------------------------- | ||
| 280 | |||
| 281 | CheckChar: ; check for char substitution | ||
| 282 | cmp al,'c' ; if true go do character | ||
| 283 | je SubstituteChar ; substitution | ||
| 284 | cmp al,'C' | ||
| 285 | jne CheckDecimal | ||
| 286 | |||
| 287 | SubstituteChar: ; do character subtitution | ||
| 288 | push ds | ||
| 289 | push si | ||
| 290 | lds si,NextVarPointer | ||
| 291 | lds si,ds:dword ptr [si] | ||
| 292 | |||
| 293 | assume ds:nothing | ||
| 294 | |||
| 295 | lodsb | ||
| 296 | pop si | ||
| 297 | pop ds | ||
| 298 | |||
| 299 | assume ds:messages | ||
| 300 | |||
| 301 | add word ptr NextVarPointer,4 | ||
| 302 | dec VarsToGo | ||
| 303 | |||
| 304 | jmp RealCharacter | ||
| 305 | |||
| 306 | ;----------------------------------------- | ||
| 307 | |||
| 308 | CheckDecimal: ; check for decimal subtitution | ||
| 309 | cmp al,'d' ; if true, do decimal | ||
| 310 | je SubstituteDecimal ; substitution | ||
| 311 | cmp al,'D' | ||
| 312 | jne CheckString | ||
| 313 | |||
| 314 | SubstituteDecimal: ; do decimal subtitution | ||
| 315 | push ds | ||
| 316 | push si | ||
| 317 | lds si,NextVarPointer | ||
| 318 | lds si,ds:dword ptr [si] | ||
| 319 | |||
| 320 | assume ds:nothing | ||
| 321 | |||
| 322 | lodsw | ||
| 323 | pop si | ||
| 324 | pop ds | ||
| 325 | |||
| 326 | assume ds:messages | ||
| 327 | |||
| 328 | add word ptr NextVarPointer,4 | ||
| 329 | dec VarsToGo | ||
| 330 | |||
| 331 | mov dx,0 | ||
| 332 | call ConvDec | ||
| 333 | |||
| 334 | add MessageLength,ax | ||
| 335 | sub MessageToGo,ax | ||
| 336 | jc PastEndOfBuffer | ||
| 337 | |||
| 338 | jmp MoveCharsLoop | ||
| 339 | |||
| 340 | PastEndOfBuffer: | ||
| 341 | jmp GetMessageDone | ||
| 342 | |||
| 343 | ;----------------------------------------- | ||
| 344 | |||
| 345 | CheckString: | ||
| 346 | cmp al,'s' ; check for string subtitution | ||
| 347 | je SubstituteString ; if true, do string | ||
| 348 | cmp al,'S' ; substitution | ||
| 349 | jne CheckLong | ||
| 350 | |||
| 351 | SubstituteString: ; do string substitution | ||
| 352 | push ds | ||
| 353 | push si | ||
| 354 | mov cx,MessageToGo | ||
| 355 | mov dx,MessageLength | ||
| 356 | lds si,NextVarPointer | ||
| 357 | lds si,ds:dword ptr [si] | ||
| 358 | assume ds:nothing | ||
| 359 | |||
| 360 | ContinueStringSubstitution: | ||
| 361 | lodsb | ||
| 362 | cmp al,0 | ||
| 363 | je EndOfSubstituteString | ||
| 364 | |||
| 365 | stosb | ||
| 366 | inc dx | ||
| 367 | loop ContinueStringSubstitution | ||
| 368 | |||
| 369 | EndOfSubstituteString: | ||
| 370 | pop si | ||
| 371 | pop ds | ||
| 372 | assume ds:messages | ||
| 373 | |||
| 374 | add word ptr NextVarPointer,4 | ||
| 375 | dec VarsToGo | ||
| 376 | |||
| 377 | mov MessageLength,dx | ||
| 378 | mov MessageToGo,cx | ||
| 379 | jcxz PastEndOfBuffer | ||
| 380 | |||
| 381 | jmp MoveCharsLoop | ||
| 382 | |||
| 383 | ;----------------------------------------- | ||
| 384 | |||
| 385 | CheckLong: ; need long substitution | ||
| 386 | cmp al,'l' | ||
| 387 | je SubstituteLong ; if true go do it | ||
| 388 | cmp al,'L' | ||
| 389 | jne Unknown ; else unknown substitution | ||
| 390 | |||
| 391 | SubstituteLong: | ||
| 392 | jmp RealCharacter ; just go back | ||
| 393 | |||
| 394 | ;----------------------------------------- | ||
| 395 | |||
| 396 | Unknown: | ||
| 397 | jmp RealCharacter ; just go back | ||
| 398 | |||
| 399 | |||
| 400 | |||
| 401 | |||
| 402 | ; Update the return message length | ||
| 403 | |||
| 404 | GetMessageDone: | ||
| 405 | push ds | ||
| 406 | push si | ||
| 407 | mov ax,MessageLength | ||
| 408 | lds si,[bp].ReturnLengthPtr | ||
| 409 | assume ds:nothing | ||
| 410 | mov ds:[si],ax | ||
| 411 | pop si | ||
| 412 | pop ds | ||
| 413 | assume ds:messages | ||
| 414 | |||
| 415 | cmp ErrorMessageFlag,0 | ||
| 416 | je NotErrorMessage | ||
| 417 | |||
| 418 | mov ErrorMessageFlag,0 | ||
| 419 | |||
| 420 | KeepGoingBackwards: | ||
| 421 | cmp es:byte ptr [di-1],0 | ||
| 422 | jne PutItHere | ||
| 423 | |||
| 424 | dec di | ||
| 425 | jmp KeepGoingBackwards | ||
| 426 | |||
| 427 | PutItHere: | ||
| 428 | mov ax,[bp].MessageNumber | ||
| 429 | mov dx,0 | ||
| 430 | |||
| 431 | call convdec | ||
| 432 | lds si,[bp].ReturnLengthPtr | ||
| 433 | assume ds:nothing | ||
| 434 | add ax,3 ; for cr, lf, nul | ||
| 435 | add ds:[si],ax | ||
| 436 | |||
| 437 | mov al,0dh | ||
| 438 | stosb | ||
| 439 | mov al,0ah | ||
| 440 | stosb | ||
| 441 | |||
| 442 | mov al,0 | ||
| 443 | stosb | ||
| 444 | |||
| 445 | NotErrorMessage: | ||
| 446 | jmp SkipToHere | ||
| 447 | |||
| 448 | mov dx,seg messages | ||
| 449 | mov ds,dx | ||
| 450 | mov dx,offset messages:OurMessage | ||
| 451 | |||
| 452 | mov ah,9 ; load op code | ||
| 453 | int 21h ; display message | ||
| 454 | |||
| 455 | lds si,[bp].ReturnLengthPtr | ||
| 456 | mov cx,ds:[si] | ||
| 457 | lds dx,[bp].MessageBufferPtr | ||
| 458 | |||
| 459 | mov bx,1 | ||
| 460 | mov ah,40h | ||
| 461 | int 21h ; display message | ||
| 462 | |||
| 463 | SkipToHere: | ||
| 464 | xor ax,ax ; set good return code | ||
| 465 | |||
| 466 | mexit ; pop registers | ||
| 467 | ret size str - 6 ; return | ||
| 468 | |||
| 469 | dosgetmessage endp | ||
| 470 | |||
| 471 | page | ||
| 472 | |||
| 473 | ;������������������������������������������������������������������ | ||
| 474 | |||
| 475 | Tens dd 10000000 | ||
| 476 | dd 1000000 | ||
| 477 | dd 100000 | ||
| 478 | dd 10000 | ||
| 479 | dd 1000 | ||
| 480 | dd 100 | ||
| 481 | dd 10 | ||
| 482 | dd 1 | ||
| 483 | dd 0 | ||
| 484 | |||
| 485 | convdec proc near | ||
| 486 | |||
| 487 | ; input es:di -> location to put decimal characters at | ||
| 488 | ; dx:ax -> 32bit value to be displayed | ||
| 489 | |||
| 490 | ; output es:di -> next location for output characters | ||
| 491 | ; ax = number of characters output | ||
| 492 | |||
| 493 | push bp | ||
| 494 | sub sp,6 | ||
| 495 | mov bp,sp | ||
| 496 | |||
| 497 | DecLength equ word ptr [bp+0] | ||
| 498 | LowValue equ word ptr [bp+2] | ||
| 499 | HighValue equ word ptr [bp+4] | ||
| 500 | |||
| 501 | mov DecLength,0 | ||
| 502 | mov HighValue,dx | ||
| 503 | mov LowValue,ax | ||
| 504 | |||
| 505 | mov bx,offset dosxxx:Tens | ||
| 506 | |||
| 507 | ; Start with a count of zero. | ||
| 508 | |||
| 509 | DigitLoop: | ||
| 510 | mov dx,0 | ||
| 511 | |||
| 512 | ; Loop, counting the number of times you can subtract the current digit value | ||
| 513 | |||
| 514 | CountLoop: | ||
| 515 | mov ax,cs:[bx+0] | ||
| 516 | sub LowValue,ax | ||
| 517 | mov ax,cs:[bx+2] | ||
| 518 | sbb HighValue,ax | ||
| 519 | jc TooFar | ||
| 520 | inc dx ; Subtraction did no go negative, inc digit | ||
| 521 | jmp CountLoop | ||
| 522 | |||
| 523 | ; Since we know when this digit is done by the number going negative, we must | ||
| 524 | ; fixup the damage. | ||
| 525 | |||
| 526 | TooFar: | ||
| 527 | mov ax,cs:[bx+0] | ||
| 528 | add LowValue,ax | ||
| 529 | mov ax,cs:[bx+2] | ||
| 530 | adc HighValue,ax | ||
| 531 | |||
| 532 | ; We need to supress leading zeros, so check to see if this digit is non zero | ||
| 533 | |||
| 534 | cmp dx,0 | ||
| 535 | jnz DoDisplay | ||
| 536 | |||
| 537 | ; Digit is zero, check to see if we have put out any digits yet? | ||
| 538 | |||
| 539 | cmp Declength,0 | ||
| 540 | jz NextDigit | ||
| 541 | |||
| 542 | ; Either digit was non zero, or we have already output the leading non-zero. | ||
| 543 | ; It really doesn't matter, display the digit | ||
| 544 | |||
| 545 | DoDisplay: | ||
| 546 | mov al,dl | ||
| 547 | add al,'0' | ||
| 548 | stosb | ||
| 549 | inc DecLength | ||
| 550 | |||
| 551 | ; Set up for the next digit, and determine if we are done | ||
| 552 | |||
| 553 | NextDigit: | ||
| 554 | add bx,4 | ||
| 555 | cmp cs:word ptr [bx+0],0 | ||
| 556 | jnz DigitLoop | ||
| 557 | cmp cs:word ptr [bx+2],0 | ||
| 558 | jnz DigitLoop | ||
| 559 | |||
| 560 | ; Check to see that we at least put out a single 0 character | ||
| 561 | |||
| 562 | cmp DecLength,0 | ||
| 563 | jne Done | ||
| 564 | |||
| 565 | ; We didn't, so let's put the zero there | ||
| 566 | |||
| 567 | mov al,'0' | ||
| 568 | stosb | ||
| 569 | inc DecLength | ||
| 570 | |||
| 571 | ; The decimal display is complete. Get the return value and return | ||
| 572 | |||
| 573 | Done: | ||
| 574 | mov ax,DecLength | ||
| 575 | |||
| 576 | mov sp,bp | ||
| 577 | add sp,6 | ||
| 578 | pop bp | ||
| 579 | |||
| 580 | ret | ||
| 581 | |||
| 582 | convdec endp | ||
| 583 | |||
| 584 | dosxxx ends | ||
| 585 | |||
| 586 | end | ||