Subversion Repositories SvarDOS

Rev

Rev 1484 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1479 mateusz.vi 1
;
1480 mateusz.vi 2
; SvarDOS MORE
1479 mateusz.vi 3
;
4
; Displays output one screen at a time
5
;
6
;  - multilingual (looks up the LANG env variable)
7
;  - tiny (fits in a single disk sector)
8
;
1480 mateusz.vi 9
; This program is part of the SvarDOS project <http://svardos.org>
1479 mateusz.vi 10
;
1480 mateusz.vi 11
; ****************************************************************************
1479 mateusz.vi 12
; *** Distributed under the terms of the MIT LICENSE *************************
1480 mateusz.vi 13
; ****************************************************************************
1479 mateusz.vi 14
;
15
; Copyright (C) 2023 Mateusz Viste
16
;
17
; Permission is hereby granted, free of charge, to any person obtaining a copy
18
; of this software and associated documentation files (the "Software"), to
19
; deal in the Software without restriction, including without limitation the
20
; rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
21
; sell copies of the Software, and to permit persons to whom the Software is
22
; furnished to do so, subject to the following conditions:
23
;
24
; The above copyright notice and this permission notice shall be included in
25
; all copies or substantial portions of the Software.
26
;
27
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32
; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33
; IN THE SOFTWARE.
34
; ****************************************************************************
35
;
36
; To be compiled with the A72 assembler:
37
; A72 MORE.ASM MORE.COM
38
;
39
 
40
 
41
; COM file always has a 100h origin
42
ORG     100h
43
 
44
 
45
; ****************************************************************************
46
; * Display a short help screen if any (non-empty) argument is provided.     *
47
; *                                                                          *
48
; * detect presence of arguments in the command's tail (PSP 81h), looking    *
49
; * at the first non-space character. If it's a CR then no argument (CR is   *
50
; * the tail's terminator).                                                  *
51
; ****************************************************************************
52
mov     ax, ds
53
mov     es, ax
54
mov     al, ' '
55
mov     cx, 0ffh
56
mov     di, 81h
57
repe    scasb                          ; compare AL with [ES:DI++]
58
mov     al, [di-1]
59
 
60
cmp     al, 0Dh
61
je      NO_ARGS
62
 
63
; some arg found: display help and quit
64
mov     ah, 9h
65
mov     dx, offset HELP
66
int     21h
67
int     20h
68
 
1480 mateusz.vi 69
HELP db "SvarDOS MORE 2023.0", 13, 10
1479 mateusz.vi 70
     db 10
71
     db "MORE < README.TXT", 13, 10
1480 mateusz.vi 72
     db "TYPE README.TXT | MORE", 13, 10, '$'
1479 mateusz.vi 73
 
74
NO_ARGS:
75
 
76
 
77
; ****************************************************************************
78
; * detect screen dimensions (max usable row and column)                     *
79
; ****************************************************************************
80
mov     ah, 0Fh                        ; GET CURRENT VIDEO MODE
81
int     10h
82
mov     byte ptr [MAXCOL], ah
83
mov     ax, 40h
84
mov     es, ax
85
mov     ah, [es:84h]                   ; 0040:0084
86
test    ah, ah                         ; ancient PCes do not know this
87
jz      SKIP_ROWS_DETECTION
88
mov     byte ptr [MAXROW], ah
89
 
90
SKIP_ROWS_DETECTION:
91
 
92
 
93
; ****************************************************************************
94
; * Scan the environement block looking for the LANG variable                *
95
; ****************************************************************************
96
 
97
; set ES to point at the environment segment (PSP's offset 2Ch)
98
mov     es, [2Ch]
99
 
100
; compare DS:[SI] with ES:[DI], up to 5 bytes ("LANG=")
101
cld
102
mov     di, 0
103
CMP_NEXT_VAR:
104
 
105
; if it points at a nul already then it's the end of the env block
106
mov     al, [es:di]
107
test    al, al
108
jz      ENDOFENV
109
 
110
mov     si, LANG
111
mov     cx, 5
112
repe    cmpsb
113
 
114
; if CX == 0 then found a LANG= match
115
jcxz    FOUND_LANG
116
 
117
; otherwise jump to next var (look for nearest nul terminator)
118
xor     al, al
119
mov     cx, 0ffffh
120
repne   scasb                          ; compare AL with [ES:DI++]
121
jmp     CMP_NEXT_VAR
122
 
123
; FOUND THE LANG VARIABLE (at ES:DI)
124
FOUND_LANG:
125
 
126
mov     ax, [es:di]                    ; load the LANG ID to AX and make
127
and     ax, 0DFDFh                     ; sure it is always upper case
128
 
129
 
130
; ****************************************************************************
131
; * Now I have a LANG ID in AX and I have to match it for something I know.  *
132
; * The LANG ID is simply the value for the two uppercase LANG letters, for  *
133
; * example the LANG ID for "PL" is 4C50h (50h = 'P', 4Ch = 'L').            *
134
; ****************************************************************************
135
 
136
; DE [44h 45h]
1484 mateusz.vi 137
mov     bp, TEXT_DE
1479 mateusz.vi 138
cmp     ax, 4544h
139
je      LANGOK
140
 
1485 mateusz.vi 141
; DK [44h 4Bh]
142
mov     bp, TEXT_DK
143
cmp     ax, 4B44h
144
je      LANGOK
145
 
146
; ES [45h 53h]
147
mov     bp, TEXT_ES
148
cmp     ax, 5345h
149
je      LANGOK
150
 
151
; FI [46h 49h]
152
mov     bp, TEXT_FI
153
cmp     ax, 4946h
154
je      LANGOK
155
 
1479 mateusz.vi 156
; FR [46h 52h]
1484 mateusz.vi 157
mov     bp, TEXT_FR
1479 mateusz.vi 158
cmp     ax, 5246h
159
je      LANGOK
160
 
1485 mateusz.vi 161
; IT [49h 54h]
162
mov     bp, TEXT_IT
163
cmp     ax, 5449h
164
je      LANGOK
165
 
1479 mateusz.vi 166
; NL [4Eh 4Ch]
1484 mateusz.vi 167
mov     bp, TEXT_NL
1479 mateusz.vi 168
cmp     ax, 4C4Eh
169
je      LANGOK
170
 
171
; PL [50h 4Ch]
1484 mateusz.vi 172
mov     bp, TEXT_PL
1479 mateusz.vi 173
cmp     ax, 4C50h
174
je      LANGOK
175
 
176
; RU [52h 55h]
1484 mateusz.vi 177
mov     bp, TEXT_RU
1479 mateusz.vi 178
cmp     ax, 5552h
179
je      LANGOK
180
 
1485 mateusz.vi 181
; SL [53h 4Ch]
182
mov     bp, TEXT_SL
183
cmp     ax, 4C53h
184
je      LANGOK
185
 
186
; SV [53h 56h]
187
mov     bp, TEXT_SV
188
cmp     ax, 5653h
189
je      LANGOK
190
 
1479 mateusz.vi 191
; TR [54h 52h]
1484 mateusz.vi 192
mov     bp, TEXT_TR
1479 mateusz.vi 193
cmp     ax, 5254h
194
je      LANGOK
195
 
196
 
197
; *** LANG NOT FOUND OR LANG ID MATCH FAILED: FALL BACK TO EN ****************
198
 
199
ENDOFENV:
1484 mateusz.vi 200
mov     bp, TEXT_EN
1479 mateusz.vi 201
 
202
LANGOK:
203
 
204
 
205
; ****************************************************************************
206
; * DUPLICATING HANDLES: here I duplicate stdin into a new handle so I can   *
207
; * safely close original stdin (file handle 0) and then duplicate stderr    *
208
; * into stdin. The purpose of these shenanigans is to be able to cope with  *
209
; * situations when stdin is redirected (eg. with CTTY)                      *
210
; ****************************************************************************
211
 
1484 mateusz.vi 212
; duplicate stdin and keep the new file handle in FHANDLE
1479 mateusz.vi 213
xor     bx, bx
214
mov     ah, 45h
215
int     21h
1484 mateusz.vi 216
mov     [FHANDLE], ax
1479 mateusz.vi 217
 
218
; I can close stdin now
219
mov     ah, 3Eh
220
int     21h
221
 
222
; duplicate stderr to stdin
223
; bx = file handle / cx = file handle to become duplicate of bx
224
mov     ah, 46h
225
mov     bx, 2
226
xor     cx, cx
227
int     21h
228
; ****************************************************************************
229
 
230
 
231
; make sure cursor is on column 0
232
mov ah, 2h                             ; write character in DL to stdout
233
mov dl, 0Dh                            ; carriage return
234
int 21h
235
 
1484 mateusz.vi 236
; reset BX - from now on bh = cur row and bl = cur col
237
xor     bx, bx
1479 mateusz.vi 238
 
239
; consume stdin bytes by loading them into buffer
240
RELOADBUF:
1484 mateusz.vi 241
xchg    di, bx                         ; save BX to DI (contains cur row+col)
1479 mateusz.vi 242
mov     ah, 3Fh                        ; DOS 2+ - read from file or device
1484 mateusz.vi 243
mov     bx, [FHANDLE]                  ; duplicated stdin was saved in FHANDLE
1479 mateusz.vi 244
mov     cx, 1024
245
mov     dx, offset BUFFER
246
int     21h
247
 
248
; abort on error
249
jc EXIT
250
 
1484 mateusz.vi 251
; restore bx
252
xchg    bx, di
253
 
1479 mateusz.vi 254
; did I get any bytes? 0 bytes read means "EOF"
255
test    ax, ax
256
jnz     PREPLOOP
257
 
258
EXIT:
259
int     20h
260
 
261
; prepare the LODSB loop
262
PREPLOOP:
263
mov     cx, ax
264
mov     si, dx
265
 
266
NEXTCHAR:
267
 
268
; AL = DS:[SI++]
269
cld
270
lodsb
271
 
272
; EOF char? (check this first so a short jump to exit is still possible)
273
cmp     al, 1Ah
274
jz      EXIT
275
 
276
; [7h] BELL?
277
cmp     al, 7h
278
je      OUTPUT_CHAR
279
 
280
; [8h] BACKSPACE? moves the cursor back by one column, no effect if it is on
281
; first column already. it does not blank the characters it passes over.
282
cmp     al, 8h
283
jne     NOTBS
1484 mateusz.vi 284
test    bl, bl                         ; am I on on column 0? (bl = cur col)
285
jz      OUTPUT_CHAR
286
dec     bl
1479 mateusz.vi 287
jmp     short OUTPUT_CHAR
288
NOTBS:
289
 
290
; [9h] TAB?
291
cmp     al, 9h
292
jne     NOTTAB
1484 mateusz.vi 293
add     bl, 8                          ; bl = cur col
294
and     bl, 248
1479 mateusz.vi 295
jmp     short OUTPUT_CHAR
296
NOTTAB:
297
 
298
; [0Ah] LF?
299
cmp     al, 0Ah
300
jne     NOTLF
1484 mateusz.vi 301
inc     bh                             ; bh = cur row
1479 mateusz.vi 302
jmp     short OUTPUT_CHAR
303
NOTLF:
304
 
305
; [0Dh] CR?
306
cmp     al, 0Dh
307
jnz     NOTCR
1484 mateusz.vi 308
xor     bl, bl                         ; bl = cur col
1479 mateusz.vi 309
jmp     short OUTPUT_CHAR
310
NOTCR:
311
 
312
; otherwise: increment cur column, and then maybe cur row
1484 mateusz.vi 313
inc     bl                             ; bl = cur col
314
cmp     bl, [MAXCOL]
1479 mateusz.vi 315
jb      OUTPUT_CHAR
1484 mateusz.vi 316
inc     bh                             ; bh = cur row
317
xor     bl, bl                         ; bl = cur col
1479 mateusz.vi 318
 
319
OUTPUT_CHAR:
320
mov     dl, al
321
mov     ah, 2h
322
int     21h
1484 mateusz.vi 323
cmp     bh, [MAXROW]                   ; bh = cur row
1479 mateusz.vi 324
jae     PRESSANYKEY
325
 
326
CHARLOOP:
327
loop    NEXTCHAR                       ; dec cx and jmp to NEXTCHAR if cx > 0
328
jmp     RELOADBUF
329
 
330
 
1482 mateusz.vi 331
; display " --- More ---"
1479 mateusz.vi 332
PRESSANYKEY:
333
mov     ah, 9h                         ; disp $-termin. string pointed by DX
1482 mateusz.vi 334
mov     dx, offset SEPAR1
1479 mateusz.vi 335
int     21h
1484 mateusz.vi 336
mov     dx, bp
1479 mateusz.vi 337
int     21h
1482 mateusz.vi 338
mov     dx, offset SEPAR2
339
int     21h
1479 mateusz.vi 340
 
1483 mateusz.vi 341
; wait for a keypress
342
mov     ah, 08h                        ; read char from stdin, no echo
1479 mateusz.vi 343
int     21h
1483 mateusz.vi 344
; read again if an extended key was pressed
345
test    al, al
346
jnz     GETKEY_DONE
347
int     21h
348
GETKEY_DONE:
1479 mateusz.vi 349
 
350
; output a CR/LF pair and reset counters
351
mov     dx, offset CRLF
352
mov     ah, 9h
353
int     21h
1484 mateusz.vi 354
xor     bx, bx                         ; bh = cur row, bl = cur col
1479 mateusz.vi 355
jmp     CHARLOOP
356
 
357
 
358
; ****************************************************************************
359
; * DATA                                                                     *
360
; ****************************************************************************
361
 
362
MAXROW  db      24                     ; maximum *addressable* row (not total)
363
MAXCOL  db      80                     ; total available columns
364
 
365
CRLF DB 13, 10, '$'
366
LANG DB "LANG="
1482 mateusz.vi 367
SEPAR1 DB "--- $"
368
SEPAR2 DB " ---$"
1479 mateusz.vi 369
 
370
TEXT_DE DB "WEITER$"
1485 mateusz.vi 371
TEXT_DK DB "MERE$"
372
TEXT_ES DB "M", 0B5h, "S$"              ; "MAS" with an A-acute (CP 850)
1479 mateusz.vi 373
TEXT_EN DB "MORE$"
1485 mateusz.vi 374
TEXT_FI DB "LIS", 8Eh, 8Eh, "$"         ; "LISAA" - AA with diaeresis (CP 850)
1479 mateusz.vi 375
TEXT_FR DB "PLUS$"
1485 mateusz.vi 376
TEXT_IT DB "PI", 0EBh, "$"              ; "PIU" with U-acute (CP 850)
1479 mateusz.vi 377
TEXT_NL DB "MEER$"
378
TEXT_PL DB "DALEJ$"
1480 mateusz.vi 379
TEXT_RU DB 84h,80h,8Bh,85h,85h,'$'     ; "DALEE" (CP 866)
1485 mateusz.vi 380
TEXT_SL DB "VE", 0ACh, "$"             ; "VEC" with C-caron (CP 852)
381
TEXT_SV DB "MERA$"
1479 mateusz.vi 382
TEXT_TR DB "DAHA FAZLA$"
383
 
1484 mateusz.vi 384
; uninitialized area (must be defined last)
385
 
386
FHANDLE dw      ?                      ; file handle I read from (DUPed stdin)
387
 
1479 mateusz.vi 388
BUFFER: