summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/FIND/FIND.ASM
blob: 459765a0d1ffb987075ab5da29a4d069f6886007 (plain) (blame)
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