Subversion Repositories SvarDOS

Rev

Rev 1496 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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