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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
|
title DOS FIND Utility
; 0
;********************************************************************
;*
;* UTILITY NAME: find.exe
;*
;* SOURCE FILE NAME: find.asm
;*
;* STATUS: Find utility, DOS Version 4.0
;*
;* SYNTAX (Command line)
;*
;* FIND [/V][/C][/N] "string" [[d:][path]filename[.ext]...]
;*
;* where:
;*
;* /V - Display all lines NOT containing the string
;* /C - Display only a count of lines containing string
;* /N - Display number of line containing string
;*
;*
;* UTILITY FUNCTION:
;*
;* Searches the specified file(s) looking for the string the user
;* entered from the command line. If file name(s) are specifeied,
;* those names are displayed, and if the string is found, then the
;* entire line containing that string will be displayed. Optional
;* parameters modify that behavior and are described above. String
;* arguments have to be enclosed in double quotes. (Two double quotes
;* if a double quote is to be included). Only one string argument is
;* presently allowed. The maximum line size is determined by buffer
;* size. Bigger lines will bomb the program. If no file name is given
;* then it will asssume the input is coming from the standard Input.
;* No errors are reported when reading from standard Input.
;*
;*
;* EXIT:
;* The program returns errorlevel:
;* 0 - OK, and some matches
;* 1 -
;* 2 - Some Error
;*
;*
;* Revision History:
;*
;* V1.1 8/23/82 M.A.U. (Microsoft)
;*
;* V1.2 9/22/82 M.A.U. (Microsoft)
;* Added the -c and -n options
;*
;* 9/23/82 M.A.U. (Microsoft)
;* Added DOS version number control
;*
;* 10/07/82 Rev.2 M.A.U. (Microsoft)
;* Changed quote for double quotes, and added
;* file name printing
;*
;* 10/20/82 Rev.3 M.A.U. (Microsoft)
;* Modified IBM name to FIND, and changed the text
;* of some messages.
;*
;* 10/25/82 Rev.4 M.A.U. (Microsoft)
;* Changed name to FIND and all messages to the
;* IBM form.
;*
;* 10/27/82 Rev.5 M.A.U. (Microsoft)
;* Made the correct exit on version check in case
;* of a 1.x DOS.
;*
;* 11/4/82 Rev. 5 A.R. Reynolds (Microsoft)
;* Messages moved to external module
;*
;* 11/10/82 Rev. 6 M.A. U. (Microsoft)
;* Corrected problem with line numbers, and a problem
;* with seeking for 0 chars.
;*
;* 03/30/83 Rev. 7 M.A. U. (Microsoft)
;* Added patch area for bug fixing.
;*
;* 04/14/83 Rev. 8 M.A. U. (Microsoft)
;* Made changes for Kanji characters. (ugh!)
;*
;* 12/17/84 Rev. 9 Zibo (Microsoft)
;* Fix boundary case for buffer containing exact line
;*
;* V4.0 : 6/29/87 Russ W (IBM)
;* Lines commented with ;AN000;
;* Add support for IBM Parse service routines
;* Add support for IBM Message Retriever Service Routines
;* Add support for Code Page File Tags
;* Made PROCs out of all labels that were targets of a call (not commented with AN000)
;* Removed patch area for "bug fixing"
;*
;* V4.0 : 9/15/87 Bill L, (IBM)
;* ;AN001; = DCR 201, changes to extended attributes support
;* ;AN002; = PTM 1090
;* ;AN003; = DCR 191
;* ;AN004; = PTM 1630
;* ;AN005; = PTM 1643, PTM 1675, PTM 1754
;* ;AN006; = DBCS support
;* ;AN007; = Optimizations to save disk space on ship diskettes
;*
;**********************************************************************
;--------------------------
;- MACRO DEFINITIONS
;--------------------------
BREAK MACRO subtitle
SUBTTL subtitle
PAGE
ENDM
;---------------------------;
;- INCLUDE FILES ;
;---------------------------;
.xlist ;
.xcref ;
INCLUDE SYSCALL.INC ;
INCLUDE sysmsg.inc ; ;AN000; Include message equates and MACROS
INCLUDE find.inc ; ;AN000; Include find equates and MACROS
.list ;
.cref ;
;---------------------------;
MSG_UTILNAME <FIND> ;AN000;
;--------------------------
;- EQUATES
;--------------------------
FALSE equ 0
TRUE equ NOT FALSE
CR equ 0dh ;A Carriage Return
LF equ 0ah ;A Line Feed
quote_char equ 22h ;A double quote character
buffer_size equ 4096 ;file buffer size
st_buf_size equ 128 ;string arg. buffer size
fname_buf_size equ 64 ;file name buffer size
;----- DOS EQUATES -----;
STDIN equ 0 ;AN000; Handle
STDOUT equ 1 ;AN000; Handle
STDERR equ 2 ;AN000; Handle
GetCPSW equ 03303h ;AN000; Int 021h function call
GetExtAttr equ 05702h ;AN000; Int 021h function call
SetExtAttr equ 05704h ;AN000; Int 021h function call
ERROR_ACCESS_DENIED equ 5 ;AN000; Int 021h error return
CPSWActive equ 1 ;AN000; Indicates Code Page support is active
CPSWNotActive equ 0 ;AN000; Just the opposite
ERRORLEVEL_ZERO equ 0 ;AN000; Termination error level
ERRORLEVEL_ONE equ 1 ;AN000; Termination error level
ERRORLEVEL_TWO equ 2 ;AN000; Termination error level
;------------------------
;- MESSAGE EQUATES
;------------------------
msg_file_not_found equ 2 ;AN000; File not found %s
msg_access_denied equ 5 ;AN000; Access denied %s
msg_read_error equ 30 ;AN000; Read error in %s
msg_inv_num_parm equ 2 ;AN000; Invalid number of parameters
msg_inv_parm equ 10 ;AN000; Invalid Parameter %s
msg_required_missing equ 2 ;AN005; Required parameter missing
msg_find equ 4 ;AN000; FIND:
msg_code_page_mismatch equ 37 ;AN005; Code Page mismatch
msg_switch equ 3 ;AN005; Invalid switch
;-----------------------
;-- Parser equates
;-----------------------
FarSW equ 0 ;AN000;
DateSW equ 0 ;AN000;
TimeSW equ 0 ;AN000;
FileSW equ 1 ;AN000;
CAPSW equ 1 ;AN000;
CmpxSW equ 0 ;AN000;
DrvSW equ 0 ;AN000;
QusSW equ 1 ;AN000;
NumSW equ 0 ;AN000;
KeySW equ 0 ;AN000;
SwSW equ 1 ;AN000;
Val1SW equ 0 ;AN000;
Val2SW equ 0 ;AN000;
Val3SW equ 0 ;AN000;
;------------------------
; SUBLIST Equates
;------------------------
Left_Align equ 0 ;AN000; 00xxxxxx
Right_Align equ 80h ;AN000; 10xxxxxx
Char_Field_Char equ 0 ;AN000; a0000000
Char_Field_ASCIIZ equ 10h ;AN000; a0010000
Unsgn_Bin_Byte equ 11h ;AN000; a0010001 - Unsigned Binary to Decimal character
Unsgn_Bin_Word equ 21h ;AN000; a0100001
Unsgn_Bin_DWord equ 31h ;AN000; a0110001
Sgn_Bin_Byte equ 12h ;AN000; a0010010 - Signed Binary to Decimal character
Sgn_Bin_Word equ 22h ;AN000; a0100010
Sgn_Bin_DWord equ 32h ;AN000; a0110010
Bin_Hex_Byte equ 13h ;AN000; a0010011 - Unsigned Binary to Hexidecimal character
Bin_Hex_Word equ 23h ;AN000; a0100011
Bin_Hex_DWord equ 33h ;AN000; a0110011
;------------------------------
; EXTENDED ATTRIBUTE Equates
;------------------------------
File_Type_None equ 00000000b ;AN001; unspecified file type
File_Type_Text equ 00100000b ;AN001; ASCII text file
File_Type_Rtl equ 00100001b ;AN001; ASCII text file in RTL
EAISBINARY equ 02h ;AN001; ea_type
EASYSTEM equ 8000h ;AN001; ea_flags
;---------------------------------------
;-------------- CODE SEGMENT -----------
;---------------------------------------
code segment public
assume cs:code
assume ds:nothing
assume es:nothing
assume ss:stack
jmp start
;
;--------------------
.xlist
.xcref
INCLUDE parse.asm
.list
.cref
;--------------------
EXTRN heading:byte,heading_len:byte
;*********************************
;* Extended Attribute Structures *
;*********************************
querylist struc ;AN001; ;query general list
qea_num dw 1 ;AN001;
qea_type db EAISBINARY ;AN001;
qea_flags dw EASYSTEM ;AN001;
qea_namelen db ? ;AN001;
qea_name db " " ;AN001;
querylist ends ;AN001;
cp_qlist querylist <1,EAISBINARY,EASYSTEM,2,"CP"> ;AN001; ;query code page attr.
cp_list label word ;AN001; ;code page attr. get/set list
dw 1 ;AN001; ; # of list entries
db EAISBINARY ;AN001; ; ea type
dw EASYSTEM ;AN001; ; ea flags
db ? ;AN001; ; ea return code
db 2 ;AN001; ; ea name length
dw 2 ;AN001; ; ea value length
db "CP" ;AN001; ; ea name
cp dw ? ;AN001; ; ea value (code page)
cp_len equ ($ - cp_list) ;AN001;
;-------Save area for Code Pages
src_cp dw ? ;AN000; Save area for source code page
tgt_cp dw ? ;AN000; Save area for target code page
str_cp dw ? ;AN005; Save area for search string code page
;-----------------------
;----- Misc Data ------
bufferDB db 6 dup(0) ;AN006;
dbcs_off dw 0 ;AN006;
dbcs_seg dw 0 ;AN006;
dbcs_len dw 0 ;AN006;
ccolon db ": "
n1_buf db "["
n2_buf db 8 dup(0) ;buffer for number conversion
errlevel db ERRORLEVEL_ZERO ;AN000; Errrorlevel save area
;----- OPTION FLAGS ----
; If a flag is set (0ffh) then the option has been selected, if
;reset (0) then it has been not. All options are reset initially.
; NOTE: the order of this table has to remain consistent with the
;options dispatch code. If any changes are made they have to
;correspond with the code.
opt_tbl:
v_flag db FALSE ;AN000; Set to FALSE
c_flag db FALSE ;AN000; Set to FALSE
n_flag db FALSE ;AN000; Set to FALSE
;----- LINE COUNTERS
mtch_cntr dw 0 ;matched lines counter
line_cntr dw 0 ;line counter
;-------------------------------------------
;- MESSAGE RETRIEVER SUBSTITUTION LIST
;-------------------------------------------
MSG_SERVICES <MSGDATA> ;AN000;
sublist label dword ;AN000;
sl_size db 11 ;AN000; SUBLIST Size, in bytes
sl_res db 0 ;AN000; reserved
sl_ptr_o dw ? ;AN000; Offset PTR to data item
sl_ptr_s dw ? ;AN000; Segment PTR to data item
sl_n db 0 ;AN000; n of %n
sl_flag db ? ;AN000; Data-Type flags
sl_maxw db 0 ;AN000; Max width
sl_minw db 0 ;AN000; Min width
sl_pad db ' ' ;AN000; Pad character
parm db ? ;AN000; Save area for invalid parm
cpsw_state db CPSWNotActive ;AN000; Save area indicating state of Code Page Support
;******************************************************************************
;* PARSER DATA STRUCTURES FOLLOW
;******************************************************************************
parms label byte ;AN000;
dw parmsx ;AN000; POINTER TO PARMS STRUCURE
db 1 ;AN000; DELIMITER LIST FOLLOWS
db 1 ;AN000; NUMBER OF ADDITIONAL DELIMITERS
db ";" ;AN000; ADDITIONAL DELIMITER
parms1 label byte ;AN005;
dw parmsx1 ;AN005; POINTER TO PARMS STRUCURE
db 1 ;AN005; DELIMITER LIST FOLLOWS
db 1 ;AN005; NUMBER OF ADDITIONAL DELIMITERS
db ";" ;AN005; ADDITIONAL DELIMITER
;------------------------------
;- STRUCTURE TO DEFINE FIND SYNTAX REQUIREMENTS
;------------------------------
parmsx label word ;AN000;
db 1,2 ;AN000; THERE ARE BETWEEN 1 AND 2 POSITIONAL PARMS
dw pos1 ;AN000; POINTER TO POSITIONAL DEFINITION AREA
dw pos2 ;AN000; POINTER TO POSITIONAL DEFINITION AREA
db 1 ;AN000; THERE IS 1 SWITCH DEF AREA FOR "/V, /C, AND /N"
dw sw1 ;AN000; POINTER TO FIRST SWITCH DEFINITION AREA
dw 0 ;AN000; THERE ARE NO KEYWORDS IN FIND SYNTAX
parmsx1 label word ;AN005;
db 0,0 ;AN005; THERE ARE BETWEEN 1 AND 2 POSITIONAL PARMS
db 1 ;AN005; THERE IS 1 SWITCH DEF AREA FOR "/V, /C, AND /N"
dw sw1 ;AN005; POINTER TO FIRST SWITCH DEFINITION AREA
dw 0 ;AN005; THERE ARE NO KEYWORDS IN FIND SYNTAX
;------------------------------
;- STRUCTURE TO DEFINE POSITIONAL PARM
;------------------------------
pos1 label word ;AN000;
dw 0080h ;AN000; QUOTED STRING, REQUIRED
dw 0000h ;AN000; NO CAPITALIZE
dw ret_buff ;AN000; PLACE RESULT IN RET_BUFF
dw novals ;AN000; NO VALUE LIST
db 0 ;AN000; NO KEYWORDS
;------------------------------
;- STRUCTURE TO DEFINE POSITIONAL PARM
;------------------------------
pos2 label word ;AN000;
dw 0203h ;AN000; FILE NAME, OPTIONAL, REPEATS ALLOWED
dw 0001h ;AN000; CAPITALIZE BY FILE TABLE
dw ret_buff ;AN000; PLACE RESULT IN RET_BUFF
dw novals ;AN000; NO VALUE LIST
db 0 ;AN000; NO KEYWORDS
;------------------------------
;- STRUCTURE TO DEFINE THE SWITCHES
;------------------------------
sw1 label word ;AN000;
dw 0 ;AN000; NO MATCH FLAGS
dw 2 ;AN005; capitalize
dw ret_buff ;AN000; PLACE RESULT IN RET_BUFF
dw novals ;AN000; NO VALUE LIST
db 3 ;AN000; THREE SWITCHES IN FOLLOWING LIST
n_swch db "/N",0 ;AN000;
v_swch db "/V",0 ;AN000;
c_swch db "/C",0 ;AN000;
;------------------------------
;- VALUE LIST DEFINITION FOR NO VALUES
;------------------------------
novals label word ;AN000;
db 0 ;AN000; VALUE LIST
;------------------------------
;- RETURN BUFFER FOR POSITIONAL PARAMETERS
;------------------------------
ret_buff label word ;AN000;
rb_type db ? ;AN000; TYPE RETURNED
rb_item_tag db ? ;AN000; SPACE FOR ITEM TAG
rb_synonym dw ? ;AN000; ES:rb_synonym points to synonym
rb_value_lo dw ? ;AN000; SPACE FOR VALUE
rb_value_hi dw ? ;AN000; SPACE FOR VALUE
did_file db FALSE ;AN004; if true then already processed a file
got_eol db FALSE ;AN004; if false then possibly more filenames on command line
got_filename db FALSE ;AN004; if true then parser found a filename on command line
got_srch_str db FALSE ;AN000; if true then parser found search string on command line
ordinal dw 0 ;AN000; parser ordinal
crlf db CR,LF ;AN000;
;
;************************************************************
;*
;* SUBROUTINE NAME: main
;*
;* SUBROUTINE FUNCTION:
;* Process the command line. If there are no errors, then open
;* the specified files, search for string, display it to the
;* standard output device.
;*
;* INPUT: Command line (described in program header)
;*
;* OUTPUT:
;* Files will be opened and read in. Regardless of the command
;* line parameters entered by the user, output will be written
;* to the standard output device handle 1.
;*
;* NORMAL EXIT:
;* File(s) opened (if not STDIN), read successfully, and closed.
;* Display requested information.
;*
;* ERROR CONDITIONS:
;* Incorrect DOS version
;* Invalid number of parameters
;* Syntax error
;* Access denied
;* File not found
;* Invalid Parameter
;* Read error in
;*
;* INTERNAL REFERENCES:
;* bin2asc
;* clr_cntrs
;* is_prefix
;* next_kchar
;* print_count
;* prout
;* prt_err
;* prt_err_2
;* prt_file_name
;* prt_lcntr
;*
;**************************************************************************
MSG_SERVICES <FIND.ctl,FIND.cla,FIND.cl1,FIND.cl2> ;AN000;
MSG_SERVICES <DISPLAYmsg,LOADmsg,CHARmsg,NOCHECKSTDIN> ;AN003; Make retriever services available
START:
mov ax,cs ;load ES to the right area,
mov es,ax ;
mov ds,ax ;
call sysloadmsg ;AN000; Preload messages, Check DOS Version.
jnc Set_for_parse ;AN000; If no error, parse command line
call prt_find ;AN005;
call sysdispmsg ;AN005;
mov ah,Exit ;AN000; Terminate new way
mov al,0 ;AN000; Errorlevel 0 (Compatible!)
int 021h ;AN000; Bye bye!
;-----------------------------------
;- DOS version is ok. Parse cmd line
;-----------------------------------
Set_for_parse:
call get_dbcs_vector ;AN006; ;Get DOS dbcs table vector
;
mov ah,GetCurrentPSP ;AN000; Get PSP address, returned in BX
int 021h ;AN000;
mov ds,bx ;AN000; Put PSP Seg in DS
mov si,081h ;AN000; Offset of command line in PSP
xor cx,cx ;AN000; Number of args processed so far = 0
mov cs:ordinal,cx ;AN000; init parser ordinal
;--------------------------------------
; See if there was nothing entered
;--------------------------------------
cmp byte ptr ds:080h,0 ;AN000; Check length of command line,
jne p_parse ;AN005; Go process the parameters
mov ax,msg_inv_num_parm ;AN000; No parms, too bad!
mov dh,2 ;AN005; message class
call display_and_die ;AN000; Tell the unfortunate user
p_parse:
mov cs:got_filename,FALSE ;AN004; input file default is STDIN
push cs ;A0005; ensure es is correct
pop es ;AN005;
call clr_cntrs ;AN005; set all counters to zero
mov cx,cs:ordinal ;AN005; init parser ordinal
call pre_parse ;AN005;
PARSER:
push cs ;A0000; ensure es is correct
pop es
call clr_cntrs ; set all counters to zero
mov cx,cs:ordinal ;AN000; init parser ordinal
call parse ;AN000; Parse command line
push si ;AN000; Save ptr to remaining command line
push ds
push cs ;Load new DS with CS
pop ds
mov cs:ordinal,cx ;AN000; Save parser ordinal
;---------------------
; get filespec size
;---------------------
mov cs:file_name_buf,di ;save buffer offset from parser
xor bx,bx ;AN000;indicate no save again
call get_length ;AN000;get filespec length
mov es:file_name_len,ax ;save the name length
;---------------------
;- Check current state of CPSW
;---------------------
save_src_cp:
mov ax,GetCPSW ;AN000; Get CPSW state, assume support is OFF
int 021h ;AN000; DL: 0=NotSupported,1=Supported
jc open_read ;AN000; If error, assume CPSW inactive
mov cs:cpsw_state,dl ;AN000; Save current state
and dl,dl ;AN007; ;AN000; If inactive, (same as CMP dl,0)
je open_read ;AN000; do nothing
;-------Code Page Switching is loaded and active!
;-------Save codepage of target handle ----------
mov bx,STDOUT ;AN000; For Standard output device
call get_cp ;AN000; Get the current codepage
jc open_read ;AN000; Error condition
mov ax,cs:cp ;AN000; Save target code page
mov cs:tgt_cp,ax ;AN000; for later reference
xor bx,bx ;AN007; ;AN005; bx=STDIN. For search string
call get_cp ;AN005; Get the code page
jc open_read ;AN005; Error condition
mov ax,cs:cp ;AN005; Save code page value
mov cs:str_cp,ax ;AN005; ..
;---------------------
;- OPEN FILE FOR READING
;---------------------
open_read:
push cs ;Load new DS with CS
pop ds
cmp cs:got_filename,TRUE ;AN004; using STDIN
je o_cont ;AN004; no, open the file
xor ax,ax ;AN007; ;AN004; file handle (ax) = STDIN
jmp short cp_check ;AN007; ;AN004; skip open of file
o_cont: ;AN004;
mov dx,cs:file_name_buf ;AC000;addrss. of the file name
openit:
mov ah,open
mov al,0 ;file open for reading
int 021h ;call the DOS
ljc do_open_error ;AN000;
;-------Open was successful. Make sure codepages are the same
cp_check:
cmp cs:cpsw_state,CPSWNotActive ;AN000; Is Code Page support active
je say_name ;AN000; No, continue
push ax ;AN000; Save source handle
mov bx,ax ;AN000; Source handle in BX
call get_cp ;AN000; Get codepage of source file
mov ax,cs:cp ;AN000; Place source CP in ax
cmp ax,cs:str_cp ;AN005; search string code page = src file code page ?
je c_cont ;AN005; yes, they are the same, ok
and ax,ax ;AN007; ;AN005; src filename cp = 0
je c_cont ;AN005; yes, this cp=0 is ok.
mov ax,msg_code_page_mismatch ;AN005; Error, code page mismatch
mov dh,1 ;AN005; message class
call display_and_die ;AN005; bye!
c_cont:
cmp ax,cs:tgt_cp ;AN000; Is same as target cp ?
je cp_match ;AN000; Yes? Do nothing
mov bx,STDOUT ;AN000; Standard output device
call set_cp ;AN000; Set codepage to that of source
cp_match:
pop ax ;AN000; Restore handle
;---------------------
;- PRINT FILE NAME
;---------------------
say_name:
push ax ;save file handle
cmp cs:got_filename,FALSE ;AN004; using STDIN
je xx1 ;AN004; yes, don't print a filename
mov dx,offset heading
mov cl,cs:heading_len
xor ch,ch
call prout
mov dx,cs:file_name_buf ;AC000;
mov cx,cs:file_name_len
call prout
cmp cs:c_flag,TRUE ;count only flag set?
je xx1
mov dx,offset crlf
mov cx,2
call prout
xx1:
pop ax
;---------------------
;- Fill Buffer for Matching
;---------------------
fill:
mov bx,ax ;retrieve handle
refill:
mov dx,offset buffer ;data buffer addrss.
mov cx,buffer_size
mov ah,read
int 021h
jnc no_read_error ;if carry then read error
jmp read_error
no_read_error:
or ax,ax ;if ax=0 then all done
jnz Truncate
DoNullRead:
cmp cs:c_flag,TRUE ;count only flag set?
jne sj2
call print_count
sj2:
and bx,bx ;Using STD IN?
jnz regular
jmp foo ;if so: all done, exit
regular:
mov ah,close ;otherwise close the file
int 021h
jmp scan_rest ;get another file
do_open_error:
jmp open_error ;AN000;
;---------------------------
; We have read in an entire buffer. Scan for a ^Z and terminate the buffer
; there. Change only CX
;---------------------------
Truncate:
push di
push cx
push es
mov di,dx
mov cx,ax
mov ax,ds
mov es,ax
mov al,1Ah
CLD
repnz scasb
;---------------------------
; If zero is set, the the previous character is a ^Z. If it is reset then
; the previous character is the end of buffer. With ^Z, we back up over the
; char.
;---------------------------
jnz chop
dec di
chop:
mov ax,di
sub ax,dx ; get true length of buffer
pop es
pop cx
pop di
or ax,ax
jz DoNullRead
;---------------------------
;----- MATCH ROUTINE
;---------------------------
;Note: If input is being taken from a file the stack contains
; (from top to bottom):
; - Pointer to the next command in the command line
; - Pointer to the program segment prefix (to be loaded into
; DS to access the command line.
; if the input is from the standard input then NONE of it will be
; in the stack.
;---------------------------
go_match:
push bx ;save the file handle
mov bp,offset buffer ;ptr to first line of file
;---------------------------
; At this point we must check to make sure there is AT LEAST one LF in the
; buffer. If there is not, then we must insert one at the end so we
; don't get stuck trying to get one complete line in the buffer when
; we can't cause the buffer ain't big enough.
;---------------------------
push ax ; Save true buffer size
mov cx,ax ; scan whole buffer
mov al,LF ; for a LF
mov di,bp ; start of buffer
repnz scasb
pop ax ; recover buffer size
mov di,ax ;displacement from beg of buffer
jnz last_line ; No line feeds, must insert one
;---------------------------
; Check to see if we reached EOF (return from READ less than buffer_size).
; If EOF we must make sure we end with a CRLF pair.
;---------------------------
cmp ax,buffer_size-1 ;last line of the file?
jg no_last_line ;nope
last_line: ;if yes, add a CRLF just in case
mov bx,bp
cmp byte ptr[bx+di-1],LF ;finished with a LF?
je no_last_line ;yes, it's an OK line.
mov byte ptr[bx+di],CR ;put a CR at the end of the data
inc di
mov byte ptr[bx+di],LF ;put a LF ...
inc di
no_last_line:
push di ;save the # of chars. in the buffer
push bp
mov dx,cs:st_length ;length of the string arg.
dec dx ;adjust for later use
jmp short try_again
more_stuff_o:
jmp more_stuff
;----- SCAN LINES IN THE BUFFER FOR A MATCH -------------------------;
;Note: at this point the stack contains (from top to bottom):
; - Stuff mentioned before
; - File Handle
; - Number of chars. left in the buffer from the next line.
; - Addrs. of the next line in the buffer.
;
; plus, DX has the adjusted length of the string argument.
;
; We are about to begin scanning a line. We start by determining if there is
; a complete line in the buffer. If so, we scan for the char. If NOT, we go
; and grab new info.
;---------------------------
try_again:
pop bp ;addrs. of next line in the buffer
mov di,bp ;points to beg. of a line
pop cx ;get # of chars left in the buffer
mov bx,cx ;save in case a non-complete line
mov al,LF ;search for a Line Feed
jcxz more_stuff_o ;no chars left in buffer
repnz scasb
jnz more_stuff_o ;no full line left in buffer
push cx ;save chars left in buffer
push di ;points to beg. of next line
mov cx,di
sub cx,bp ;length of the current line
mov bx,cx ;save in case it has a match
dec cx ;Discount the LF we found
cmp byte ptr ES:[DI-2],CR ; Is there a CR to discount too?
jnz NO_SECOND_DEC ; No there is not.
dec cx ;CR character discounted
NO_SECOND_DEC:
inc cs:line_cntr ;increment line counter
jcxz try_again_opt ;if line empty go to next line
mov di,bp ;pointer to the beg. of current line
another_char:
;---------------------------
; On entry:
; BX line length
; CX adjusted line length
; DX adjusted string argument length
; DI points to beg. of line
;---------------------------
push dx ;save for next line
lop:
pop dx
push dx
inc dx ;different algorithm!
mov si,offset st_buffer ;pointer to beg. of string argument
comp_next_char:
push di
mov di,si
call is_prefix ;check for a prefix char
pop di
jnc nopre
lodsw
cmp cx,1 ; Can not compare a two byte char
jbe try_again_opt1 ; if there is only one available
cmp ax,word ptr [di]
jz kmatch1
jmp short back_up ;AN007;
nopre:
lodsb
cmp al,byte ptr [di]
jz kmatch
back_up:
pop ax ; Original length of comp string
push ax
inc ax
;---------------------------
; Our match failed IN THE MIDDLE of the string (partial match). We need
; to back up in the line to the NEXT char after the one which matched
; the first char of the search string and try again. The amount to
; back up to where we started is ax-dx (the result MAY be 0, this is OK).
; we then need to skip ONE char in the line.
;---------------------------
sub ax,dx ; AX = AX-DX
sub di,ax ; Do the back up.
add cx,ax ; restore count too!
call next_kchar ;no match, advance di to next kanji
jc try_again_opt1 ;not enough chars left in line
jmp short lop ;try another char in line
try_again_opt1:
pop dx
jmp short try_again_opt ;AN007;
kmatch1:
dec dx ;last char had prefix so it was
; long.
kmatch:
dec dx
jz a_matchk ; no chars left: a match!
call next_kchar
jc try_again_opt1
jmp comp_next_char ; loop if chars left in arg.
a_matchk:
pop dx
cmp cs:v_flag,TRUE ;is flag set?
jne prt_line ;no, print the line
jmp try_again
;---------------------------
;- NO MATCH: CHECK FOR THE v OPTION
;---------------------------
try_again_opt:
cmp cs:v_flag,TRUE ;is flag set?
jne try_again ;no goto next line
;---------------------------
;- PRINT THE LINE WITH THE MATCH
;Note: at this point the stack contains (top to bottom)
; - Stuff mentioned before
;
; plus, BP points to begginig of the current line, BX has the length
;of the current line including the CRLF, and DX the adjusted length of
;the string argument.
;---------------------------
prt_line:
cmp cs:c_flag,TRUE ;is count only flag set?
jne no_c_flg
inc cs:mtch_cntr ;yes, increment counter
jmp try_again
no_c_flg:
push dx ;save the adjusted string arg. length
cmp cs:n_flag,TRUE ;is line number flag set?
jne no_n_flg
call prt_lcntr
no_n_flg:
mov dx,bp
mov cx,bx
call prout
pop dx ;restore
jmp try_again
;----- READ MORE TEXT LINES INTO THE BUFFER -------------------------;
; The scanning routines have detected that the buffer does not
;contain a full line any more. More lines have to be read into the
;buffer. But first perform a seek on the file in order to re-read
;the non-complete line into the begining of the buffer.
; Uppon entry BP contains points to the begining of the non-complete
;line, and BX has the number of characters left in the buffer.
; The Stack contains (top to bottom):
; - Pointer to the next command in the command line
; - Pointer to the program segment prefix (to be loaded into
; DS to access the command line).
; - File handle.
more_stuff:
mov dx,bx ;get chars left in buffer
pop bx ;get the handle
or dx,dx ;are there 0 left?
jz no_seek ;yes, do not seek
neg dx ;form two's complement
mov cx,-1
mov al,1 ;seek from the current position
mov ah,lseek ;seek on file
int 021h
jc read_error
no_seek:
jmp refill ;no errors: refill the buffer
read_error:
and bx,bx ;AN007; ;Using STD IN?
je foo ;if so: all done, exit
mov ah,close ;close the file
int 021h
;---------------
;------ Set message number and go display it
mov ax,msg_read_error ;AN000; Read error message
jmp short r_error ;AN007;
;---------------------
;- PRINT ERRORS
;---------------------
open_error:
cmp ax,ERROR_ACCESS_DENIED ;AN000;
jnz DoNorm
mov ax,msg_access_denied ;AN000; Message for Access Denied
jmp short r_error ;AN007; ;AN000; Do the rest
DoNorm: ;AN000;
mov ax,msg_file_not_found ;AN000; Message for File Not Found
r_error:
call prt_find ;AN005;
mov cs:sl_ptr_s,ds ;AN000; Save segment of subst text
mov cx,cs:file_name_buf ;AN000;
mov cs:sl_ptr_o,cx ;AN000; Save offset of subst text
mov cs:sl_flag,left_align+char_field_ASCIIZ ;AN000; Type of insertion text
mov bx,STDERR ;AN000; Sent to STD OUT
mov cx,1 ;AN000; One substitution string
mov dh,1 ;AN000; Its a utility message
call display_msg ;AN000; Display rror message
;---------------------
;- SCAN THE REST OF THE COMMAND LINE
;---------------------
scan_rest:
pop ds ;restore pointer to comm. line
pop si ;restore pointer to next comm.
mov cs:did_file,TRUE ;AN004; tell parser we did a file, so if it doesn't find another, ok!
cmp cs:got_eol,TRUE ;AN004; Check if nothing left on command line
je foo ;AN004; no, nothing left on command line, exit
jmp parser
foo:
mov cs:errlevel,ERRORLEVEL_ZERO ;AN000; Proper code
call terminate ;AN000; reset codepage and terminate
;--------------------------
; Clear Counters
;--------------------------
clr_cntrs proc near
mov byte ptr cs:mtch_cntr,0
mov byte ptr cs:line_cntr,0
ret
clr_cntrs endp
;--------------------------
; Print Count of Matched lines
; Modifies: AX,CX,DX and DI
;--------------------------
print_count proc near
push bx ;save handle
and bx,bx ;AN007; ;using STDIN?
jz sj3 ;if so do not print file name
mov dx,offset ccolon
mov cx,2
call prout ;print colon
sj3:
mov ax,cs:mtch_cntr
mov di,offset n2_buf ;buffer for characters
call bin2asc ;convert to ascii
mov dx,offset n2_buf
call prout ;print the number
mov dx,offset crlf
mov cx,2
call prout ;print an end of line
pop bx
ret
print_count endp
;--------------------------
; Print relative line number
; Modifies: AX,CX and DI
;--------------------------
prt_lcntr proc near
push bx
push dx
mov ax,cs:line_cntr
mov di,offset n2_buf
call bin2asc
mov byte ptr[di],"]"
inc cx
inc cx
mov dx,offset n1_buf
call prout
pop dx
pop bx
ret
prt_lcntr endp
;--------------------------
; Print string to STDOUT
;--------------------------
prout proc near
mov bx,STDOUT
mov ah,write
int 021h
ret
prout endp
;--------------------------
; Binary to Ascii conversion routine
; Entry:
; AX Binary number
; DI Points to one past the last char in the
; result buffer.
; Exit:
; Result in the buffer MSD first
; CX Digit count
; Modifies:
; AX,BX,CX,DX and DI
;--------------------------
bin2asc proc near
mov bx,0ah
xor cx,cx
go_div:
inc cx
cmp ax,bx
jb div_done
xor dx,dx
div bx
add dl,'0' ;convert to ASCII
push dx
jmp short go_div
div_done:
add al,'0'
push ax
mov bx,cx
deposit:
pop ax
stosb
loop deposit
mov cx,bx
ret
bin2asc endp
;--------------------------
; CAPIALIZES THE CHARACTER IN AL
; entry:
; AL has the character to Capitalize
; exit:
; AL has the capitalized character
; modifies:
; AL
;--------------------------
;make_caps proc near
; cmp al,'a'
; jb no_cap
; cmp al,'z'
; jg no_cap
; and al,0dfh
;no_cap:
; ret
;make_caps endp
;
;--------------------------
; ADVANCE POINTER TO NEXT KANJI CHARACTER
; entry: DI points to a Kanji string
; CX length in bytes of the string
; exit: DI points to next Kanji char
; CX has number of bytes left
; modifies: AX
;--------------------------
next_kchar proc near
jcxz no_kleft
call is_prefix
jnc no_p
inc di
dec cx
jcxz no_kleft ; for insurance
no_p:
inc di
dec cx
clc
ret
no_kleft:
stc
ret
next_kchar endp
;--------------------------
; Get DOS dbcs table vector
; entry: none
; exit: none
; modifies: none
;--------------------------
get_dbcs_vector proc near ;AN006;
push es ;AN006;
push di ;AN006;
push ax ;AN006;
push bx ;AN006;
push cx ;AN006;
push dx ;AN006;
;
mov ax,cs ;AN006; ;segment of return buffer
mov es,ax ;AN006;
mov di,offset bufferDB ;AN006; ;offset of return buffer
mov ah,65h ;AN006; ;get extended country info
mov al,07h ;AN006; ;get DBCS environment table
mov bx,0ffffh ;AN006; ;use active code page
mov cx,5 ;AN006; ;number of bytes returned
mov dx,0ffffh ;AN006; ;default country ID
int 21h ;AN006; ;DOS function call,vector returned
;AN006; ; in ES:DI
inc di ;AN006; ;skip over id byte returned
mov ax,word ptr es:[di] ;AN006; ;get offset of DBCS table
mov cs:dbcs_off,ax ;AN006; ;save it
;
add di,2 ;AN006; ;skip over offset to get segment
mov bx,word ptr es:[di] ;AN006; ;get segment of DBCS table
mov cs:dbcs_seg,bx ;AN006; ;save it
;
mov di,ax ;AN006; ;Point to DBCS table to get length
mov es,bx ;AN006;
mov ax,word ptr es:[di] ;AN006;
mov cs:dbcs_len,ax ;AN006;
add cs:dbcs_off,2 ;AN006; ;change offset to point to table
;
pop dx ;AN006;
pop cx ;AN006;
pop bx ;AN006;
pop ax ;AN006;
pop di ;AN006;
pop es ;AN006;
;
ret ;AN006;
get_dbcs_vector endp ;AN006;
;--------------------------
; FIND OUT IS THE BYTE IS A KANJI PREFIX
; entry: DI points to a kanji string
; exit: Carry set if it is a kanji prefix
; modifies: AX
;--------------------------
is_prefix proc near ;AN006;
push es
push si
push ax
;
mov si,cs:dbcs_off ;ES:SI -> DOS dbcs table
mov ax,cs:dbcs_seg
mov es,ax
;
mov al,byte ptr cs:[di] ;get first byte of string
;
; Two consecutive 00 bytes signifies end of table
;
is_loop:
cmp word ptr es:[si],00h ;Check for two consecutive 00 bytes
jne is_next1 ;no, continue
clc ;clear carry - byte is not lead byte of db char
jmp short is_exit ;AN007; ;yes, found them, quit
;
; Check if byte is within range values of DOS dbcs table
;
is_next1:
cmp al,byte ptr es:[si] ;is byte >= first byte in range?
jae is_next2 ;yes, continue
jmp short is_again ;AN007; ;no, loop again
is_next2:
cmp al,byte ptr es:[si+1] ;is byte <= last byte in range?
jbe is_found ;yes, found a lead byte of db char
is_again:
add si,2 ;no, increment ptr to next range
jmp is_loop
is_found:
stc ;byte is lead byte of db char, set carry
is_exit:
pop ax
pop si
pop es
;
ret
is_prefix endp
;
;---------------------
;- Terminate process
;---------------------
terminate proc near ;AN000;
mov ah,exit ;AN000; Terminate function call
mov al,cs:errlevel ;AN000; Errorlevel placed in AL
int 021h ;AN000; Terminate
ret ;AN000; Meaningless return
terminate endp ;AN000;
;
;************************************************************
;*
;* SUBROUTINE NAME: set_cp
;*
;* FUNCTION: Sets the cp of the handle in bx to the cp in LIST structure
;*
;* INPUT:
;* BX = handle
;* cp_list.cp = code page to set for the file handle in BX
;*
;* OUTPUT:
;* Codepage will be set to that requested, or an error will be
;* returned in AX with carry flag set.
;*
;************************************************************
set_cp proc near ;AN000;
mov ax,SetExtAttr ;AN000; Set target codepage to that of source
mov di,offset cp_list ;AC001; Input buffer address
int 021h ;AN000; Call DOS
ret ;AN000; Return to caller
set_cp endp ;AN000;
;************************************************************
;*
;* SUBROUTINE NAME: get_cp
;*
;* FUNCTION: Gets the cp of the handle in bx
;*
;* INPUT:
;* BX = handle
;*
;* OUTPUT:
;* Codepage for the file handle in bx will be returned in
;* the CP_LIST.CP structure, or an error will be returned in
;* AX with carry flag set.
;*
;************************************************************
get_cp proc near ;AN000;
push ds ;AN005;
push cs ;AN005;
pop ds ;AN005;
mov ax,GetExtAttr ;AN000; Get codepage
mov di,offset cp_list ;AN000; Input buffer address
mov si,offset cp_qlist ;AN001; which ea to select
mov cx,cp_len ;AN001; buffer length
int 021h ;AN000; Call to DOS
pop ds ;AN005;
ret ;AN000; Return to caller
get_cp endp ;AN000;
;
;************************************************************
;*
;* SUBROUTINE NAME: display_msg
;*
;* SUBROUTINE FUNCTION:
;* Display the requested message to the specified handle
;*
;* INPUT:
;* 1) AX = Number of the message to be displayed.
;* 2) BX = Handle to be written to.
;* 3) DH = Code indicating message class
;*
;* OUTPUT:
;* The message corresponding to the requested msg number will
;* be written to the requested handle.
;*
;* NORMAL EXIT:
;* Message will be successfully written to requested handle.
;*
;* ERROR EXIT:
;* None. Note that theoretically an error can be returned from
;* SYSDISPMSG, but there is nothing that the application can do.
;*
;* INTERNAL REFERENCES:
;* System Display Message service routines
;*
;* EXTERNAL REFERENCES:
;* None
;*
;************************************************************
display_msg proc near ;AN000;
push ds ;AN000; Save DS
push cs ;AN000; Substitution list segment
pop ds ;AN000;
mov si,offset sublist ;AN000; Substitution list offset
; mov dh,-1 ;AN000; Message class
; 1=DOS Extended error
; 2=DOS Parse error
; -1=Utility message
mov dl,0 ;AN000; DOS INT 21H function number to use for input
; 00H=No input, 01H=Keyboard input,
; 07H=Direct Console Input Without Echo,
; 08H=Console Input Without Echo, 0AH=Buffered Keyboard Input
call SYSDISPMSG ;AN000; AX=Extended key value if wait for key
; jnc disp_done ;AN000; If CARRY SET then registers will contain extended error information
; AX - Extended error Number
; BH - Error Class
; BL - Suggested action
; CH - Locus
disp_done: ;AN000;
pop ds ;AN000; Restore DS
ret ;AN000;
display_msg ENDP ;AN000;
PAGE
;************************************************************
;*
;* SUBROUTINE NAME: parse
;*
;* SUBROUTINE FUNCTION:
;* Call the DOS PARSE Service Routines to process the command
;* line. Search for valid switches (/N, /V, and /C) and take
;* appropriate action for each. Extract the search string.
;*
;* INPUT: DS:SI points to string to parse
;* ES:DI parser parms
;*
;* OUTPUT: ES:DI points to filespec for text search
;*
;* NORMAL EXIT:
;*
;* If /V, /C, or /N entered, set appropriate flag.
;* Save the search string.
;*
;* ERROR EXIT:
;*
;* If user enters any invalid parameter or switch, then this
;* routine will display an error message and terminate with
;* errorlevel 1.
;*
;************************************************************
EOL equ -1 ;AN000; Indicator for End-Of-Line
NOERROR equ 0 ;AN000; Return Indicator for No Errors
SYNTAX equ 9 ;AN000; Syntax error from parser
SWITCH equ 3 ;AN000;
FILESPEC equ 5 ;AN000;
QUOTED_STRING equ 9 ;AN000;
parse proc near ;AN000;
;--------------------------------------
; address of command line in DS:SI
;--------------------------------------
;------------------------------------------
;- Look for the search string and switches
;------------------------------------------
parse_loop: ;AN000;
mov di,offset parms ;AN000; Address of parse control block at ES:DI
xor dx,dx ;AN000; Reserved
call sysparse ;AN000; Parse parm at DS:SI
cmp ax,EOL ;AN000; Are we at End Of Line ??
jne p_next ;AN004; No eol found
mov cs:got_eol,TRUE ;AN004; no more filenames to get!
cmp cs:did_file,TRUE ;AN004; did we do a file already ?
lje doexit ;AN004; yes, exit
jmp end_parse ;AN004; Yes, done here
p_next: ;AN004; continue
and ax,ax ;AN007; ;AN000; Was there an error?
je CONT2 ;AN000; No, continue processing
mov dh,2 ;AN005; Its a PARSE message
call display_and_die ;AN005;
CONT2: ;AN000; Something valid was entered
cmp cs:rb_type,QUOTED_STRING ;AN000; Is it a quoted string ?
je its_a_quoted_string ;AN000; Yes, go process it
cmp cs:rb_type,FILESPEC ;AN000; Is it a filespec?
jne cont3 ;AN000;
mov di,cs:rb_value_lo ;AN000; Look for another
mov cs:got_filename,TRUE ;AN004; got a filename
jmp short end_parse ;AN007; ;AN000; Look for another
cont3:
cmp cs:rb_type,SWITCH ;AN000; Is it a switch ?
je its_a_switch ;AN000; Yes, go process it
mov ax,msg_inv_parm ;AN000; None of above, too bad
mov dh,2 ;AN005; message class
call display_and_die ;AN000; Tell the poor user and terminate
;-----------------------------
;- The search string was entered
;-----------------------------
its_a_quoted_string: ;AN000; Found a quoted string
cmp cs:got_srch_str,TRUE ;AN000; Do we already have one?
jne its_ok ;AN000; No, it's ok
mov ax,msg_inv_parm ;AN000; Yes, Invalid parm!
mov dh,2 ;AN005; message class
call display_and_die ;AN000; Tell user and die gracefully
its_ok: ;AN000;
mov di,cs:rb_value_lo ;AN000; Get pointer to it
mov bx,offset st_buffer ;AN000; save buffer offset
call get_length ;AN000; get string length
mov cs:st_length,ax ;AN000; save length
mov cs:got_srch_str,TRUE ;AN000; Indicate that we have it
jmp parse_loop ;AN000;
;-----------------------------
;- A valid switch was entered
;-----------------------------
its_a_switch: ;AN000;
mov bx,cs:rb_synonym ;AN000; Get offset of switch entered
cmp bx,offset n_swch ;AN000; Is it the /N switch?
jne chek_v ;AN000: Yes, process it.
jmp parse_loop ;AN000; Look for another
chek_v: ;AN000;
cmp bx,offset v_swch ;AN000; Is it the /N switch?
jne chek_c ;AN000: Yes, process it.
jmp parse_loop ;AN000; Look for another
chek_c: ;AN000;
cmp bx,offset c_swch ;AN000; Is it the /N switch?
jne whoops ;AN000: Yes, process it.
jmp parse_loop ;AN000; Look for another
whoops: ;AN000; None of the above (can we ever get here?)
mov ax,msg_switch ;AN000; Invalid parameter
mov dh,2 ;AN005; message class
call display_and_die ;AN000; Yes, tell the poor user and terminate
end_parse: ;AN000; A filename should be next
cmp cs:got_srch_str,TRUE ;AN000; Do we already have one?
je rett ;AN000;
mov ax,msg_required_missing ;AN005;
mov dh,-1 ;AN005; message class
call display_and_die ;AN000; Yes, tell the poor user and terminate
rett: ;AN000;
ret ;AN000;
doexit:
mov cs:errlevel,ERRORLEVEL_ZERO;AN000; Proper code
call terminate ;AN000; reset codepage and terminate
parse endp ;AN000;
;------------------------------------
;-
;- Procedure name: pre_parse
;-
;- Purpose: parse for all switches now
;- so that they can be applied for
;- all filenames on command line.
;-
;- INPUT: none
;-
;------------------------------------
pre_parse proc near ;AN005;
push ax ;AN005;
push bx ;AN005;
push cx ;AN005;
push dx ;AN005;
push di ;AN005;
push si ;AN005;
push es ;AN005;
push ds ;AN005;
;
pp_loop: ;AN005;
mov di,offset parms1 ;AN005; Address of parse control block at ES:DI
xor dx,dx ;AN005; Reserved
call sysparse ;AN005; Parse parm at DS:SI
cmp ax,EOL ;AN005; Are we at End Of Line ??
je pp_end ;AN005; No eol found
cmp ax,SWITCH ;AN005; invalid switch ?
jne pp_next ;AN005; no
; error
mov ax,msg_switch ;AN005; Invalid switch
mov dh,2 ;AN005; message class
call display_and_die ;AN005; Yes, tell the poor user and terminate
pp_next:
and ax,ax ;AN007; ;AN005; Was there an error?
jne pp_loop ;AN005; No, continue processing
cmp cs:rb_type,SWITCH ;AN005; Is it a switch ?
jne pp_loop ;AN005;
; got a switch
mov bx,cs:rb_synonym ;AN005; Get offset of switch entered
cmp bx,offset n_swch ;AN005; Is it the /N switch?
jne pp_chek_v ;AN005: Yes, process it.
mov cs:n_flag,TRUE ;AN005; Set the corresponding flag
jmp pp_loop ;AN005; Look for another
pp_chek_v: ;AN005;
cmp bx,offset v_swch ;AN005; Is it the /N switch?
jne pp_chek_c ;AN005: Yes, process it.
mov cs:v_flag,TRUE ;AN005; Set the corresponding flag
jmp pp_loop ;AN005; Look for another
pp_chek_c: ;AN005;
cmp bx,offset c_swch ;AN005; Is it the /N switch?
jne pp_error ;AN005: Yes, process it.
mov cs:c_flag,TRUE ;AN005; Set the corresponding flag
jmp pp_loop ;AN005; Look for another
pp_error: ;AN005; None of the above (can we ever get here?)
mov ax,msg_switch ;AN005; Invalid parameter
mov dh,2 ;AN005; message class
call display_and_die ;AN005; Yes, tell the poor user and terminate
pp_end: ;AN005; A filename should be next
pop ds ;AN005;
pop es ;AN005;
pop si ;AN005;
pop di ;AN005;
pop dx ;AN005;
pop cx ;AN005;
pop bx ;AN005;
pop ax ;AN005;
;
ret ;AN005;
pre_parse endp ;AN005;
;------------------------------------
;-
;- Procedure name: prt_find
;-
;- Purpose: When FIND is used as a filter,
;- then display error messages with the
;- prefix: "FIND: ".
;-
;- INPUT: none
;-
;------------------------------------
prt_find proc near ;AN005;
cmp cs:got_filename,TRUE ;AN005; Check if should print "FIND:"
je prt_ret ;AN005;
push ax ;AN005; Save error
push dx ;AN005;
mov dh,-1 ;AN005; Display FIND:
mov ax,msg_find ;AN005;
xor cx,cx ;AN007; ;AN005; No substitution text
mov bx,STDERR ;AN005; Sent to STD OUT
call display_msg ;AN005; Display the message
pop dx ;AN005;
pop ax ;AN005; Restore error
prt_ret:
ret ;AN005;
prt_find endp ;AN005;
;------------------------------------
;-
;- Procedure name: display_and_die
;-
;- Purpose: Called when the parser finds that
;- required arguments were not entered
;- from the command line.
;-
;- INPUT: AX = Error number
;-
;------------------------------------
display_and_die proc near
call prt_find ;AN005;
xor cx,cx ;AN007; ;AN000; No substitution text
mov cs:errlevel,ERRORLEVEL_TWO ;AC005; Error code for exit
mov bx,STDERR ;AN000; Sent to STD OUT
call display_msg ;AN000; Display the message
call terminate ;AN000; and Terminate
ret ;AN000;
display_and_die endp
;------------------------------------
;-
;- Procedure name: get_length
;-
;- Purpose: determine the length of a null
;- ending string.
;-
;- INPUT: ES:DI = string address
;- ES:BX = save address (0=no save)
;-
;- OUTPUT: AX = length of string
;------------------------------------
get_length proc near
push di
push bx
push dx
xor ax,ax ;init string length
look_str:
mov dl,es:[di] ;get character
or bx,bx ;save it?
jz no_save
mov es:[bx],dl ;save character
inc bx ;save next character
no_save: ;AN007;
and dl,dl ;AN007; ;check for eol (asciiz string)
je done_look ;if so, exit
cmp dl,0dh ;AN005; check for eol (carriage return)
je done_look ;AN005;
inc ax ;increment length
inc di ;look at next character
jmp look_str
done_look:
pop dx
pop bx
pop di
ret
get_length endp
;
;----- BUFFER AREA --------
st_length dw 0 ;String argument length
st_buffer db st_buf_size dup(?) ;String argument buffer
file_name_len dw 0 ;File name length
file_name_buf dw 0 ;File name buffer offset
buffer db buffer_size+2 dup(?) ;file data buffer
include msgdcl.inc
code ends
;--------------------------
;--- STACK SEGMENT ---
;--------------------------
stack segment para stack 'STACK'
dw (362 - 80h) +64 dup(?,?) ;(362 - 80h) == New - old IBM ROM
stack_top equ $
stack ends
end start
|