-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcommandparser.asm
5509 lines (5234 loc) · 162 KB
/
commandparser.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; NAME msscmd
; File MSSCMD.ASM
include symboldefs.h
; Copyright (C) 1982, 1999, Trustees of Columbia University in the
; City of New York. The MS-DOS Kermit software may not be, in whole
; or in part, licensed or sold for profit as a software product itself,
; nor may it be included in or distributed with commercial products
; or otherwise distributed by commercial concerns to their clients
; or customers without written permission of the Office of Kermit
; Development and Distribution, Columbia University. This copyright
; notice must not be removed, altered, or obscured.
;
; Edit history
; 12 Jan 1995 version 3.14
; Last edit
; 12 Jan 1995
public comnd, comand, isdev, iseof, prompt, tolowr, toupr, valtab
public parstate, pardone, parfail, nparam, param, lparam, ninter
public inter, atparse, atpclr, atdispat, cspb, dspb, mprompt, nvaltoa
public savepoff, saveplen, keyboard, fwrtdir, cspb1, filetdate
public fqryenv, ifelse, oldifelse, retbuf, vfile
public rfprep, rgetfile, findkind, rfileptr, rpathname, rfilename
dos equ 21h
env equ 2CH ; environment address in psp
braceop equ 7bh ; opening curly brace
bracecl equ 7dh ; closing curly brace
; codes for various \fxxx(arg list) operations
F_char equ 1
F_code equ 2
F_contents equ 3
F_definition equ 4
;F_eval equ 5
F_exec equ 6
F_files equ 7
F_index equ 8
F_length equ 9
F_literal equ 10
F_lower equ 11
F_lpad equ 12
F_maximum equ 13
F_minimum equ 14
F_nextfile equ 15
F_repeat equ 16
F_reverse equ 17
F_right equ 18
F_rpad equ 19
F_substr equ 20
F_upper equ 21
F_date equ 22
F_size equ 23
F_replace equ 24
F_eval equ 25
F_rindex equ 26
F_verify equ 27
F_ipaddr equ 28
F_tod2secs equ 29
F_chksum equ 30
F_basename equ 31
F_directories equ 32
F_rfiles equ 33
F_rdirectories equ 34
; Constants for valtoa
V_environ equ 0
V_argc equ 1
V_carrier equ 22
V_charset equ 33
V_console equ 27
V_count equ 2
V_cmdlevel equ 29
V_cps equ 24
V_date equ 3
V_ndate equ 14
V_dir equ 5
V_dosver equ 19
V_errlev equ 4
V_kbd equ 10
V_line equ 15
V_monitor equ 28
V_parity equ 21
V_platform equ 8
V_port equ 15
V_program equ 12
V_prompt equ 23
V_query equ 31
V_session equ 17
V_tcpip equ 20
V_space equ 25
V_speed equ 11
V_startup equ 26
V_status equ 13
V_sysid equ 32
V_system equ 9
V_terminal equ 16
V_time equ 6
V_ntime equ 18
V_version equ 7
V_input equ 30
V_inpath equ 34
V_disk equ 35
V_cmdfile equ 36
V_inidir equ 37
V_instatus equ 38
V_minput equ 39
V_return equ 40
V_connection equ 41
V_filespec equ 42
V_fsize equ 43
V_crc16 equ 44
V_day equ 45
V_nday equ 46
; Like main filest, but shorter for local usage.
fileiost struc
mydta db 26 dup(0) ; DOS, 21 resev'd bytes, file attr, 2 each date & time
mysizelo dw 0 ; DOS, file size double word
mysizehi dw 0
filename db 13 dup(0) ; DOS, filename, asciiz, with dot. End of DOS section
fileiost ends
data segment
extrn flags:byte, taklev:byte, takadr:word, mcctab:byte
extrn kstatus:word, errlev:byte, psp:word, fsta:word
extrn portval:word, bdtab:byte, tdfmt:byte, machnam:byte
extrn verident:word, kstatus:word, errlev:byte, comptab:byte
extrn termtb:byte, dosnum:word, prmptr:word, startup:byte
extrn crt_mode:byte, tmpbuf:byte, buff:byte, minpcnt:word
extrn decbuf:byte, encbuf:byte, queryseg:word, inpath_seg:word
extrn cmdfile:byte, inidir:byte, dos_bottom:byte, marray:word
extrn input_status:word, domath_ptr:word, domath_cnt:word
extrn domath_msg:word, atoibyte:byte, atoi_err:byte, atoi_cnt:word
extrn crcword:word, lastfsize:dword
ifndef no_tcp
extrn sescur:word, tcp_status:word
endif ; no_tcp
; Start Patch structure. Must be first.
even
dspb dw code ; segment values for patcher
dw code1
dw code2
dw data
dw data1
dw _TEXT
db 64 dup (0) ; data segment patch buffer
; with space for other material, if req'd
; end of Patch structure
progm db 'MS-DOS_KERMIT$' ; for \v(program)
system db 'MS-DOS$' ; for \v(system)
keyboard dw 88 ; \v(keyboard) kind of keybd 88/101
ten db 10 ; for times ten
comand cmdinfo <>
cmer00 db cr,lf,'?Program internal error, recovering$'
cmer01 db cr,lf,'?More parameters are needed$'
cmer02 db cr,lf,'?Word "$'
cmer03 db '" is not usable here$'
cmer04 db '" is ambiguous$'
cmer07 db cr,lf,'?Ignoring extra characters "$'
cmer08 db '"$' ; "
cmer09 db cr,lf,'?Text exceeded available buffer capacity$'
cmin01 db ' Use one of the following words in this position:',cr,lf,'$'
stkmsg db cr,lf,bell,'?Exhausted work space! Circular definition?$'
moremsg db '... more, press a key to continue ...$'
crlf db cr,lf,'$'
ctcmsg db 5eh,'C$'
cmunk db 'unknown'
errflag db 0 ; non-zero to suppress cmcfrm errors
kwstat db 0 ; get-keyword status
subcnt db 0 ; count of chars matched in '\%'
subtype db 0 ; kind of sub (% or v)
evaltype dw 0 ; evaltoa kind
bracecnt db 0 ; curly brace counter
parencnt db 0 ; parenthesis counter
report_binary db 0 ; subst reporting \number directly
argptr dw 3 dup (0) ; \fxxx() argument pointers
arglen dw 3 dup (0) ; \fxxx() argument lengths
replay_cnt dw 0 ; report to app, no echo
replay_skip db 0 ; non-zero to skip subst for replays
retbuf db 130 dup (0) ; \v(return) buffer
vfile db 65 dup (0) ; \v(filespec) buffer
maxdepth equ 15 ; depth of directory search
fileio fileiost maxdepth dup(<>) ; find first/next support
rfileptr dw 0 ; pointer to search dta structure
rpathname db 64+1 dup (0) ; search path
rfilename db 8+3+1 dup (0) ; search filename
filecnt dw 0 ; count of files found
findkind db 0 ; find kind (1=file,2=dir,plus 4=recurse,0=nothing)
cmsflg db 0 ; Non-zero when last char was a space
cmkind db 0 ; command kind request (cmkey etc)
in_showprompt db 0 ; Non-zero when in showprompt
cmdbuf db cmdblen dup (0) ; Buffer for command parsing
db 0 ; safety for overflow
rawbuf db cmdblen dup (0) ; input, what user provided
db 0 ; safety for overflow
read_source db 0 ; channel whence we read
endedbackslash db 0
in_reparse db 0
even
cmdstk dw 0 ; stack pointer at comand call time
cmptab dw 0 ; Address of present keyword table
cmhlp dw 0 ; Address of present help
cmwptr dw 0 ; Pointer for next char write
cmrptr dw 0 ; Pointer for next char read
cmsiz dw 0 ; Size info of user input
cmsptr dw 0 ; Place to save a pointer
mcmprmp dw 0 ; master prompt, string address
mcmrprs dd 0 ; master prompt, reparse address
mcmostp dw 0 ; master prompt, stack pointer
temp dw 0 ; temp (counts char/line so far)
cmrawptr dw 0 ; non-substitution level, write ptr
ifndef no_tcp
valtab db 1+46 ; table of values for \v(value)
else
valtab db 1+46 - 2
endif ; no_tcp
mkeyw 'argc)',V_argc
mkeyw 'carrier)',V_carrier
mkeyw 'charset)',V_charset
mkeyw 'cmdfile)',V_cmdfile
mkeyw 'connection)',V_connection
mkeyw 'console)',V_console
mkeyw 'count)',V_count
mkeyw 'cmdlevel)',V_cmdlevel
mkeyw 'cps)',V_cps
mkeyw 'crc16)',V_crc16
mkeyw 'date)',V_date
mkeyw 'ndate)',V_ndate
mkeyw 'day)',V_day
mkeyw 'nday)',V_nday
mkeyw 'directory)',V_dir
mkeyw 'dosversion)',V_dosver
mkeyw 'disk)',V_disk
mkeyw 'errorlevel)',V_errlev
mkeyw 'filespec)',V_filespec
mkeyw 'fsize)',V_fsize
mkeyw 'inidir)',V_inidir
mkeyw 'inpath)',V_inpath
mkeyw 'input)',V_input
mkeyw 'instatus)',V_instatus
mkeyw 'keyboard)',V_kbd
mkeyw 'line)',V_port
mkeyw 'minput)',V_minput
mkeyw 'monitor)',V_monitor
mkeyw 'parity)',V_parity
mkeyw 'platform)',V_platform
mkeyw 'port)',V_port
mkeyw 'program)',V_program
mkeyw 'prompt)',V_prompt
mkeyw 'query)',V_query
mkeyw 'return)',V_return
ifndef no_tcp
mkeyw 'session)',V_session
mkeyw 'tcpip_status)',V_tcpip
endif ; no_tcp
mkeyw 'space)',V_space
mkeyw 'speed)',V_speed
mkeyw 'startup)',V_startup
mkeyw 'status)',V_status
mkeyw 'sysid)',V_sysid
mkeyw 'system)',V_system
mkeyw 'terminal)',V_terminal
mkeyw 'time)',V_time
mkeyw 'ntime)',V_ntime
mkeyw 'version)',V_version
evaltab db 32 ; \fverb(args)
mkeyw 'basename(',F_basename
mkeyw 'character(',F_char
mkeyw 'checksum(',F_chksum
mkeyw 'code(',F_code
mkeyw 'contents(',F_contents
mkeyw 'date(',F_date
mkeyw 'definition(',F_definition
mkeyw 'directories(',F_directories
mkeyw 'eval(',F_eval
mkeyw 'files(',F_files
mkeyw 'index(',F_index
mkeyw 'ipaddr(',F_ipaddr
mkeyw 'length(',F_length
mkeyw 'literal(',F_literal
mkeyw 'lower(',F_lower
mkeyw 'lpad(',F_lpad
mkeyw 'maximum(',F_maximum
mkeyw 'minimum(',F_minimum
mkeyw 'nextfile(',F_nextfile
mkeyw 'rindex(',F_rindex
mkeyw 'repeat(',F_repeat
mkeyw 'replace(',F_replace
mkeyw 'reverse(',F_reverse
mkeyw 'rdirectories(',F_rdirectories
mkeyw 'rfiles(',F_rfiles
mkeyw 'right(',F_right
mkeyw 'rpad(',F_rpad
mkeyw 'size(',F_size
mkeyw 'substr(',F_substr
mkeyw 'tod2secs(',F_tod2secs
mkeyw 'verify(',F_verify
mkeyw 'upper(',F_upper
; not implemented in MS-DOS Kermit
; mkeyw 'execute(',F_exec
envtab db 1 ; \$(..) Environment table
mkeyw 'An Environment variable)',0 ; reserve 0 in valtab
numtab db 1 ; \number help table
mkeyw 'a number such as \123',0
; table of Parity strings
parmsgtab dw parevnmsg,parmrkmsg,parnonmsg,paroddmsg,parspcmsg
parevnmsg db 'EVEN',0
parmrkmsg db 'MARK',0
parnonmsg db 'NONE',0
paroddmsg db 'ODD',0
parspcmsg db 'SPACE',0
onoffmsgtab dw offmsg,onmsg ; on/off table, asciiz
offmsg db 'OFF',0
onmsg db 'ON',0
ansiword db 'ANSI',0 ; \v(console) ASCIIZ strings
noneword db 'NONE',0
colormsg db 'COLOR',0 ; \v(monitor) ASCIIZ strings
monomsg db 'MONO',0
connmsg db 'local',0 ; \v(connection) state
valtmp dw 0
numtmp dw 0
even
envadr dd 0 ; seg:offset of a string in Environemt
envlen dw 0 ; length of envadr's string
even ; Control sequence storage area
maxparam equ 16 ; number of ESC and DCS Parameters
maxinter equ 16 ; number of ESC and DCS Intermediates
savepoff label word ; Start per session save area
parstate dw 0 ; parser state, init to startup
pardone dw 0 ; where to jmp after Final char seen
parfail dw 0 ; where to jmp if parser fails
nparam dw 0 ; number of received Parameters
param dw maxparam dup (0) ; Parameters for ESC
lparam db 0 ; a single letter Parameter for ESC
ninter dw 0 ; number of received Intermediates
inter db maxinter dup (0),0 ; Intermediates for ESC, + guard
saveplen dw ($-savepoff)
ifelse db 0 ; non-zero if last IF statement failed
oldifelse db 0 ; copy of ifelse from previous command
month db 'Jan ','Feb ','Mar ','Apr ','May ','Jun '
db 'Jul ','Aug ','Sep ','Oct ','Nov ','Dec '
day db 'Sun','Mon','Tue','Wed','Thu','Fri','Sat'
data ends
data1 segment
db 0 ; so error msg has non-zero offset
cmin00 db ' Press ENTER to execute command$'
f1hlp db ' number$'
f2hlp db ' char$'
f3hlp db ' variable or macro name$'
f8hlp db ' pattern-text, string, start-position$'
f9hlp db ' text$'
f12hlp db ' text, pad-length, pad-char$'
f15hlp db ' no argument$'
f16hlp db ' repeat-text, repeat-count$'
f18hlp db ' text, right-most count$'
f20hlp db ' text, start-position, substring len$'
f22hlp db ' filename$'
f24hlp db ' source, pattern, replacement$'
f25hlp db ' arithmetic expression$'
f30hlp db ' string$'
n1hlp db ' digits of a number whose value fits into one byte$'
data1 ends
ifndef no_terminal
ifndef no_tcp
_TEXT segment
extrn cpatch:far
_TEXT ends
endif ; no_tcp
endif ; no_terminal
code1 segment
assume cs:code1
extrn shovarcps:near, dskspace:far, fparse:far
extrn strlen:far, prtscr:far, strcpy:far, prtasz:far, strcat:far
extrn dec2di:far, decout:far, malloc:far, domath:far
extrn atoi:far, takrd:far, buflog:far, tod2secs:far
cspb1 equ this byte
db (256-($-cspb1)) dup (0) ; code1 segment patch buffer
; end of Patch area
code1 ends
code segment
extrn ctlu:near, cmblnk:near, locate:near
extrn takclos:far, docom:near, getenv:near
extrn getbaud:near, lnout:near, takopen_sub:far
extrn takopen_macro:far
assume cs:code, ds:data, es:nothing
; Patch area. Must be first in MSK's Code Seg
cspb equ this byte
dw seg code1
dw seg code2
dw seg data
dw seg data1
dw seg _TEXT
dw seg _DATA
ifndef no_terminal
ifndef no_tcp
dw offset cpatch
endif ; no_tcp
endif ; no_terminal
db (256-($-cspb)) dup (0) ; code segment patch buffer
; end of Patch area
fctlu proc far ; FAR callable versions of items in seg code
call ctlu ; for calling from code segment code1 below
ret
fctlu endp
fcmblnk proc far
call cmblnk
ret
fcmblnk endp
fgetbaud proc far
call getbaud
ret
fgetbaud endp
fgetenv proc far
call getenv
ret
fgetenv endp
flocate proc far
call locate
ret
flocate endp
fdec2di proc far
push cx
push ds
mov cx,es
mov ds,cx
call dec2di
pop ds
pop cx
ret
fdec2di endp
ftakclos proc far
call takclos
ret
ftakclos endp
nvaltoa proc near
push es
mov ax,ds
mov es,ax
call fvaltoa
pop es
ret
nvaltoa endp
flnout proc far
call lnout
ret
flnout endp
fdskspace proc far
call dskspace
ret
fdskspace endp
; This routine parses the specified function in AH. Any additional
; information is in DX and BX.
; Returns carry clear on success and carry set on failure
COMND PROC NEAR
mov cmdstk,sp ; save stack ptr for longjmp exit
mov bracecnt,0 ; curly brace counter
cmp ah,cmeol ; Parse a confirm?
jne cm2 ; nz = no
call cmcfrm ; get a Carriage Return end of line
ret
cm2: mov cmkind,ah ; remember for {} line continuation
cmp ah,cmkey ; Parse a keyword?
jne cm3 ; ne = no
xor al,al ; get a zero/clear
xchg al,ifelse ; get current ifelse state
mov oldifelse,al ; remember here (one cmd delay)
call cmkeyw ; get keyword
ret
cm3: cmp ah,cmline ; parse line of text
jne cm4
call cmtxt
ret
cm4: cmp ah,cmword ; parse arbitrary word
jne cm5
call cmtxt
ret
cm5: mov ah,prstr ; else give error
mov dx,offset cmer00 ; "?Program internal error"
int dos
jmp prserr ; reparse
; Control-C exit path (far to near)
cmexit label far
mov sp,cmdstk ; restore command entry stack pointer
stc
retn ; and fail immediately (a longjmp)
COMND ENDP
code ends
code1 segment
assume cs:code1
; This routine parses a keyword from the table pointed at by DX, help text
; point to by BX. Format of the table is as follows (use macro mkeyw):
; addr: db N ; Where N is the # of entries in the table
; dw M ; M is the size of the keyword
; db 'string' ; String is the keyword
; dw value ; Value is data to be returned
; Keywords may be in any order and in mixed case.
; Return is carry clear for success and carry set for failure.
; cmptab: pointer to keyword table (supplied by caller)
; cmhlp: pointer to help message (supplied by caller)
; cmsptr: pointer to current user word text
; cmsiz: length of user text, excluding terminator
; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed
; comand.cmwhite: non-zero allows leading whitespace for cmline and cmword,
; reset automatically at end of call
; cmwptr: buffer write pointer to next free byte
; cmrptr: buffer read pointer for next free byte
; comand.cmper: 0 to do \%x substitution. Set to 0 at end of call
; comand.impdo: non-zero permits keyword failure to retry as DO command, reset
; automatically at time of failure.
cmkeyw proc far
mov cmsiz,0 ; user word length
mov ax,cmrptr ; get command reading pointer
mov cmsptr,ax ; set pointer for start of user word
mov cmhlp,bx ; save the help pointer
mov cmptab,dx ; save the beginning of keyword table
mov bx,dx
cmp byte ptr[bx],0 ; get number of entries in table
jne cmky1
jmp cmky7 ; e = no keywords to check, error
cmky1: mov cmsflg,0ffh ; skip leading spaces/tabs
call cmgtch ; get char from the user into ah
jc cmky3 ; c = terminator
mov dx,cmrptr ; next byte to read
dec dx ; where we just read a char
mov cmsptr,dx ; remember start of keyword
inc cmsiz ; start counting user chars
cmky2: call cmgtch ; read until terminator
jc cmky3 ; c = terminator
inc cmsiz ; count user chars
jmp short cmky2 ; no terminator yet
cmky3: cmp ah,'?' ; need help?
jne cmky4 ; ne = no
call cmkyhlp ; display help
jmp repars
cmky4: cmp ah,escape ; escape?
jne cmky6 ; ne = no
call cmkyesc ; process escape
jc cmky5 ; c = failure (no unique keyword yet)
mov comand.cmper,0 ; reset to variable recognition
mov comand.cmkeep,0
mov comand.impdo,0 ; clear flag to prevent loops
mov comand.cmquiet,0 ; permit echoing again
mov comand.cmcnvkind,cmcnv_none ; default is no conversion
clc
ret ; return successfully to user
cmky5: cmp cmsiz,0 ; started a word yet?
je cmky1 ; e = no, ignore escape, keep looking
call cmkyhlp ; display help
jmp repars
cmky6: cmp cmsiz,0 ; length of user's text, empty?
je cmky7 ; e = yes, parse error
push bx
mov bx,cmsptr ; point at first user character
cmp byte ptr[bx],':' ; start of a label?
pop bx
jne cmky6a ; ne = no, return success
mov cmsiz,1 ; say just one byte
cmky6a: call getkw ; get unique kw, point to it with bx
jc cmky8 ; c = not found
add bx,[bx] ; add length of keyword text (CNT)
add bx,2 ; point at value field
mov bx,[bx] ; bx = return value following keyword
call optionclr ; clear parser options
mov errflag,0
clc
ret ; return successfully
; all other terminators come here
cmky7: cmp cmsiz,0 ; empty table or empty user's text?
jne cmky8 ; ne = no
cmp comand.cmcr,0 ; empty lines allowed?
jne cmky10 ; ne = yes, do not complain
push dx
mov ah,prstr
mov dx,offset cmer01 ; command word expected
int dos
pop dx
xor al,al
mov comand.cmquiet,al ; permit echoing again
mov comand.impdo,al ; clear flag to prevent loops
stc ; failure
ret
cmky8: cmp comand.impdo,0 ; failed here, ok to try Macro table?
je cmky8a ; e = no, use regular exit path
mov comand.impdo,0 ; yes, but clear flag to prevent loops
mov cmrptr,offset cmdbuf ; reinit read pointer
mov comand.cmquiet,1 ; suppress echoing of same keyword
mov bx,offset docom ; return DO as "found" keyword
clc
ret ; return success to invoke DO
cmky8a: cmp comand.cmswitch,0 ; looking for switch keyword?
je cmky8b ; e = no
mov comand.cmswitch,0
mov comand.impdo,0 ; yes, but clear flag to prevent loops
mov ax,cmsptr ; where keyword started in buffer
mov cmrptr,ax ; reread it again later
mov comand.cmquiet,1 ; suppress echoing of same keyword
stc ; return with no complaint
ret
cmky8b: mov errflag,1 ; say already doing error recovery
or kstatus,ksgen ; global command status, failure
mov comand.cmquiet,0 ; permit echoing again
call isdev ; reading pretyped lines?
jnc cmky9 ; nc = yes, consume rest of line
cmp taklev,0 ; in a Take file?
jne cmky9 ; ne = yes
call cmskw ; display offending keyword
mov comand.impdo,0 ; clear flag to prevent loops
dec cmrptr ; interactive, backup to terminator
mov bx,cmrptr ; look at it
cmp byte ptr [bx],' ' ; got here on space terminator?
jne cmky10 ; ne = no, (cr,lf,ff) exit failure
mov ah,prstr ; start a fresh line
mov dx,offset crlf
int dos
call bufdel ; cut back buffer to last good char
jmp repars ; reparse interactive lines
cmky9: call cmcfrm ; get formal end of command line
; to maintain illusion of typeahead
; and let user backspace to correct
; mistakes (we reparse everything)
call cmskw ; display offending keyword
cmky10: mov comand.cmquiet,0 ; permit echoing again
stc ; say failure
ret
cmkeyw endp
;;;;;; start support routines for keyword parsing.
cmkyesc proc near ; deal with escape terminator
push cmrptr ; points at ESC
pop cmwptr ; pointed one byte beyond ESC
cmp cmsiz,0 ; user word length, empty?
jne cmkye2 ; ne = have user text, else complain
cmkye1: call esceoc ; do normal escape end-of-command
stc ; say failure to fill out word
ret
; add unique keyword to buffer
cmkye2: call getkw ; is there a matching keyword?
jc cmkye1 ; c = ambiguous or not found
push bx ; unique, bx points to structure
push si
mov cx,[bx] ; length of keyword
add bx,2 ; point to first letter
dec cmrawptr ; overwrite ESC
mov si,cmrawptr ; where raw writes go
mov dx,cmsiz ; length of user word
add bx,dx ; add chars known so far
sub cx,dx ; calculate number yet to add
jcxz cmkye4 ; z = none
cmkye3: mov al,[bx] ; get a keyword letter
inc bx
call tolowr ; lowercase
mov [si],al ; store it
inc si
loop cmkye3 ; do all new chars
cmkye4: mov word ptr [si],' ' ; add trailing space, clear old next
inc si
mov cmrawptr,si
pop si
pop bx ; bx = keyword structure
inc cmrawptr ; bufdel backs up one char
jmp bufdel
cmkyesc endp
esceoc proc near ; do normal escape end-of-command
push ax
push dx
mov ah,conout ; ring the bell
mov dl,bell
int dos
pop dx
pop ax
call bufreset ; reset buffer
stc ; say error condition
ret
esceoc endp
; Help. Question mark entered by user. Display all the keywords that match
; user text. If text is null then use external help if available; otherwise,
; display all keywords in the table. Removes question mark from buffer and
; invokes reparse of command line to-date. User word starts at cmsptr and
; is cmsiz bytes long.
cmkyhlp proc near
xor cx,cx ; clear number of keyword (none yet)
cmp cmsiz,0 ; user text given?
jne cmkyh1 ; ne = yes, use matching keywords
cmp cmhlp,0 ; external help given?
jne cmkyh6 ; yes, use it instead of full table
cmkyh1: mov temp,0 ; count # chars printed on this line
mov bx,cmptab ; beginning of kw table
mov ch,[bx] ; length of table
xor cl,cl ; no keywords or help displayed yet
inc bx ; point at CNT field
cmkyh2: cmp cmsiz,0 ; length of user word
je cmkyh3 ; e = null, use full table
call cmpwrd ; compare keyword with user word
jc cmkyh5 ; c = no match, get another keyword
cmkyh3: mov ax,[bx] ; length of table keyword
add byte ptr temp,al ; count chars printed so far
cmp temp,76 ; will this take us beyond column 78?
jbe cmkyh4 ; be = no, line has more room
mov byte ptr temp,al ; reset the count
mov ah,prstr
mov dx,offset crlf ; break the line
int dos
cmkyh4: or cl,cl ; any keywords found yet?
jnz cmkyh4a ; nz = yes
mov dx,offset cmin01 ; start with One of the following: msg
mov ah,prstr
int dos
inc cl ; say one keyword has been found
cmkyh4a:mov dl,spc ; put two spaces before each keyword
mov ah,conout
int dos
int dos
add temp,2 ; count output chars
mov di,bx ; get current keyword structure
add di,2 ; text part
push cx
mov cx,[bx] ; string length to cx, offset to di
call prtscr ; display counted string
pop cx
cmkyh5: dec ch ; are we at end of table?
jle cmkyh7 ; le = yes, quit now
add bx,[bx] ; next keyword, add CNT chars to bx
add bx,4 ; skip CNT and 16 bit value
jmp cmkyh2 ; go examine this keyword
cmkyh6: mov si,cmhlp ; external help text in seg data1
xor bx,bx ; line counter
push es
mov ax,seg data1 ; all help text is in data1
mov es,ax
cld
cmkyh10:mov al,es:[si] ; read a help msg byte
inc si
cmp al,'$' ; end of message?
je cmkyh14 ; e = yes, stop
cmkyh11:mov ah,conout
mov dl,al
int dos ; display byte
cmp dl,LF ; line break?
jne cmkyh10 ; ne = no
inc bl ; count line
cmp bl,dos_bottom ; (24) time for a more msg?
jbe cmkyh10 ; be = not yet
xor bl,bl ; reset line count
call iseof ; are we at EOF, such as from disk?
jc cmkyh10 ; c = yes, ignore more msg
mov ah,prstr
mov dx,offset moremsg ; "... more..." msg
int dos
cmkyh13:mov ah,coninq ; read the char from file, not device
int dos
cmp al,3 ; a ^C?
je short cmkyh14 ; e = yes, stop the display
push bx ; save line counter
push es ; and read pointer
push si
call fctlu ; clear display's line, reuse it
pop si
pop es
pop bx
jmp short cmkyh10 ; continue
cmkyh14:pop es
inc cl ; say gave help already
cmkyh7: or cl,cl ; found any keywords?
jnz cmkyh9 ; nz = yes
mov cx,cmsiz ; length of word
or cx,cx
jg cmkyh8 ; g = something to show
push dx
mov ah,prstr
mov dx,offset cmer01 ; command word expected
int dos
pop dx
jmp prserr
cmkyh8: mov kwstat,0 ; set keyword not-found status
call cmskw ; display offending keyword
cmkyh9: mov ah,prstr ; start a fresh line
mov dx,offset crlf
int dos
call bufdel ; unwrite the "?" (cmrptr is there)
ret
cmkyhlp endp
; See if keyword is ambiguous or not from what the user has typed in.
; Return carry set if word is ambiguous or not found, carry clear otherwise.
; Uses table pointed at by cmptab, user text pointed at by cmsptr and length
; in cmsiz.
cmambg proc near
push bx
push cx
push dx
xor dl,dl ; count keyword matches so far
mov bx,cmptab ; look at start of keyword table
mov cl,[bx] ; get number of entries in table
xor ch,ch ; use cx as a counter
jcxz cmamb8 ; z = no table so always ambiguous
inc bx ; look at CNT byte of keyword
cmamb4: call cmpwrd ; user vs table words, same?
jc cmamb6 ; c = no match
inc dl ; count this as a match
cmp dl,1 ; more than one match?
ja cmamb8 ; a = yes, quit now
cmamb6: add bx,[bx] ; add CNT chars to bx
add bx,4 ; skip CNT and 16 bit value
loop cmamb4 ; do rest of keyword table
cmp dl,1 ; how many matches were found?
jne cmamb8 ; ne = none or more than 1: ambiguous
pop dx ; restore main registers
pop cx
pop bx
clc
ret ; ret = not ambiguous
cmamb8: pop dx ; restore main registers
pop cx
pop bx
stc
ret ; return ambiguous or not found
cmambg endp
; Compare user text with keyword, abbreviations are considered a match.
; Enter with bx pointing at keyword table CNT field for a keyword.
; Return carry clear if they match, set if they do not match. User text
; pointed at by cmsptr and length is in cmsiz.
; Registers preserved.
cmpwrd proc near
push cx
mov cx,cmsiz ; length of user's text
jcxz cmpwrd2 ; z: null user word matches no keyword
cmp cx,[bx] ; user's text longer than keyword?
ja cmpwrd2 ; a = yes, no match
push ax
push bx
push si
add bx,2 ; point at table's keyword text
mov si,cmsptr ; buffer ptr to user input
cld
cmpwrd1:lodsb ; user text
mov ah,[bx] ; keyword text
inc bx ; next keyword letter
call tolowr ; force lower case on both chars
cmp ah,al ; same?
loope cmpwrd1 ; e = same so far
pop si
pop bx
pop ax
jne cmpwrd2 ; ne = mismatch
pop cx ; recover keyword counter
clc ; they match
ret
cmpwrd2:pop cx ; recover keyword counter
stc ; they do not match
ret
cmpwrd endp
; Get pointer to keyword structure using user text. Uses keyword table
; pointed at by cmptab and cmsiz holding length of user's keyword (cmpwrd
; needs cmsptr pointing at user's keyword and length of cmsiz).
; Structure pointer returned in BX.
; Return carry clear for success and carry set for failure. Modifies BX.
getkw proc near
push cx
mov kwstat,0 ; keyword status, set to not-found
cmp cmsiz,0 ; length of user word, empty?
je getkw3 ; e = yes, fail
mov bx,cmptab ; table of keywords
mov cl,[bx] ; number of keywords in table
xor ch,ch
jcxz getkw3 ; z = none, fail
inc bx ; point to first
getkw1: call cmpwrd ; compare user vs table words
jc getkw2 ; c = failed to match word, try next
mov kwstat,1 ; say found one keyword, maybe more
push dx
mov dx,cmsiz ; users word length
cmp [bx],dx ; same length (end of keyword)?
pop dx
je getkw4 ; e = yes, exact match. Done
call cmambg ; ambiguous?
jnc getkw4 ; nc = unique, done, return with bx
mov kwstat,2 ; say more than one such keyword
getkw2: add bx,[bx] ; next keyword, add CNT chars to bx
add bx,4 ; skip CNT and 16 bit value
loop getkw1 ; do all, exhaustion = failure
getkw3: pop cx
stc ; return failure
ret
getkw4: pop cx
clc ; return success
ret
getkw endp
; show offending keyword message. Cmsptr points to user word,
; cmsiz has length. Modifies AX, CX, and DX.
cmskw proc near
cmp comand.cmquiet,0 ; Quiet mode?
je cmskw0 ; e = no, regular mode
ret ; else say nothing
cmskw0: mov ah,prstr ; not one of the above terminators
mov dx,offset cmer02 ; '?Word "'
int dos
mov ah,conout
mov cx,cmsiz ; length of word
jcxz cmskw3 ; z = null
mov ah,conout
push si
mov si,cmsptr ; point to word
cld
cmskw1: lodsb
cmp al,' ' ; control code?
jae cmskw2 ; ae = no
push ax
mov dl,5eh ; caret
int dos
pop ax
add al,'A'-1 ; plus ascii bias
cmskw2: mov dl,al ; display chars in word
int dos
loop cmskw1
pop si
cmskw3: mov dx,offset cmer03 ; '" not usable here.'
cmp kwstat,1 ; kywd status from getkw, not found?
jb cmskw4 ; b = not found, a = ambiguous
mov dx,offset cmer04 ; '" ambiguous'
cmskw4: mov ah,prstr
int dos
ret
cmskw endp
;;;;;;;;;; end of support routines for keyword parsing.
; CMLINE: Parse arbitrary text up to a CR.
; CMWORD: Parse text up to first trailing space, or if starts with ()
; then consume the line.
; Enter with BX = pointer to output buffer
; DX pointing to help text. Produces asciiz string. Return updated pointer in
; BX and output size in AX. Leading spaces are omitted unless comand.cmwhite
; is non-zero (cleared upon exit). It does not need to be followed by the
; usual call to confirm the line. Byte comand.cmblen can be used to specify
; the length of the caller's buffer; cleared to zero by this command to
; imply a length of 127 bytes (default) and if zero at startup use 127 bytes.
; If the line starts with an opening curly brace, then physical lines are
; automatically continued until the closing curly brace is obtained.
; Continuation breaks are a comma in the data stream and a CR/LF to the
; visual screen. Material after the closing brace is discarded.
;
; Lines and words starting on a curly brace and ending on a matching
; curly brace plus optional whitespace have the trailing whitespace
; omitted and both outer braces removed.
cmtxt proc far
mov cmptab,bx ; save pointer to data buffer
xor ax,ax
mov word ptr [bx],ax ; clear result buffer
mov cmhlp,dx ; save the help message
mov cmsiz,ax ; init the char count
mov parencnt,al ; clear count of parentheses
cmp comand.cmblen,ax ; length of user's buffer given?