summaryrefslogtreecommitdiff
path: root/v2.0/source/CHKDSK.ASM
blob: c305a1dd4d7f775739c5468d38e3a252e578156c (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
TITLE   CHKDSK - MS-DOS Disk consistancy checker

; CHKDSK        Version 2.30
; Verifies and repairs MS-DOS disk directory.


; To build CHKDSK you need three modules:
; CHKDSK CHKPROC CHKMES
; They should be linked the that order as well.


; REVISION HISTORY

;REV 1.1
;     05/21/82  Added rev number

;REV 1.5
;       Mod by NANCYP to report on extents
;       Mod by AARONR to report volume ID

;REV 2.0
;       Total rewrite for directories

;REV 2.1
;       Added ^C and INT 24H handlers

;REV 2.2
;       INTERNATIONAL support

;REV 2.3
;       Split into two modules to allow assembly on a PC
;       CHKDSK and CHKPROC

FALSE   EQU     0
TRUE    EQU     NOT FALSE

DRVCHAR EQU     ":"

;The following defines the ranges of DOS version numbers for which this CHKDSK
; is good

DOSVER_LOW EQU  0136H   ;1.54 in hex
DOSVER_HIGH EQU 020BH   ;2.11 in hex


        INCLUDE DOSSYM.ASM

FCB     EQU     5CH

;Drive parameter block from DOS header

SUBTTL  Segments used in load order

CODE    SEGMENT PUBLIC
CODE    ENDS

CONST   SEGMENT PUBLIC BYTE
CONST   ENDS

DATA    SEGMENT PUBLIC WORD
DATA    ENDS

DG      GROUP   CODE,CONST,DATA

SUBTTL  Initialized Data
PAGE
CONST   SEGMENT PUBLIC BYTE

        PUBLIC  HECODE,SWITCHAR,NOISY,DOFIX,CONBUF,ORPHCNT,ORPHSIZ,DOFIX
        PUBLIC  HIDCNT,HIDSIZ,DIRCNT,DIRSIZ,FILCNT,FILSIZ,BADSIZ,LCLUS
        PUBLIC  DOTENT,HAVFIX,SECONDPASS,NUL,ALLFILE,PARSTR,ERRSUB,LCLUS
        PUBLIC  DIRTYFAT,BADSIZ,DDOTENT,CROSSCNT,ORPHFCB,ORPHEXT,ALLDRV
        PUBLIC  FRAGMENT,USERDIR,DIRBUF,USERDIR,FIXMFLG,DOTMES,DIRCHAR

        EXTRN   IDMES1:BYTE,IDPOST:BYTE,VNAME:BYTE,MONTAB:BYTE
        EXTRN   TCHAR:BYTE,BADREAD_PRE:BYTE,BADREAD_POST:BYTE
        EXTRN   CRLF:BYTE,BADVER:BYTE,BADSUBDIR:BYTE,CENTRY:BYTE
        EXTRN   BADDRV:BYTE,BADCD:BYTE,BADRDMES:BYTE,OPNERR:BYTE
        EXTRN   CONTAINS:BYTE,EXTENTS:BYTE,NOEXTENTS:BYTE
        EXTRN   BADDRVM:BYTE,BADDRVM2:BYTE,BADIDBYT:BYTE


DIRBUF  LABEL   BYTE                    ;Entry buffer for searches
VOLID   DB      -1,0,0,0,0,0,8          ;Volume ID FCB
VOLNAM  DB      0,"???????????"
        DB      25 DUP(0)

ALLFILE DB      -1,0,0,0,0,0,1EH        ;Extended FCB
ALLDRV  DB      0,"???????????"
        DB      25 DUP (?)

ORPHFCB DB      0,"FILE0000"
ORPHEXT DB      "CHK"
        DB      25 DUP (?)


;Non-message data

SWITCHAR DB     "-"
ROOTSTR LABEL   BYTE
DIRCHAR DB      "/"
NUL     DB      0
PARSTR  DB      "..",0
DOTMES  DB      ".",0
DOTENT  DB      ".          "
DDOTENT DB      "..         "
HECODE  DB      ?
FIXMFLG DB      0                       ;Flag for printing fixmes
ERRSUB  DW      0                       ;Flag for bad subdir error
FRAGMENT DB     0                       ;Flag for extent processing
DIRTYFAT DB     0                       ;Dirty flag for FAT
DIRCNT  DW      0                       ;# directories
DIRSIZ  DW      0                       ;# alloc units in directories
FILCNT  DW      0                       ;# reg files
FILSIZ  DW      0                       ;# alloc units in reg files
HIDCNT  DW      0                       ;# hidden files
HIDSIZ  DW      0                       ;# alloc units in hidden files
BADSIZ  DW      0                       ;# alloc units in bad sectors
ORPHCNT DW      0                       ;# orphan files made
ORPHSIZ DW      0                       ;# alloc units in orphan files
LCLUS   DW      0                       ;# alloc units in lost clusters
DISPFLG DB      0                       ;used by number routines
CROSSCNT DW     0                       ;# crosslinked files (first pass)
SECONDPASS DB   0                       ;Pass flag
HAVFIX  DB      0                       ;non zero if any fixes
DOFIX   DB      0                       ;flag for F switch
NOISY   DB      0                       ;flag for V switch
USERDIR DB      "/",0                   ;Users current dir for drive
        DB      (DIRSTRLEN-1) DUP (?)
CONBUF  DB      15,0                    ;Input buffer
        DB      15 DUP (?)

CONST   ENDS

SUBTTL  Un-initialized Data
PAGE
DATA    SEGMENT PUBLIC WORD

        PUBLIC  ZEROTRUNC,NAMBUF,MCLUS,THISDPB,STACKLIM,ERRCNT
        PUBLIC  SRFCBPT,ISCROSS,CSIZE,DSIZE,SSIZE,FAT,FATMAP
        PUBLIC  HARDCH,CONTCH,USERDEV,SECBUF,DOTSNOGOOD

HARDCH  DD      ?                       ;Pointer to real INT 24 handler
CONTCH  DD      ?                       ;Pointer to real INT 23 handler
THISDPB DD      ?                       ;Pointer to drive DPB
USERDEV DB      ?                       ;Users current device
CSIZE   DB      ?                       ;Sectors per cluster
SSIZE   DW      ?                       ;bytes per sector
DSIZE   DW      ?                       ;# alloc units on disk
MCLUS   DW      ?                       ;DSIZE + 1
NAMBUF  DB      14 DUP (?)              ;Buffer
DOTSNOGOOD DB   ?                       ;. or .. error flag
ZEROTRUNC DB    ?                       ;Trimming flag
ISCROSS DB      ?                       ;Crosslink flag
OLDCLUS DW      ?
SRFCBPT DW      ?
FATMAP  DW      OFFSET DG:FAT           ;Offset of FATMAP table
SECBUF  DW      ?                       ;Offset of sector buffer
ERRCNT  DB      ?                       ;Used by FATread and write
STACKLIM DW     ?                       ;Stack growth limit

INTERNATVARS    internat_block <>
                DB      (internat_block_max - ($ - INTERNATVARS)) DUP (?)

FAT     LABEL   WORD
DATA    ENDS


SUBTTL  Start of CHKDSK

CODE    SEGMENT PUBLIC
ASSUME  CS:DG,DS:DG,ES:DG,SS:DG

        PUBLIC  SUBERRP,DOTCOMBMES,FIGREC,FCB_TO_ASCZ,PRTCHR,EPRINT
        PUBLIC  PRINT,DOCRLF,DISP16BITS,DISP32BITS,DISPCLUS,CHECKFILES

        EXTRN   RDSKERR:NEAR,SETSWITCH:NEAR,PROMPTYN:NEAR,REPORT:NEAR
        EXTRN   PRINTCURRDIRERR:NEAR,PRINTTHISEL2:NEAR,CHECKERR:NEAR
        EXTRN   INT_23:NEAR,INT_24:NEAR,FINDCHAIN:NEAR,DONE:NEAR,AMDONE:NEAR
        EXTRN   FATAL:NEAR,DIRPROC:NEAR,CHKMAP:NEAR,CHKCROSS:NEAR,UNPACK:NEAR

        ORG     100H

CHKDSK:
        JMP     SHORT CHSTRT

HEADER  DB      "Ver 2.30"

CHSTRT:

;Code to print header.
;       PUSH    AX
;       MOV     DX,OFFSET DG:HEADER
;       CALL    PRINT
;       POP     AX

        PUSH    AX              ;Save DRIVE validity info
        MOV     AH,GET_VERSION
        INT     21H
        XCHG    AH,AL           ;Turn it around to AH.AL
        CMP     AX,DOSVER_LOW
        JB      GOTBADDOS
        CMP     AX,DOSVER_HIGH
        JBE     OKDOS
GOTBADDOS:
        MOV     DX,OFFSET DG:BADVER
        JMP     CERROR

OKDOS:
        POP     AX              ;Get back drive info
        MOV     BX,0FFF0H
        MOV     DX,SP
        CMP     DX,BX
        JAE     STACKOK         ;Lots of stack
        MOV     DX,DS:[2]       ;High break
        MOV     CX,CS
        SUB     DX,CX
        CMP     DX,0FFFH
        JAE     SETSTACK        ;Lots to grab
        MOV     CX,4            ;Suck up more stack (blast command)
        SHL     DX,CL
        MOV     BX,DX
SETSTACK:
        CLI
        MOV     SP,BX
        STI
STACKOK:
        PUSH    AX
        MOV     AH,DISK_RESET        ;Flush everything, and invalidate
        INT     21H
        POP     AX
        CMP     AL,0FFH                 ;Illegal drive specifier?
        JNZ     FILECHK                 ;No -- check for filename

DRVERR:
        MOV     DX,OFFSET DG:BADDRV
CERROR:
        PUSH    CS                      ;Make sure DS is OK
        POP     DS
        CALL    PRINT                   ;Print error message
        INT     20H

CERROR2:
        PUSH    DX
        CALL    DONE                            ;Reset users disk
        POP     DX
        JMP     SHORT CERROR

FILECHK:
        MOV     AX,(CHAR_OPER SHL 8)
        INT     21H
        MOV     [SWITCHAR],DL
        CMP     DL,"/"
        JNZ     SLASHOK
        MOV     [DIRCHAR],"\"
        MOV     [USERDIR],"\"
SLASHOK:
        CMP     DS:(BYTE PTR FCB+1)," "         ;Filename specified?
        JZ      DRVCHK                          ;No -- get the correct drive
        MOV     AL,[SWITCHAR]
        CMP     DS:(BYTE PTR FCB+1),AL          ;Filename specified?
        JZ      DRVCHK                          ;No -- get the correct drive
        MOV     BYTE PTR [FRAGMENT],1           ;Set flag to perform fragment
                                                ;check on specified files
DRVCHK:
        CALL    SETSWITCH                       ;Look for switches
        MOV     AH,GET_DEFAULT_DRIVE            ;Get current drive
        INT     21H
        MOV     [USERDEV],AL                    ;Save for later
        MOV     AH,AL
        INC     AH                      ;A = 1
        MOV     BH,DS:(BYTE PTR FCB)    ;See if drive specified
        OR      BH,BH
        JZ      SETDSK
        MOV     AL,BH
        MOV     AH,AL
        DEC     AL                      ;A = 0
SETDSK:
        MOV     [ALLDRV],AH             ;Target drive
        MOV     [VOLNAM],AH             ;A = 1
        MOV     [ORPHFCB],AH            ;A = 1
        ADD     [BADDRVM],AL            ;A = 0
        ADD     [BADDRVM2],AL           ;A = 0
        MOV     DL,AH                   ;A = 1
        MOV     AH,GET_DPB              ;Get the DPB
        INT     21H
ASSUME  DS:NOTHING
        CMP     AL,-1
        JNZ     DRVISOK                 ;Bad drive (should always be ok)
        MOV     DX,OFFSET DG:BADDRV
CERROR2J: JMP    CERROR2

DRVISOK:
        DEC     DL                      ;A = 0
        MOV     AH,SET_DEFAULT_DRIVE    ;Set Target
        INT     21H
        CMP     [BX.dpb_current_dir],0
        JZ      CURRISROOT              ;Save users current dir for target
        MOV     SI,BX
        ADD     SI,dpb_dir_text
        MOV     DI,OFFSET DG:USERDIR + 1
SETDIRLP:
        LODSB
        STOSB
        OR      AL,AL
        JZ      CURRISROOT
        JMP     SHORT SETDIRLP
CURRISROOT:
        MOV     WORD PTR [THISDPB+2],DS
        PUSH    CS
        POP     DS
ASSUME  DS:DG
        MOV     WORD PTR [THISDPB],BX
        MOV     AX,(GET_INTERRUPT_VECTOR SHL 8) OR 23H
        INT     21H
        MOV     WORD PTR [CONTCH],BX
        MOV     WORD PTR [CONTCH+2],ES
        MOV     AX,(SET_INTERRUPT_VECTOR SHL 8) OR 23H
        MOV     DX,OFFSET DG:INT_23
        INT     21H
        MOV     AX,(GET_INTERRUPT_VECTOR SHL 8) OR 24H
        INT     21H
        MOV     WORD PTR [HARDCH],BX
        MOV     WORD PTR [HARDCH+2],ES
        MOV     AX,(SET_INTERRUPT_VECTOR SHL 8) OR 24H
        MOV     DX,OFFSET DG:INT_24
        INT     21H
        PUSH    CS
        POP     ES
        MOV     DX,OFFSET DG:ROOTSTR
        MOV     AH,CHDIR                        ;Start at root
        INT     21H
        MOV     DX,OFFSET DG:BADCD
        JC      CERROR2J                        ;Couldn't get there
        MOV     DX,OFFSET DG:FAT                ;Scratch space
        MOV     AH,SET_DMA
        INT     21H
        MOV     DX,OFFSET DG:VOLID              ;Look for VOL ID
        MOV     AH,DIR_SEARCH_FIRST
        INT     21H
        CMP     AL,-1
        JZ      NOTVOLID
        CALL    PRINTID                         ;Have a VOL ID
NOTVOLID:
        LDS     BX,[THISDPB]
ASSUME  DS:NOTHING
        MOV     AX,[BX.dpb_sector_size]
        MOV     [SSIZE],AX              ;Sector size in bytes
        MOV     AL,[BX.dpb_cluster_mask]
        INC     AL
        MOV     [CSIZE],AL              ;Sectros per cluster
        MOV     AX,[BX.dpb_max_cluster]
        MOV     [MCLUS],AX              ;Bound for FAT searching
        DEC     AX
        MOV     [DSIZE],AX              ;Total data clusters on disk
        MOV     AL,[BX.dpb_FAT_size]          ;Sectors for one fat
        XOR     AH,AH
        MOV     CX,AX
        MUL     [SSIZE]                 ;Bytes for FAT
        ADD     [FATMAP],AX             ;Allocate FAT space
        MOV     AX,[FATMAP]
        ADD     AX,[MCLUS]
        ADD     AX,2                    ;Insurance
        MOV     [SECBUF],AX             ;Allocate FATMAP space
        ADD     AX,[SSIZE]
        ADD     AX,20                   ;Insurance
        MOV     [STACKLIM],AX           ;Limit on recursion
        MOV     DI,CX
        MOV     CL,[BX.dpb_FAT_count]          ;Number of FATs
        MOV     DX,[BX.dpb_first_FAT]          ;First sector of FAT
        PUSH    CS
        POP     DS
ASSUME  DS:DG
        MOV     BX,OFFSET DG:FAT
        MOV     AL,[ALLDRV]
        DEC     AL
        MOV     AH,'1'
RDLOOP:
        XCHG    CX,DI
        PUSH    DX
        PUSH    CX
        PUSH    DI
        PUSH    AX
        INT     25H                     ;Read in the FAT
        MOV     [HECODE],AL
        POP     AX                      ;Flags
        JNC     RDOK
        MOV     DX,OFFSET DG:BADREAD_PRE    ;Barfed
        CALL    PRINT
        POP     AX
        PUSH    AX
        MOV     DL,AH
        CALL    PRTCHR
        MOV     DX,OFFSET DG:BADREAD_POST
        CALL    PRINT
        POP     AX
        POP     CX
        POP     DI
        POP     DX
        INC     AH
        ADD     DX,DI
        LOOP    RDLOOP                  ;Try next FAT
        CALL    RDSKERR
        JNZ     NORETRY1
        JMP     NOTVOLID
NORETRY1:
        MOV     BX,OFFSET DG:BADRDMES
        JMP     FATAL                   ;Couldn't read any FAT, BARF

RDOK:
        POP     AX                      ;Clean up
        POP     AX
        POP     AX
        POP     AX
        MOV     SI,OFFSET DG:FAT
        LODSB                           ;Check FAT ID byte
        CMP     AL,0F8H
        JAE     IDOK
        MOV     DX,OFFSET DG:BADIDBYT   ;FAT ID bad
        CALL    PROMPTYN                ;Ask user
        JZ      IDOK
        JMP     ALLDONE                 ;User said stop
IDOK:
        MOV     DI,[FATMAP]
        MOV     CX,[MCLUS]
        INC     CX
        XOR     AL,AL
        REP     STOSB                   ;Initialize FATMAP to all free
        MOV     DX,OFFSET DG:DIRBUF     ;FOR ALL SEARCHING
        MOV     AH,SET_DMA
        INT     21H
        XOR     AX,AX
        PUSH    AX                      ;I am root
        PUSH    AX                      ;Parent is root
        CALL    DIRPROC
        CALL    CHKMAP                  ;Look for badsectors, orphans
        CALL    CHKCROSS                ;Check for second pass
        CALL    DOCRLF
        CALL    REPORT

ALLDONE:
        CALL    AMDONE
        INT     20H                     ;Fini


ASSUME  DS:DG

SUBTTL  Check for extents in specified files
PAGE
CHECKFILES:
;Search the directory for the files specified on the command line
;and report the number of fragmented allocation units found in
;each one.
        CALL    DOCRLF
        MOV     AH,SET_DMA
        MOV     DX,[FATMAP]             ;Use the first free space available
        MOV     BP,DX
        ADD     BP,27                   ;cluster in the directory entry
        INT     21H
        MOV     AH,DIR_SEARCH_FIRST              ;Look for the first file
FRAGCHK:
        MOV     DX,FCB
        INT     21H
        OR      AL,AL                   ;Did we find it?
        JNZ     MSGCHK                  ;No -- we're done
        XOR     AX,AX                   ;Initialize the fragment counter
        MOV     SI,[BP]                 ;Get the first cluster
        CALL    UNPACK
        CMP     DI,0FF8H                ;End-of-file?
        JAE     NXTCHK                  ;Yes -- go report the results
        INC     SI
        CMP     SI,DI
        JZ      EACHCLUS
        INC     AX
EACHCLUS:
        MOV     [OLDCLUS],DI            ;Save the last cluster found
        MOV     SI,DI                   ;Get the next cluster
        CALL    UNPACK
        INC     [OLDCLUS]               ;Bump the old cluster
        CMP     DI,[OLDCLUS]            ;Are they the same?
        JNZ     LASTCLUS                ;No -- check for end-of-file
        JMP     SHORT EACHCLUS          ;Continue processing
LASTCLUS:
        CMP     DI,0FF8H                ;End-of-file?
        JAE     NXTCHK                  ;Yes -- go report the results
        INC     AX                      ;No -- found a fragement
        JMP     SHORT EACHCLUS          ;Continue processing

NXTCHK:
        OR      AX,AX
        JZ      GETNXT
        MOV     [FRAGMENT],2            ;Signal that we output at least one file
        PUSH    AX                      ;Save count of fragments
        MOV     SI,[FATMAP]
        INC     SI
        CALL    PRINTTHISEL2
        CALL    DOCRLF
        MOV     DX,OFFSET DG:CONTAINS   ;Print message
        CALL    PRINT
        POP     SI                      ;Number of fragments found
        INC     SI                      ;Number non-contig blocks
        XOR     DI,DI
        MOV     BX,OFFSET DG:EXTENTS
        PUSH    BP
        CALL    DISP16BITS
        POP     BP
GETNXT:
        MOV     AH,DIR_SEARCH_NEXT              ;Look for the next file
        JMP     FRAGCHK

MSGCHK:
        CMP     AH,DIR_SEARCH_FIRST
        JNZ     FILSPOK
        MOV     SI,FCB + 1              ;File not found error
        CALL    PRINTTHISEL2
        CALL    DOCRLF
        MOV     DX,OFFSET DG:OPNERR
        CALL    PRINT                   ;Bad file spec
        RET
FILSPOK:
        CMP     BYTE PTR [FRAGMENT],2
        JZ      CDONE
        MOV     DX,OFFSET DG:NOEXTENTS
        CALL    PRINT
CDONE:
        RET


FIGREC:
;Convert cluster number in BX to sector # AH of cluster in DX
        LDS     DI,[THISDPB]
ASSUME  DS:NOTHING
        MOV     CL,[DI.dpb_cluster_shift]
        MOV     DX,BX
        DEC     DX
        DEC     DX
        SHL     DX,CL
        OR      DL,AH
        ADD     DX,[DI.dpb_first_sector]
        PUSH    CS
        POP     DS
ASSUME  DS:DG
        RET


SUBTTL  PRINTID - Print Volume ID info
PAGE
PRINTID:
ASSUME  DS:DG
        MOV     DX,OFFSET DG:INTERNATVARS
        MOV     AX,INTERNATIONAL SHL 8
        INT     21H
        MOV     [DISPFLG],1             ;Don't sub spaces for leading zeros
        MOV     SI,OFFSET DG:FAT + 8
        MOV     DI,OFFSET DG:VNAME
        MOV     CX,11
        REP     MOVSB
        MOV     DX,OFFSET DG:IDMES1
        CALL    PRINT                   ;Print ID message
        ADD     SI,13
        LODSW                           ;Get date
        PUSH    SI
        MOV     DX,AX
        MOV     AX,[INTERNATVARS.Date_tim_format]
        OR      AX,AX
        JZ      USPDAT
        DEC     AX
        JZ      EUPDAT
        CALL    P_YR
        CALL    P_DSEP
        CALL    P_MON
        CALL    P_DSEP
        MOV     CX,1000H                ;Do not supress leading zeroes
        CALL    P_DAY
        JMP     P_TIME

USPDAT:
        CALL    P_MONTH_NAM
        MOV     CX,1110H                ;Supress at most 1 leading 0
        CALL    P_DAY
        PUSH    DX
        MOV     DL,','
        CALL    PRTCHR
        MOV     DL,' '
        CALL    PRTCHR
        POP     DX
PYA:
        CALL    P_YR
        JMP     P_TIME

EUPDAT:
        MOV     CX,1110H                ;Supress at most 1 leading 0
        CALL    P_DAY
        PUSH    DX
        MOV     DL,' '
        CALL    PRTCHR
        POP     DX
        CALL    P_MONTH_NAM
        JMP     PYA

P_DSEP:
        PUSH    DX
        MOV     DL,[INTERNATVARS.Date_sep]
        CALL    PRTCHR
        POP     DX
        RET

P_MONTH_NAM:
        MOV     AX,DX
        PUSH    DX
        MOV     CL,5
        SHR     AX,CL
        AND     AX,0FH                  ;Month in AX
        DEC     AX                      ;Make 0 indexed
        MOV     CX,AX
        SHL     AX,1
        ADD     AX,CX                   ;Mult by 3 chars/mo
        MOV     SI,OFFSET DG:MONTAB
        ADD     SI,AX
        LODSB
        MOV     DL,AL
        CALL    PRTCHR
        LODSB
        MOV     DL,AL
        CALL    PRTCHR
        LODSB
        MOV     DL,AL
        CALL    PRTCHR
        MOV     DL,' '
        CALL    PRTCHR
        POP     DX
        RET

P_MON:
        MOV     SI,DX
        PUSH    DX
        MOV     CL,5
        SHR     SI,CL
        AND     SI,0FH                  ;Month in SI
        CALL    CONVERT
        MOV     DL,AL
        MOV     CX,1000H                ;Do not supress leading 0
        CALL    OUTBYTE                 ;Print month
        POP     DX
        RET

P_DAY:
        MOV     SI,DX
        PUSH    DX
        PUSH    CX
        AND     SI,01FH                 ;SI has day
        CALL    CONVERT
        POP     CX
        MOV     DL,AL
        CALL    OUTBYTE                 ;Print day
        POP     DX
        RET

P_YR:
        MOV     SI,DX
        PUSH    DX
        MOV     CL,9
        SHR     SI,CL
        AND     SI,07FH                 ;SI has raw year
        ADD     SI,1980                 ;Real year
        CALL    CONVERT
        MOV     CX,1000H                ;Do not supress leading zeros
        CALL    OUTWORD                 ;Print year
        POP     DX
        RET

P_TIME:
        MOV     DL,' '
        CALL    PRTCHR
        POP     SI
        ADD     SI,-4
        LODSW                           ;Get time
        MOV     DI,AX
        MOV     SI,DI
        MOV     CL,11
        SHR     SI,CL
        AND     SI,01FH                 ;SI has hour
        CMP     [INTERNATVARS.Time_24],0
        JNZ     ISOK2                   ;24 hour time?
        CMP     SI,12
        JB      ISOK                    ;Is AM
        MOV     [TCHAR],'p'
        JZ      ISOK                    ;Is 12-1p
        SUB     SI,12                   ;Is PM
ISOK:
        OR      SI,SI
        JNZ     ISOK2
        MOV     SI,12                   ;0 is 12a
ISOK2:
        CALL    CONVERT
        MOV     CX,1110H                ;Supress at most 1 leading 0
        MOV     DL,AL
        CALL    OUTBYTE                 ;Print hour
        MOV     DL,BYTE PTR [INTERNATVARS.Time_sep]
        CALL    PRTCHR
        MOV     SI,DI
        MOV     CL,5
        SHR     SI,CL
        AND     SI,03FH                 ;SI has minute
        CALL    CONVERT
        MOV     CX,1000H                ;Do not supress leading zeroes
        MOV     DL,AL
        CALL    OUTBYTE                 ;Print minute
        MOV     DL,[TCHAR]
        CMP     [INTERNATVARS.Time_24],0
        JNZ     NOAP                    ;24 hour time, no a or p
        CALL    PRTCHR                  ;Print a or p
NOAP:
        MOV     DX,OFFSET DG:IDPOST
        CALL    PRINT
        MOV     [DISPFLG],0
        RET

CONVERT:
        MOV     CX,16
        XOR     AX,AX
CNVLOOP:
        SHL     SI,1
        CALL    CONVWRD
        CLC
        LOOP    CNVLOOP
        RET

SUBTTL  Misc Routines - Mostly I/O
PAGE
CONVWRD:
        ADC     AL,AL
        DAA
        XCHG    AL,AH
        ADC     AL,AL
        DAA
        XCHG    AL,AH
RET1:   RET

UNSCALE:
        SHR     CX,1
        JC      RET1
        SHL     SI,1
        RCL     DI,1
        JMP     SHORT UNSCALE

DISP16BITS:
        MOV     BYTE PTR DISPFLG,1
        JMP     SHORT DISP32BITS

DISPCLUS:
        MUL     [SSIZE]
        MOV     CL,[CSIZE]
        XOR     CH,CH
        MOV     SI,AX
        MOV     DI,DX
        CALL    UNSCALE

DISP32BITS:
        PUSH    BP
        PUSH    BX
        XOR     AX,AX
        MOV     BX,AX
        MOV     BP,AX
        MOV     CX,32
CONVLP:
        SHL     SI,1
        RCL     DI,1
        XCHG    AX,BP
        CALL    CONVWRD
        XCHG    AX,BP
        XCHG    AX,BX
        CALL    CONVWRD
        XCHG    AX,BX
        ADC     AL,0
        LOOP    CONVLP
        ; Conversion complete
        MOV     CX,1310H        ;Print 3-digit number with 2 leading blanks
        CMP     BYTE PTR DISPFLG,0
        JNZ     FOURDIG
        MOV     CX,1810H        ;Print 8-digit number with 2 leading blanks
        XCHG    DX,AX
        CALL    DIGIT
        XCHG    AX,BX
        CALL    OUTWORD
FOURDIG:
        MOV     AX,BP
        CALL    OUTWORD
        MOV     BYTE PTR DISPFLG,0
        POP     DX
        CALL    PRINT
        POP     BP
        RET

OUTWORD:
        PUSH    AX
        MOV     DL,AH
        CALL    OUTBYTE
        POP     DX
OUTBYTE:
        MOV     DH,DL
        SHR     DL,1
        SHR     DL,1
        SHR     DL,1
        SHR     DL,1
        CALL    DIGIT
        MOV     DL,DH
DIGIT:
        AND     DL,0FH
        JZ      BLANKZER
        MOV     CL,0
BLANKZER:
        DEC     CH
        AND     CL,CH
        OR      DL,30H
        SUB     DL,CL
        CMP     BYTE PTR DISPFLG,0
        JZ      PRTCHR
        CMP     DL,30H
        JL      RET2
PRTCHR:
        MOV     AH,STD_CON_OUTPUT
        INT     21H
RET2:   RET

PRINTCNT:
        LODSB
        MOV     DL,AL
        INT     21H
        LOOP    PRINTCNT
        RET

EPRINT:
        CALL    CHECKERR
        JNZ     RET$1
        JMP     SHORT PRINT

DOCRLF:
        MOV     DX,OFFSET DG:CRLF
PRINT:
        MOV     AH,STD_CON_STRING_OUTPUT
        INT     21H
RET$1:  RET

DOTCOMBMES:
        CMP     [NOISY],0
        JZ      SUBERRP
        PUSH    DX
        CALL    PRINTCURRDIRERR
        MOV     DX,OFFSET DG:CENTRY
        CALL    EPRINT
        POP     DX
        CALL    EPRINT
        CALL    DOCRLF
        RET

SUBERRP:
        MOV     AL,1
        XCHG    AL,[ERRSUB]
        CMP     AL,0
        JNZ     RET32
        MOV     SI,OFFSET DG:NUL
        CALL    PRINTCURRDIRERR
        MOV     DX,OFFSET DG:BADSUBDIR
        CALL    EPRINT
RET32:  RET


FCB_TO_ASCZ:                            ;Convert DS:SI to ASCIIZ ES:DI
        MOV     CX,8
MAINNAME:
        LODSB
        CMP     AL,' '
        JZ      SKIPSPC
        STOSB
SKIPSPC:
        LOOP    MAINNAME
        LODSB
        CMP     AL,' '
        JZ      GOTNAME
        MOV     AH,AL
        MOV     AL,'.'
        STOSB
        XCHG    AL,AH
        STOSB
        MOV     CL,2
EXTNAME:
        LODSB
        CMP     AL,' '
        JZ      GOTNAME
        STOSB
        LOOP    EXTNAME

GOTNAME:
        XOR     AL,AL
        STOSB
        RET

CODE    ENDS
        END     CHKDSK