Subversion Repositories SvarDOS

Rev

Rev 1493 | 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)
1493 mateusz.vi 7
;  - TINY! (fits in a single disk sector)
1479 mateusz.vi 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
; ****************************************************************************
1486 mateusz.vi 94
; * preset lang to EN                                                        *
95
; ****************************************************************************
96
mov     bp, LANGLIST+2
97
 
98
 
99
; ****************************************************************************
1479 mateusz.vi 100
; * Scan the environement block looking for the LANG variable                *
101
; ****************************************************************************
102
 
103
; set ES to point at the environment segment (PSP's offset 2Ch)
104
mov     es, [2Ch]
105
 
106
; compare DS:[SI] with ES:[DI], up to 5 bytes ("LANG=")
107
cld
108
mov     di, 0
109
CMP_NEXT_VAR:
110
 
111
; if it points at a nul already then it's the end of the env block
112
mov     al, [es:di]
113
test    al, al
1486 mateusz.vi 114
jz      LANG_DONE
1479 mateusz.vi 115
 
116
mov     si, LANG
117
mov     cx, 5
118
repe    cmpsb
119
 
120
; if CX == 0 then found a LANG= match
121
jcxz    FOUND_LANG
122
 
123
; otherwise jump to next var (look for nearest nul terminator)
124
xor     al, al
1490 mateusz.vi 125
mov     ch, 0ffh
1479 mateusz.vi 126
repne   scasb                          ; compare AL with [ES:DI++]
1486 mateusz.vi 127
jmp     short CMP_NEXT_VAR
1479 mateusz.vi 128
 
129
; FOUND THE LANG VARIABLE (at ES:DI)
130
FOUND_LANG:
131
 
1486 mateusz.vi 132
mov     bx, [es:di]                    ; load the LANG ID to BX and make
133
and     bx, 0DFDFh                     ; sure it is always upper case
1479 mateusz.vi 134
 
135
 
136
; ****************************************************************************
1486 mateusz.vi 137
; * Now I have a LANG ID in BX and I have to match it for something I know.  *
1479 mateusz.vi 138
; ****************************************************************************
139
 
1486 mateusz.vi 140
mov     di, LANGLIST
141
mov     ax, ds
142
mov     es, ax
1479 mateusz.vi 143
 
1486 mateusz.vi 144
NEXTLANG:
145
cmp     byte ptr [di], 0               ; look for the end of list terminator
146
je      LANG_DONE
147
cmp     [di], bx                       ; look for a LANG ID match
148
je      LANGIDOK
1485 mateusz.vi 149
 
1486 mateusz.vi 150
; skip string (look for its $ terminator) and repeat
151
SKIPLANG:
152
mov     al, '$'
1490 mateusz.vi 153
mov     ch, 0ffh
1486 mateusz.vi 154
repne   scasb                          ; compare AL with [ES:DI++]
155
jmp     short NEXTLANG
1485 mateusz.vi 156
 
1486 mateusz.vi 157
LANGIDOK:
158
mov     bp, di                         ; ptr to localized msg is always in BP
159
inc     bp
160
inc     bp
1485 mateusz.vi 161
 
1479 mateusz.vi 162
 
1486 mateusz.vi 163
LANG_DONE:
1485 mateusz.vi 164
 
1479 mateusz.vi 165
 
166
; ****************************************************************************
167
; * DUPLICATING HANDLES: here I duplicate stdin into a new handle so I can   *
168
; * safely close original stdin (file handle 0) and then duplicate stderr    *
169
; * into stdin. The purpose of these shenanigans is to be able to cope with  *
170
; * situations when stdin is redirected (eg. with CTTY)                      *
171
; ****************************************************************************
172
 
1484 mateusz.vi 173
; duplicate stdin and keep the new file handle in FHANDLE
1479 mateusz.vi 174
xor     bx, bx
175
mov     ah, 45h
176
int     21h
1484 mateusz.vi 177
mov     [FHANDLE], ax
1479 mateusz.vi 178
 
179
; I can close stdin now
180
mov     ah, 3Eh
181
int     21h
182
 
183
; duplicate stderr to stdin
184
; bx = file handle / cx = file handle to become duplicate of bx
185
mov     ah, 46h
186
mov     bx, 2
187
xor     cx, cx
188
int     21h
189
; ****************************************************************************
190
 
191
 
192
; make sure cursor is on column 0
193
mov ah, 2h                             ; write character in DL to stdout
194
mov dl, 0Dh                            ; carriage return
195
int 21h
196
 
1484 mateusz.vi 197
; reset BX - from now on bh = cur row and bl = cur col
198
xor     bx, bx
1479 mateusz.vi 199
 
200
; consume stdin bytes by loading them into buffer
201
RELOADBUF:
1484 mateusz.vi 202
xchg    di, bx                         ; save BX to DI (contains cur row+col)
1479 mateusz.vi 203
mov     ah, 3Fh                        ; DOS 2+ - read from file or device
1484 mateusz.vi 204
mov     bx, [FHANDLE]                  ; duplicated stdin was saved in FHANDLE
1479 mateusz.vi 205
mov     cx, 1024
206
mov     dx, offset BUFFER
207
int     21h
208
 
209
; abort on error
210
jc EXIT
211
 
1484 mateusz.vi 212
; restore bx
213
xchg    bx, di
214
 
1479 mateusz.vi 215
; did I get any bytes? 0 bytes read means "EOF"
216
test    ax, ax
217
jnz     PREPLOOP
218
 
219
EXIT:
220
int     20h
221
 
222
; prepare the LODSB loop
223
PREPLOOP:
224
mov     cx, ax
225
mov     si, dx
226
 
227
NEXTCHAR:
228
 
229
; AL = DS:[SI++]
230
cld
231
lodsb
232
 
233
; EOF char? (check this first so a short jump to exit is still possible)
234
cmp     al, 1Ah
235
jz      EXIT
236
 
237
; [7h] BELL?
238
cmp     al, 7h
239
je      OUTPUT_CHAR
240
 
241
; [8h] BACKSPACE? moves the cursor back by one column, no effect if it is on
242
; first column already. it does not blank the characters it passes over.
243
cmp     al, 8h
244
jne     NOTBS
1484 mateusz.vi 245
test    bl, bl                         ; am I on on column 0? (bl = cur col)
246
jz      OUTPUT_CHAR
247
dec     bl
1479 mateusz.vi 248
jmp     short OUTPUT_CHAR
249
NOTBS:
250
 
251
; [9h] TAB?
252
cmp     al, 9h
253
jne     NOTTAB
1484 mateusz.vi 254
add     bl, 8                          ; bl = cur col
255
and     bl, 248
1479 mateusz.vi 256
jmp     short OUTPUT_CHAR
257
NOTTAB:
258
 
259
; [0Ah] LF?
260
cmp     al, 0Ah
261
jne     NOTLF
1484 mateusz.vi 262
inc     bh                             ; bh = cur row
1479 mateusz.vi 263
jmp     short OUTPUT_CHAR
264
NOTLF:
265
 
266
; [0Dh] CR?
267
cmp     al, 0Dh
268
jnz     NOTCR
1484 mateusz.vi 269
xor     bl, bl                         ; bl = cur col
1479 mateusz.vi 270
jmp     short OUTPUT_CHAR
271
NOTCR:
272
 
273
; otherwise: increment cur column, and then maybe cur row
1484 mateusz.vi 274
inc     bl                             ; bl = cur col
275
cmp     bl, [MAXCOL]
1479 mateusz.vi 276
jb      OUTPUT_CHAR
1484 mateusz.vi 277
inc     bh                             ; bh = cur row
278
xor     bl, bl                         ; bl = cur col
1479 mateusz.vi 279
 
280
OUTPUT_CHAR:
281
mov     dl, al
282
mov     ah, 2h
283
int     21h
1484 mateusz.vi 284
cmp     bh, [MAXROW]                   ; bh = cur row
1479 mateusz.vi 285
jae     PRESSANYKEY
286
 
287
CHARLOOP:
288
loop    NEXTCHAR                       ; dec cx and jmp to NEXTCHAR if cx > 0
289
jmp     RELOADBUF
290
 
291
 
1496 mateusz.vi 292
; display "--- More ---"
1479 mateusz.vi 293
PRESSANYKEY:
294
mov     ah, 9h                         ; disp $-termin. string pointed by DX
1482 mateusz.vi 295
mov     dx, offset SEPAR1
1479 mateusz.vi 296
int     21h
1484 mateusz.vi 297
mov     dx, bp
1479 mateusz.vi 298
int     21h
1482 mateusz.vi 299
mov     dx, offset SEPAR2
300
int     21h
1479 mateusz.vi 301
 
1483 mateusz.vi 302
; wait for a keypress
303
mov     ah, 08h                        ; read char from stdin, no echo
1479 mateusz.vi 304
int     21h
1483 mateusz.vi 305
; read again if an extended key was pressed
306
test    al, al
307
jnz     GETKEY_DONE
308
int     21h
309
GETKEY_DONE:
1479 mateusz.vi 310
 
311
; output a CR/LF pair and reset counters
312
mov     dx, offset CRLF
313
mov     ah, 9h
314
int     21h
1484 mateusz.vi 315
xor     bx, bx                         ; bh = cur row, bl = cur col
1479 mateusz.vi 316
jmp     CHARLOOP
317
 
318
 
319
; ****************************************************************************
320
; * DATA                                                                     *
321
; ****************************************************************************
322
 
323
MAXROW  db      24                     ; maximum *addressable* row (not total)
324
MAXCOL  db      80                     ; total available columns
325
 
326
CRLF DB 13, 10, '$'
327
LANG DB "LANG="
1482 mateusz.vi 328
SEPAR1 DB "--- $"
329
SEPAR2 DB " ---$"
1479 mateusz.vi 330
 
1486 mateusz.vi 331
LANGLIST:
332
DB "EN",  "MORE$"                      ; EN must be 1st to be used as default
1487 mateusz.vi 333
; non-EN strings follow
1486 mateusz.vi 334
DB "DE",  "WEITER$"
335
DB "DK",  "MERE$"
336
DB "ES",  "M", 0B5h, "S$"              ; "MAS" with an A-acute (CP 850)
337
DB "FI",  "LIS", 8Eh, 8Eh, "$"         ; "LISAA" - AA with diaeresis (CP 850)
338
DB "FR",  "PLUS$"
1489 mateusz.vi 339
DB "HU",  "T", 99h, "BB$"              ; TOBB with O-diaeresis (CP 852)
1486 mateusz.vi 340
DB "IT",  "PI", 0EBh, "$"              ; "PIU" with U-acute (CP 850)
1487 mateusz.vi 341
DB "LV",  "T", 0A0h, "L", 0A0h, "K$"   ; "TALAK" with A-makron (CP 775)
1486 mateusz.vi 342
DB "NL",  "MEER$"
1487 mateusz.vi 343
DB "NO",  "MER$"
1486 mateusz.vi 344
DB "PL",  "DALEJ$"
345
DB "RU",  84h,80h,8Bh,85h,85h,'$'      ; "DALEE" (CP 866)
346
DB "SL",  "VE", 0ACh, "$"              ; "VEC" with C-caron (CP 852)
347
DB "SV",  "MERA$"
348
DB "TR",  "DAHA FAZLA$"
349
DB, 0                                  ; LANGLIST terminator
1479 mateusz.vi 350
 
1484 mateusz.vi 351
; uninitialized area (must be defined last)
352
 
353
FHANDLE dw      ?                      ; file handle I read from (DUPed stdin)
354
 
1479 mateusz.vi 355
BUFFER: