Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3471 lines
85 KiB

  1. page ,132
  2. title DIR Internal Command
  3. ;/*
  4. ; * Microsoft Confidential
  5. ; * Copyright (C) Microsoft Corporation 1991
  6. ; * All Rights Reserved.
  7. ; */
  8. ;*** DIR.ASM - DIR internal command
  9. comment % =================================================================
  10. This module replaces TCMD1A.ASM. The old module was titled
  11. "PART4 COMMAND Transient routines".
  12. From residual documentation, I surmise that TCMD.ASM originally
  13. contained the internal commands DIR, PAUSE, ERASE, TYPE, VOL, and
  14. VER. The file seems to have been successively split:
  15. TCMD -> TCMD1,TCMD2 -> TCMD1A,TCMD1B,TCMD2A,TCMD2B
  16. TCMD1A.ASM contained only the DIR command.
  17. Usage:
  18. ------
  19. DIR <filespec> /w /p /b /s /l /o<sortorder> /a<attriblist>
  20. DIR /?
  21. <filespec> may include any or none of: drive; directory path;
  22. wildcarded filename. If drive or directory path are
  23. omitted, the current defaults are used. If the
  24. file name or extension is omitted, wildcards are
  25. assumed.
  26. /w Wide listing format. Files are displayed in compressed
  27. 'name.ext' format. Subdirectory files are enclosed in
  28. brackets, '[dirname]'.
  29. /p Paged, or prompted listing. A screenful is displayed
  30. at a time. The name of the directory being listed appears
  31. at the top of each page.
  32. Bugbug: pages nead to be uniform length..?
  33. /b Bare listing format. Turns off /w or /p. Files are
  34. listed in compressed 'name.ext' format, one per line,
  35. without additional information. Good for making batch
  36. files or for piping. When used with /s, complete
  37. pathnames are listed.
  38. /s Descend subdirectory tree. Performs command on current
  39. or specified directory, then for each subdirectory below
  40. that directory. Directory header and footer is displayed
  41. for each directory where matching files are found, unless
  42. used with /b. /b suppresses headers and footers.
  43. Tree is explored depth first, alphabetically within the
  44. same level.
  45. Bugbug: hidden directories aren't searched.
  46. /l Display file names, extensions and paths in lowercase. ;M010
  47. /o Sort order. /o alone sorts by default order (dirs-first, name,
  48. extension). A sort order may be specified after /o. Any of
  49. the following characters may be used: nedsg (name, extension,
  50. date/time, size, group-dirs-first). Placing a '-' before any
  51. letter causes a downward sort on that field. E.g., /oe-d
  52. means sort first by extension in alphabetical order, then
  53. within each extension sort by date and time in reverse chronological
  54. order.
  55. /a Attribute selection. Without /a, hidden and system files
  56. are suppressed from the listing. With /a alone, all files
  57. are listed. An attribute list may follow /a, consisting of
  58. any of the following characters: hsdar (hidden, system,
  59. directory, archive, read-only). A '-' before any letter
  60. means 'not' that attribute. E.g., /ar-d means files that
  61. are marked read-only and are not directory files. Note
  62. that hidden or system files may be included in the listing.
  63. They are suppressed without /a but are treated like any other
  64. attribute with /a.
  65. /? Help listing. Display DIR useage information. ;M008;Handled externally
  66. /h has been removed. ;M008
  67. DIRCMD An environment variable named DIRCMD is parsed before the
  68. DIR command line. Any command line options may be specified
  69. in DIRCMD, and become defaults. /? will be ignored in DIRCMD.
  70. A filespec may be specified in DIRCMD and will be used unless
  71. a filespec is specified on the command line. Any switch
  72. specified in DIRCMD may be overridden on the command line.
  73. If the original DIR default action is desired for a particular
  74. switch, the switch letter may be preceded by a '-' on the
  75. command line. E.g.,
  76. /-w use long listing format
  77. /-p don't page the listing
  78. /-b don't use bare format
  79. /-s don't descend subdirectory tree
  80. /-o display files in disk order
  81. /-a suppress hidden and system files
  82. Notes:
  83. ------
  84. For sorted listings, file entries are loaded into the TPA buffer, which
  85. is usually about 64K in size. This allows sorts of up to 3000 files at
  86. a time. Each entry takes up 21 bytes in the buffer (see EntryStruc below).
  87. The byte after the last entry is 0FFh. The first byte of each entry is
  88. a flag byte which is made zero when the entry is loaded, and made one
  89. when the entry is used.
  90. Revision History
  91. ================
  92. M01 md 7/13/90 Use ROM BIOS data area to obtain screen height
  93. in the absence of ANSI.SYS
  94. M007 sa 8/1/90 Allow /p/b combination
  95. M008 sa 8/1/90 Remove /h parameter. Eliminate code used
  96. to internally handle /? message.
  97. M010 sa 8/5/90 Add support for /l (lowercase) option.
  98. M011 sa 8/5/90 Patch up bug where MS-DOS does not load the
  99. first FCB with the drive number when the drive
  100. letter in the command line is preceded by a
  101. switch. Now dir manually loads the drive
  102. number after parsing.
  103. M018 md 8/12/90 Increment the screen height by 1 when obtained
  104. from the ROM BIOS.
  105. M023 sa 8/31/90 Prevent DIR from failing if it encounters
  106. a subdirectory having len(pathname)>MAXPATH.
  107. Just skip over that subdirectory.
  108. M028 dbo 9/24/90 When country=US, sort by strict character
  109. byte value, rather than collating table.
  110. This to match MS-DOS Shell's sort order.
  111. ========================================================================= %
  112. ;*** SYMBOLS & MACROS
  113. .xlist
  114. .xcref
  115. include comsw.asm ; get COMMAND version switches
  116. include dossym.inc ; get DOS basic symbol set
  117. include syscall.inc ; get DOS call names
  118. include doscntry.inc ; get extended country info symbols
  119. include bpb.inc
  120. include filemode.inc
  121. include find.inc
  122. include comseg.asm ; define segment order
  123. include comequ.asm ; get equates for COMMAND routines
  124. include ioctl.inc ; get symbols for ioctl's
  125. include rombios.inc ; get ROM BIOS data definition
  126. .list
  127. .cref
  128. ;M008;NUM_DIR_SWS reduced by 2 for /h,/? not used
  129. ;M010;NUM_DIR_SWS increased by 2 for /l,/-l
  130. NUM_DIR_SWS equ 14 ; # of dir switch synonyms in Dir_Sw_Ptrs list
  131. ;M010;'lcase' replaces removed 'help' in OptionRec
  132. OptionRec record inmem:1,lcase:1,bare:1,subd:1,pagd:1,wide:1
  133. ; on/off bit record for /l, /b, /s, /p, /w options
  134. ; (order is hard-coded; see OnOffSw)
  135. ; Inmem is set when entries are loaded in memory.
  136. NUM_ATTR_LTRS equ 6 ; length of attribute letter list
  137. NUM_ORDER_LTRS equ 5 ; length of sort order letter list
  138. ResultBuffer struc ; structure of parse result buffer
  139. ValueType db ?
  140. ValueTag db ?
  141. SynPtr dw ?
  142. ValuePtr dd ?
  143. ResultBuffer ends
  144. ErrorRec record baddir:1,dev:1
  145. ; Error bits are:
  146. ; Invalid directory format
  147. ; File is device
  148. EntryStruc struc ; our private directory entry structure
  149. used db ? ; =0 until entry used, then =1
  150. filename db 8 dup (?) ; filename
  151. fileext db 3 dup (?) ; extension
  152. fileattr db ? ; file attributes
  153. filetime dw ? ; file time
  154. filedate dw ? ; file date
  155. filesize dd ? ; file size
  156. EntryStruc ends
  157. shove macro val ; hose-bag 8086 doesn't push immediate
  158. mov ax,val ; invisible, dangerous use of AX!
  159. push ax
  160. endm
  161. ;*** DATA
  162. DATARES segment public byte
  163. extrn Append_Flag:byte ; true when APPEND needs to be reset
  164. extrn Append_State:word ; state to reset APPEND to
  165. DATARES ends
  166. TRANDATA segment public byte
  167. extrn AttrLtrs:byte ; list of attribute letters
  168. extrn BadCd_Ptr:word ; "invalid directory" msg block
  169. extrn Bytes_Ptr:word ; "%1 bytes" msg block
  170. extrn BytMes_Ptr:word ; "%1 bytes free" msg block
  171. extrn DirCont_Ptr:word ; "(continuing %1)" msg block
  172. extrn DirDat_Yr:word ; year field of date msg block
  173. extrn DirDat_Mo_Day:word ; month/day field of date msg block
  174. extrn DirDatTim_Ptr:word ; date/time msg block
  175. extrn DirEnvVar:byte ; DIR environment variable name
  176. extrn DirHead_Ptr:word ; directory header message block
  177. extrn DirMes_Ptr:word ; "%1 File(s)" msg block
  178. extrn DirTim_Hr_Min:word ; time field of msg block
  179. extrn Dir_Sw_Ptrs:word ; list of DIR switch synonym ptrs
  180. extrn Disp_File_Size_Ptr:word ; file size message block
  181. extrn DMes_Ptr:word ; <DIR> message block
  182. extrn ErrParsEnv_Ptr:word ; "(Error occurred in env.." msg blk
  183. extrn Extend_Buf_Ptr:word ; extended error message block
  184. extrn Extend_Buf_Sub:byte ; # substitions in message block
  185. extrn Msg_Disp_Class:byte ; message display class
  186. extrn OrderLtrs:byte ; list of sort order letters
  187. extrn Parse_Dir:byte ; DIR parse block
  188. extrn String_Buf_Ptr:word ; message block ptr to string
  189. extrn Tab_Ptr:word ; tab output block
  190. extrn Total_Ptr:word ; "Total:" msg block
  191. TRANDATA ends
  192. TRANSPACE segment public byte
  193. extrn AttrSelect:byte ; attribute select states -
  194. extrn AttrSpecified:byte ; attribute mask -
  195. ; Attribute conditions are recorded in two steps.
  196. ; AttrSpecified indicates which attributes are to be checked.
  197. ; AttrSelect indicates which state the specified attributes
  198. ; must be in for a file to be included in the listing.
  199. ; Attributes not indicated in AttrSpecified are ignored when
  200. ; deciding which files to include.
  201. extrn Bits:word ; some option flags (see OptionRec)
  202. extrn BwdBuf:byte ; 'build working dir string' buf
  203. extrn BytCnt:word ; # bytes in TPA
  204. extrn Bytes_Free:word ; #bytes free for BytMes_Ptr msg block
  205. extrn CharBuf:byte ; character string buffer
  206. extrn ComSw:word ; error bits (see ErrorRec)
  207. extrn CountryPtrInfo:byte ; buffer for collating table ptr
  208. extrn CountryPtrId:byte ; info ID for collating table ptr
  209. extrn CountryPtr:dword ; collating table ptr
  210. extrn CurDrv:byte ; current drive # (0-based)
  211. extrn DestBuf:byte ; null-terminated sort codes -
  212. ; Sort order is specified as a series of 0 to 5 sort code
  213. ; bytes, followed by a zero byte.
  214. ; Codes are 1=name, 2=extension, 3=date&time, 4=size, and
  215. ; 5=filetype (subdir or not).
  216. ; Bit 7 of code is set for a downwards sort.
  217. extrn DestIsDir:byte ; indicator of delim char's in path
  218. extrn DestTail:word ; ptr to filename in pathname
  219. extrn Dir_Num:word ; #files for DirMes_Ptr msg block
  220. extrn DirBuf:byte ; DTA buffer for DOS calls
  221. extrn DirFlag:byte ; signal to PathCrunch routine
  222. extrn Display_Ioctl:word ; display info block for IOCTL call
  223. extrn EndDestBuf:byte ; end of DestBuf (sort order codes)
  224. extrn File_Size_High:word ; field for file size message block
  225. extrn File_Size_Low:word ; field for file size message block
  226. extrn FileCnt:word ; file count in a single directory
  227. extrn FileCntTotal:dword ; file count in all directories
  228. extrn FileSiz:dword ; file sizes in a single directory
  229. extrn FileSizTotal:dword ; file sizes in all directories
  230. extrn InternatVars:byte ; buffer for international info
  231. extrn LeftOnLine:byte ; entries left on current display line
  232. extrn LeftOnPage:word ; lines left on page
  233. extrn LinPerPag:word ; lines/page entry in Display_Ioctl
  234. extrn Msg_Numb:word ; extended error code
  235. extrn OldCtrlCHandler:dword ; old int 23 vector
  236. extrn Parse1_Syn:word ; ptr to matched synonym
  237. extrn PathCnt:word ; length of pathname (see PathPos)
  238. extrn PathPos:word ; ptr to pathname buffer (see SrcBuf)
  239. extrn PerLine:byte ; # entries per line
  240. extrn ResSeg:word ; RESGROUP seg addr
  241. extrn ScanBuf:byte ; buffer for environment value and
  242. ; subdirectory names
  243. extrn SrcBuf:byte ; pathname buffer
  244. extrn String_Ptr_2:word ; message substitution string ptr
  245. extrn Tpa:word ; TPA buffer seg addr
  246. TRANSPACE ends
  247. ;*** PRINCIPAL ROUTINES
  248. TRANCODE segment public byte
  249. extrn CError:near ; COMMAND error recycle point
  250. public Catalog ; our entry point
  251. break <DIR (Catalog) principal routines>
  252. assume cs:TRANGROUP,ds:TRANGROUP,es:nothing,ss:TRANGROUP
  253. ; Bugbug: Each routine should start with it's own ASSUME.
  254. ;*** Catalog - DIR command main routine
  255. ;
  256. ; ENTRY FCB #1 in PSP has drive# from cmd-line or default
  257. ; Cmd-line tail text is at 81h, terminated by 0Dh
  258. ; CS, DS, ES, SS = TRANGROUP seg addr
  259. ; Tpa = TPA buffer seg addr
  260. ; BytCnt = # bytes in TPA buffer
  261. ;
  262. ; EXIT nothing
  263. ;
  264. ; USED AX,BX,CX,DX,SI,DI,BP
  265. ;
  266. ; ERROR EXITS
  267. ;
  268. ; Errors are handled by setting up error message pointers
  269. ; for Std_EPrintf and jumping to CError. Syntax errors in
  270. ; the environment variable, however, are handled by printing
  271. ; an error message and continuing.
  272. ;
  273. ; EFFECTS
  274. ;
  275. ; Directory listing is displayed (on standard output).
  276. ; APPEND is disabled. HeadFix routine is expected to
  277. ; restore APPEND state.
  278. ; Working directory may be changed. The user's default
  279. ; directory is saved and flagged for restoration by RestUDir
  280. ; during COMMAND cycle.
  281. ; Lots of variables may be changed in TRANSPACE segment.
  282. ;
  283. ; NOTES
  284. ;
  285. ; ES = TRANGROUP seg addr except when used to address the
  286. ; the TPA buffer, where directory entries are loaded from disk.
  287. Catalog proc
  288. call SetDefaults
  289. call ParseEnvironment
  290. call ParseCmdLine
  291. jnc @F ; no parse error
  292. jmp catErr ; error msg is set up
  293. @@: call SetOptions
  294. call SetCollatingTable
  295. ; Drive # to operate on has already been placed in FCB by
  296. ; COMMAND preprocessing. OkVolArg & PathCrunch depend on that.
  297. test Bits,mask bare
  298. jnz @F ; don't display volume info for /b
  299. invoke OkVolArg ; find & display volume info
  300. sub LeftOnPage,2 ; record display lines used by volume info
  301. jmp short catCrunch
  302. ; OkVolArg side effects:
  303. ; APPEND is disabled;
  304. ; DTA established at DirBuf;
  305. ; Filename fields in FCB are wildcarded.
  306. @@:
  307. ; OkVolArg wasn't executed, so we have to do these ourselves.
  308. invoke DisAppend ; disable APPEND
  309. mov dx,offset TRANGROUP:DirBuf
  310. mov ah,Set_DMA
  311. int 21h ; set DTA
  312. mov di,FCB ; ES:DI = ptr to FCB
  313. inc di ; ES:DI = ptr to filename field of FCB
  314. mov al,'?' ; AL = wildcard character
  315. mov cx,11
  316. rep stosb ; wildcard filename field
  317. catCrunch:
  318. call CrunchPath ; crunch pathname to get directory and filename
  319. jc catRecErr ; handle recorded or extended error
  320. ; User's directory has been saved, we've changed to specified directory.
  321. ; ComSw = error bits for later use
  322. ; FCB contains parsed filename
  323. cmp ComSw,0
  324. jne catRecErr ; handle recorded error
  325. call InstallCtrlC ; install control-C handler
  326. call ZeroTotals ; zero grand totals
  327. call ListDir ; list main directory
  328. jc catExtErr
  329. test Bits,mask subd
  330. jz @F ; subdirectories option not set
  331. call ListSubds ; list subdirectories
  332. jc catExtErr
  333. @@:
  334. ; Check if any files were found.
  335. test Bits,mask bare
  336. jnz catRet ; don't bother for bare format
  337. mov ax,word ptr FileCntTotal
  338. or ax,ax
  339. jz catNoFiles ; no files found
  340. call DisplayTotals ; display trailing grand totals
  341. jmp short catRet ; all done
  342. catRecErr:
  343. ; ComSw may have error bit set. If not, do extended error.
  344. test ComSw,mask dev
  345. jnz catNoFiles ; filename is device, respond 'file not found'
  346. test ComSw,mask baddir
  347. jz catExtErr ; no ComSw error bits, must be extended error
  348. mov dx,offset TRANGROUP:BadCd_Ptr ; invalid directory
  349. jmp short catErr
  350. catNoFiles:
  351. ; Display header and force 'file not found' message.
  352. call DisplayHeader
  353. mov ax,ERROR_FILE_NOT_FOUND
  354. mov Msg_Disp_Class,EXT_MSG_CLASS
  355. mov dx,offset TRANGROUP:Extend_Buf_ptr
  356. mov Extend_Buf_ptr,ax
  357. jmp short catErr
  358. catExtErr:
  359. ; DOS has returned an error status. Get the extended error#, and
  360. ; set up an error message, changing 'No more files' error
  361. ; to 'File not found' error.
  362. invoke Set_Ext_Error_Msg
  363. cmp Extend_Buf_Ptr,ERROR_NO_MORE_FILES
  364. jne @F
  365. mov Extend_Buf_Ptr,ERROR_FILE_NOT_FOUND
  366. @@:
  367. ; Error exit. Error message information has been set up
  368. ; for Std_EPrintf.
  369. catErr: jmp CError ; go to COMMAND error recycle point
  370. catRet: ret
  371. Catalog endp
  372. ;*** SetDefaults - set default pathname, options
  373. ;
  374. ; ENTRY DS = TRANGROUP seg addr
  375. ;
  376. ; EXIT nothing
  377. ;
  378. ; USED AX,DI
  379. ;
  380. ; EFFECTS
  381. ; SrcBuf = '*',EOL - default pathname
  382. ; PathPos = ptr to pathname
  383. ; PathCnt = length of pathname
  384. SetDefaults proc
  385. mov di,offset TRANGROUP:SrcBuf ; DI = ptr to pathname buffer
  386. mov PathPos,di ; PathPos = ptr to pathname
  387. mov al,STAR
  388. stosb
  389. mov al,END_OF_LINE_IN
  390. stosb ; SrcBuf = '*',0Dh
  391. mov PathCnt,1 ; PathCnt = pathname length
  392. xor ax,ax ; AX = 0
  393. mov ComSw,ax ; = no error
  394. mov Bits,ax ; = options off
  395. mov DestBuf,al ; = no sort
  396. mov AttrSpecified,ATTR_HIDDEN+ATTR_SYSTEM
  397. mov AttrSelect,al ; exclude hidden, system files
  398. ret
  399. SetDefaults endp
  400. ;*** ParseEnvironment - find and parse our environment variable
  401. ;
  402. ; Find our environment variable and parse it. If a parse
  403. ; error occurs, issue an error message. The parse results
  404. ; up to the error will still have effect. Always leave
  405. ; the option variables in a useable state.
  406. ;
  407. ; ENTRY DS = TRANGROUP seg addr
  408. ;
  409. ; EXIT nothing
  410. ;
  411. ; USED AX,BX,CX,DX,SI,DI
  412. ;
  413. ; EFFECTS
  414. ;
  415. ; Bits may contain new option settings.
  416. ; DestBuf may contain new series of sort codes.
  417. ; AttrSpecified, AttrSelect may contain new attribute conditions.
  418. ; SrcBuf may contain a new default pathname/filespec.
  419. ; PathPos, PathCnt updated for new pathname.
  420. ;
  421. ; If a parse error occurred, an error message will be issued.
  422. ParseEnvironment proc
  423. call GetEnvValue ; get environment variable value
  424. jc peRet ; name not found in environment
  425. ; SI = ptr to value of environment variable, in TRANGROUP seg
  426. call ParseLine ; parse environment value
  427. cmp ax,END_OF_LINE
  428. je peRet ; successful completion
  429. ; Some kind of parse error occurred.
  430. ; We're set up for a Std_EPrintf call.
  431. invoke Std_EPrintf ; display the parse error
  432. mov Msg_Disp_Class,UTIL_MSG_CLASS ; restore default msg class
  433. mov dx,offset TRANGROUP:ErrParsEnv_Ptr
  434. invoke Printf_Crlf ; "(Error occurred in environment.."
  435. ;M008;Internal handling of /? removed
  436. ;peOk: and Bits,not mask help ; disallow /h in environment variable
  437. peRet: ret
  438. ParseEnvironment endp
  439. ;*** ParseCmdLine - parse and record command line parameters
  440. ;
  441. ; ENTRY PSP offset 81h is beginning of cmd line buffer
  442. ; DS, ES, CS = TRANGROUP seg addr
  443. ;
  444. ; EXIT CY = set if parse error occurred
  445. ;
  446. ; If parse error occurred, we're set up for Std_EPrintf call:
  447. ; AX = system parser error code
  448. ; DX = ptr to message block
  449. ;
  450. ; USED AX,BX,CX,DX,SI,DI
  451. ;
  452. ; EFFECTS
  453. ;
  454. ; Bits may contain new option settings.
  455. ; DestBuf may contain new series of sort codes.
  456. ; AttrSpecified, AttrSelect may contain new attribute conditions.
  457. ; SrcBuf may contain a new default pathname/filespec.
  458. ; PathPos, PathCnt updated for new pathname.
  459. ;
  460. ; If parse error occurred, we're set up for Std_EPrintf call:
  461. ; Msg_Disp_Class = parse error class
  462. ; Byte after last parameter in text is zeroed to make ASCIIZ string
  463. ; Message block (see DX) is set up for parse error message
  464. ParseCmdLine proc
  465. mov si,81h ; SI = ptr to cmd-line tail text
  466. call ParseLine ; parse cmd line tail
  467. cmp AX,END_OF_LINE
  468. je pcOk ; parse completed successfully
  469. ; A parse error occurred. We're all set up for message output.
  470. stc ; return failure
  471. jmp short pcRet
  472. pcOk: clc ; return success
  473. pcRet: ret
  474. ParseCmdLine endp
  475. ;*** SetCollatingTable - set up character collating table for sorting
  476. ;
  477. ; If country is other than USA, try to get a collating table
  478. ; for character sorting. For USA, use straight byte values.
  479. ; This is so DIR behaves like the MS-DOS Shell, which sorts
  480. ; by straight byte values in the USA for better performance.
  481. ;
  482. ; ENTRY ES = TRANGROUP seg addr
  483. ;
  484. ; EXIT nothing
  485. ;
  486. ; USED AX,BX,CX,DX,DI
  487. ;
  488. ; EFFECTS
  489. ;
  490. ; If collating table is set -
  491. ; CountryPtrId = 6.
  492. ; CountryPtr points to collating table.
  493. ;
  494. ; Otherwise -
  495. ; CountryPtrId = 0.
  496. SetCollatingTable proc
  497. ; Begin modification M028
  498. mov dx,offset TRANGROUP:InternatVars
  499. ; DS:DX = ptr to international info buffer
  500. mov ax,INTERNATIONAL shl 8
  501. ; AX = 'Get current country info'
  502. int 21h ; call DOS
  503. jc scNoTable ; error - so don't collate
  504. ; BX = country code
  505. cmp bx,1
  506. je scNoTable ; we're in USA, don't collate
  507. ; End modification M028
  508. ;* Country code is other than USA. Try to get a collating table.
  509. mov ax,(GETEXTCNTRY shl 8) + SETCOLLATE
  510. ; AH = 'Get Extended Country Info'
  511. ; AL = 'Get Pointer to Collating Table'
  512. mov bx,-1 ; BX = code page of interest = CON
  513. mov cx,5 ; CX = length of info buffer
  514. mov dx,bx ; DX = country ID = default
  515. mov di,offset TRANGROUP:CountryPtrInfo
  516. ; ES:DI = ptr to info buffer
  517. int 21h ; call DOS
  518. jnc scRet ; success
  519. ;* Set CountryPtrId = 0 to signal no collating table.
  520. scNoTable: ;M028
  521. mov CountryPtrId,0
  522. scRet: ret
  523. SetCollatingTable endp
  524. ;*** SetOptions - check and set options
  525. ;
  526. ; ENTRY nothing
  527. ;
  528. ; EXIT nothing
  529. ;
  530. ; USED AX,BX,CX,DX
  531. ;
  532. ; EFFECTS
  533. ;
  534. ; Bits may contain modified option settings.
  535. ; Display_Ioctl table, including LinPerPag variable, is filled in.
  536. ; LeftOnPage is initialized to # lines till end of page is handled.
  537. ; PerLine is set according to /w presence.
  538. SetOptions proc
  539. ; If bare listing requested, cancel wide listings.
  540. test Bits,mask bare
  541. jz @F
  542. and Bits,not mask wide ;M007;Allow /p with /b
  543. @@:
  544. ; Set # lines per display page.
  545. ;M01 Obtain screen height from ROM BIOS data area
  546. ;
  547. ;M01 mov LinPerPag,LINESPERPAGE ; default value
  548. ifndef JAPAN
  549. push ds
  550. MOV AX,ROMBIOS_DATA ; Get ROM Data segment
  551. MOV DS,AX ;
  552. Assume DS:ROMBIOS_DATA
  553. MOV al,CRT_Rows ; Get max rows
  554. pop ds ;
  555. Assume DS:Trangroup
  556. or al,al ; If zero specified
  557. jnz @F ;
  558. endif
  559. MOV al,LINESPERPAGE ; assume 24 rows
  560. @@:
  561. xor ah,ah
  562. ifndef JAPAN
  563. inc al ; height + 1 ;M018
  564. endif
  565. mov LinPerPag,ax ; set the rows now
  566. ; Now the console driver can change the rows if it knows better (M01 end)
  567. mov ax,(IOCTL shl 8)+GENERIC_IOCTL_HANDLE ; IOCTL for handles
  568. mov bx,STDOUT ; handle #
  569. mov ch,IOC_SC ; screen
  570. mov cl,GET_GENERIC ; get display info
  571. mov dx,offset TRANGROUP:Display_Ioctl ; info block
  572. int 21h ; call DOS
  573. mov ax,LinPerPag ; AX = # lines per page
  574. mov LeftOnPage,ax ; initialize # lines left on page
  575. ; Set # entries per line.
  576. mov PerLine,NORMPERLIN ; # entries per line without /w
  577. test Bits,mask wide
  578. jz @F
  579. mov PerLine,WIDEPERLIN ; # entries per line with /w
  580. @@:
  581. ;M011;start;The following code checks if a drive
  582. ;letter has been parsed into SrcBuf, and if
  583. ;so, the correct drive number is loaded into
  584. ;the first FCB, at offset 5C.
  585. cmp TRANGROUP:[SrcBuf+1],COLON_CHAR ; is this a drive letter?
  586. jne soRet
  587. mov al,TRANGROUP:[SrcBuf] ; load drive letter into al
  588. and al,not 20h ; capitalize ASCII drive letter (LowerCase-32)-->UpperCase
  589. sub al,'@' ; convert to 1-based number (1=A)
  590. mov ds:FCB,al ; store in first FCB
  591. ;M011;end
  592. soRet: ret
  593. SetOptions endp
  594. ;*** CrunchPath - analyze supplied or default pathname
  595. ;
  596. ; ENTRY PathPos = ptr to pathname buffer
  597. ; PathCnt = length of pathname, not incl trailing delimiter
  598. ; Pathname in buffer must end in delimiter (like CR) and
  599. ; must have space for another char after the delimiter.
  600. ;
  601. ; EXIT CY = clear if no error
  602. ; We are changed to directory found in pathname
  603. ; Previous directory ready to be restored via RestUDir
  604. ; FCB filename fields contain filename (possibly w/ wildcards)
  605. ;
  606. ; If error occurred,
  607. ; CY = set
  608. ; ComSw = error bits (see ErrorRec)
  609. ; If ComSw not set,
  610. ; Ready for DOS Get Extended Error call
  611. CrunchPath proc
  612. call FileIsDevice
  613. jne @F ; not a device, skip ahead
  614. or ComSw,mask dev ; signal file is device
  615. jmp short cpErr ; return error
  616. @@:
  617. push PathPos ; save ptr to pathname
  618. mov DirFlag,-1 ; tell PathCrunch not to parse file into FCB
  619. invoke PathCrunch ; change to directory in pathname
  620. mov DirFlag,0 ; reset our little flag
  621. pop si ; SI = ptr to pathname
  622. jc cpNoDir ; didn't find directory path
  623. jz cpRet ; found directory path w/ no filename
  624. ; - leave wildcard default in FCB and return
  625. ;* We found a directory, and there was a filename attached.
  626. ; DestTail = ptr to ASCIIZ filename
  627. mov si,DestTail ; SI = ptr to filename
  628. jmp short cpFile ; go parse the file into FCB
  629. ;* PathCrunch failed to find a directory in the pathname.
  630. ;
  631. ; Msg_Numb = error code
  632. ; DestIsDir = nonzero if path delimiter char's occur in pathname
  633. ; SI = ptr to pathname (now an ASCIIZ string)
  634. cpNoDir:
  635. mov ax,Msg_Numb ; AX = error code from PathCrunch
  636. or ax,ax
  637. jnz cpErr ; error occurred - return it
  638. cmp DestIsDir,0
  639. je cpMaybe ; no path delimiters seen, maybe it's a file
  640. or ComSw,mask baddir ; signal invalid directory name
  641. jmp short cpErr ; return error
  642. cpMaybe:
  643. ; SI = ptr to pathname
  644. cmp byte ptr [si+1],COLON_CHAR
  645. jnz @F ; no drive specifier, skip ahead
  646. lodsw ; SI = ptr past drive specifier "d:"
  647. @@: cmp [si],".."
  648. jne cpFile ; if not "..", treat as a file
  649. cmp byte ptr [si+2],0
  650. jne cpFile ; or if there's more after "..", treat as file
  651. or ComSw,mask baddir ; signal invalid directory
  652. jmp short cpErr ; return error
  653. ; The preceding code was taken from the old DIR routine.
  654. ; It's garbage, I'm afraid. It's meant to check for ".."
  655. ; occurring when we're at the root directory. Too bad it
  656. ; doesn't handle problems with "..\..", etc.
  657. ; We're ready to parse a filename into the FCB.
  658. ; SI = ptr to ASCIIZ filename
  659. cpFile: mov di,FCB ; DI = ptr to FCB
  660. mov ax,(PARSE_FILE_DESCRIPTOR shl 8) or 0Eh
  661. ; wildcards already in FCB used as defaults
  662. int 21h
  663. clc ; return success
  664. jmp short cpRet
  665. cpErr: stc ; return error
  666. cpRet: ret
  667. CrunchPath endp
  668. ;*** InstallCtrlC - install our private control-C handler
  669. ;
  670. ; Put our control-c handler in front of command.com's default
  671. ; handler, to make sure the user's default directory gets restored.
  672. ; This shouldn't be necessary, but, for now, there are situations
  673. ; where the TDATA segment is left in a modified state when a
  674. ; control-c occurs. This means that the transient will be
  675. ; reloaded, and the user's directory cannot be restored.
  676. ;
  677. ; Bugbug: fix the wider problem? Involves message services. Ugly.
  678. ;
  679. ; ENTRY nothing
  680. ;
  681. ; EXIT nothing
  682. ;
  683. ; USED AX,BX,DX
  684. ;
  685. ; EFFECTS
  686. ;
  687. ; CtrlCHandler address placed in int 23 vector.
  688. ;
  689. ; NOTE
  690. ;
  691. ; Command.com's basic control-c handler will be restored
  692. ; to the int 23 vector by the HeadFix routine, after DIR finishes.
  693. InstallCtrlC proc
  694. push es ; preserve ES
  695. mov ax,(GET_INTERRUPT_VECTOR shl 8) + 23h
  696. int 21h
  697. mov word ptr OldCtrlCHandler,bx ; save old int 23 vector
  698. mov word ptr OldCtrlCHandler+2,es
  699. pop es ; restore ES
  700. mov dx,offset TRANGROUP:CtrlCHandler ; DS:DX = ptr to CtrlCHandler
  701. mov ax,(SET_INTERRUPT_VECTOR shl 8) + 23h
  702. int 21h
  703. ret
  704. InstallCtrlC endp
  705. ;*** ListSubds - search and list files in subdirectories
  706. ;
  707. ; ENTRY Current directory (on selected drive) is top of subdir tree
  708. ; FCB is still set up for file searches
  709. ; Bits, AttrSpecified, AttrSelect, DestBuf all still set up
  710. ;
  711. ; EXIT CY = clear if no error
  712. ; FileCnt = # files found & displayed
  713. ; FileSiz = total size of files found
  714. ;
  715. ; If error,
  716. ; CY = set
  717. ; Ready for DOS Get Extended Error call
  718. ;
  719. ; USED AX,BX,CX,DX,SI,DI,BP
  720. ;
  721. ; EFFECTS
  722. ;
  723. ; FileCntTotal, FileSizTotal are updated.
  724. ; Subdirectories may be listed on standard output device.
  725. ;
  726. ; NOTES
  727. ;
  728. ; ListSubds seeds the recursive entry point lsNode with a ptr
  729. ; to a buffer where we'll stack up subdirectory filenames.
  730. ; Each name is stored ASCIIZ.
  731. ListSubds proc
  732. invoke SetRest1 ; make sure user's dir gets restored
  733. mov bx,offset TRANGROUP:ScanBuf ; BX = ptr to child name buffer
  734. lsNode:
  735. mov byte ptr ds:[bx],0 ; start with null child name
  736. lsLoop:
  737. call FindNextChild ; search for next subdirectory
  738. jc lsErr ; search failed - examine error
  739. mov dx,bx ; DX = ptr to child's name
  740. call ChangeDir ; enter child directory
  741. ; M023;start
  742. jnc @F ; check for error
  743. cmp ax,ERROR_PATH_NOT_FOUND ; error due to len(pathname)>MAXPATH?
  744. je lsLoop ; yes, skip over this subdirectory
  745. jmp SHORT lsRet ; no, other error: DIR must fail
  746. ; M023;end
  747. @@: push bx
  748. call ListDir ; list the directory
  749. pop bx
  750. ; Note we're ignoring errors returned here.
  751. mov di,bx ; DI = ptr to child's name
  752. mov cx,13 ; CX = max name length w/ null
  753. xor al,al ; AL = zero byte to look for
  754. repne scasb ; DI = ptr to next name pos'n in buf
  755. push bx ; save ptr to child's name
  756. mov bx,di ; BX = ptr to next name pos'n in buf
  757. call lsNode ; recurse from new node
  758. pop bx ; BX = ptr to child's name
  759. pushf ; save error condition
  760. shove 0
  761. shove ".."
  762. mov dx,sp ; DX = ptr to "..",0 on stack
  763. call ChangeDir ; return to parent directory
  764. pop ax ; restore stack
  765. pop ax
  766. popf ; restore error condition from child
  767. jc lsRet ; return error
  768. jmp lsLoop ; look for more children
  769. lsErr:
  770. invoke Get_Ext_Error_Number ; AX = extended error code
  771. cmp ax,ERROR_FILE_NOT_FOUND
  772. je lsRet ; file not found, we're ok
  773. cmp ax,ERROR_NO_MORE_FILES
  774. je lsRet ; no more files, we're ok
  775. stc ; return other errors
  776. lsRet: ret
  777. ListSubds endp
  778. break <DIR support routines>
  779. ;*** SUPPORT ROUTINES
  780. ;*** CheckChild - check potential subdirectory name for FindNextChild
  781. ;
  782. ; ENTRY DirBuf contains DOS Find-buffer with potential child
  783. ; BX = ptr to last child's name
  784. ; BP = ptr to temp child's name
  785. ;
  786. ; EXIT nothing
  787. ;
  788. ; USED AX,CX,SI,DI
  789. ;
  790. ; EFFECTS
  791. ;
  792. ; Filename pointed to by BP may be changed.
  793. ;
  794. ; NOTES
  795. ;
  796. ; Potential filename replaces temp filename if:
  797. ; it's a subdirectory file;
  798. ; it doesn't start with a '.';
  799. ; it's alphanumerically greater than last child's name;
  800. ; and it's alphanumerically less than temp name.
  801. CheckChild proc
  802. test DirBuf.find_buf_attr,ATTR_DIRECTORY
  803. jz ccRet ; not a subdirectory file- return
  804. cmp DirBuf.find_buf_pname,'.'
  805. je ccRet ; starts with a dot- return
  806. mov si,offset TRANGROUP:DirBuf+find_buf_pname
  807. mov di,bx
  808. call CmpAscz ; compare candidate to last child's name
  809. jna ccRet ; it's not above it- return
  810. mov si,offset TRANGROUP:DirBuf+find_buf_pname
  811. mov di,bp
  812. call CmpAscz ; compare candidate to temp name
  813. jnb ccRet ; it's not below it- return
  814. ; New kid is alright. Copy to temp.
  815. mov si,offset TRANGROUP:DirBuf+find_buf_pname
  816. mov di,bp
  817. mov cx,13
  818. rep movsb
  819. ccRet: ret
  820. CheckChild endp
  821. ;*** CmpEntry - compare one directory entry to another in sort order
  822. ;
  823. ; Compare one directory entry against another according to
  824. ; the sort codes in DestBuf. One or more comparisons
  825. ; may be made of file name, extension, time/date, and
  826. ; size. Comparisons may be made for upward or downward
  827. ; sort order.
  828. ;
  829. ; ENTRY ES:BX = ptr to entry to compare
  830. ; ES:BP = ptr to entry to be compared against
  831. ; DestBuf contains sort codes (see DestBuf)
  832. ; DS = TRANGROUP seg addr
  833. ;
  834. ; EXIT BX = unchanged
  835. ; BP = unchanged
  836. ; Condition flags set for same, above, or below
  837. ; comparing BX entry against BP entry.
  838. ; 'Same, above, below' translate to 'same, after, before'.
  839. ;
  840. ; USED: AX,CX,DX,SI,DI
  841. CmpEntry proc
  842. mov si,offset TRANGROUP:DestBuf ; (DS:SI) = ptr to sort codes
  843. ceLoop:
  844. xor ax,ax ; AX = 0
  845. mov al,[si] ; AL = sort code
  846. or al,al
  847. jz ceDone ; sort code is zero, we're done
  848. inc si ; DS:SI = ptr to next sort code
  849. push si ; save ptr to next sort code
  850. dec al
  851. sal al,1 ; AX = index into cmp call table
  852. ; CY set for downward sort order
  853. mov si,ax ; SI = index into cmp call table
  854. mov ax,cs:FieldCmps[si] ; AX = addr of compare routine
  855. jc ceDn ; downwards sort - go swap entries
  856. call ax ; do upwards sort
  857. jmp short @F
  858. ceDn:
  859. xchg bx,bp ; swap entry ptrs for downward sort order
  860. call ax ; do sort
  861. xchg bx,bp ; swap ptrs back
  862. @@:
  863. pop si ; SI = ptr to next sort code
  864. je ceLoop ; compare showed no difference, keep trying
  865. ceDone:
  866. ; Get here either from unequal compare or sort code = 0.
  867. ; In the latter case, condition codes indicate equality,
  868. ; which is correct.
  869. ret
  870. FieldCmps label word ; call table of entry comparisons
  871. dw CmpName
  872. dw CmpExt
  873. dw CmpTime
  874. dw CmpSize
  875. dw CmpType
  876. CmpEntry endp
  877. ;*** CmpName - compare file name of two entries
  878. ;*** CmpExt - compare extension of two entries
  879. ;
  880. ; ENTRY ES:BX = ptr to one entry
  881. ; ES:BP = ptr to another entry
  882. ;
  883. ; EXIT BX = unchanged
  884. ; BP = unchanged
  885. ; Condition flags set for same, above, or below
  886. ; comparing BX entry to BP entry.
  887. ;
  888. ; USED: AX,CX,DX,SI,DI
  889. CmpName proc
  890. mov si,bx ; ES:SI = ptr to BX entry
  891. mov di,bp ; ES:DI = ptr to BP entry
  892. add si,filename ; ES:SI = ptr to BX name
  893. add di,filename ; ES:DI = ptr to BP name
  894. mov cx,size filename; CX = length of name
  895. jmp short CmpStr
  896. CmpExt: mov si,bx ; ES:SI = ptr to BX entry
  897. mov di,bp ; ES:DI = ptr to BP entry
  898. add si,fileext ; ES:SI = ptr to BX extension
  899. add di,fileext ; ES:DI = ptr to BP extension
  900. mov cx,size fileext ; CX = length of extension field
  901. ; Bugbug: use symbol for subfunction code.
  902. CmpStr: cmp CountryPtrId,6
  903. jne cnNoCollTable ; no collating table available
  904. ;* Compare strings using collating table.
  905. ;
  906. ; ES:SI = ptr to 1st string
  907. ; ES:DI = ptr to 2nd string
  908. ; CX = length
  909. push bp ; preserve BP
  910. push bx ; preserve BX
  911. push ds ; preserve DS
  912. lds bx,CountryPtr ; DS:BX = ptr to collating table
  913. assume ds:NOTHING
  914. mov bp,ds:[bx] ; BP = size of collating table
  915. inc bx
  916. inc bx ; DS:BX = ptr to collating values
  917. ; DS:[BX]-2 = size of table
  918. xor ax,ax ; AX = 0 for starters
  919. ; Bugbug: Investigate removing collating table length checks.
  920. cnNextChar:
  921. mov al,es:[di] ; AL = AX = char from 2nd string
  922. inc di ; ES:DI = ptr to next char 2nd string
  923. cmp ax,bp ; compare to collating table length
  924. jae @F ; char not in table
  925. xlat
  926. @@: ; AL = AX = collating value
  927. mov dx,ax ; DX = collating value from 2nd string
  928. lods byte ptr es:[si] ; AL = AX = char from 1st string
  929. ; ES:SI = ptr to next char 1st string
  930. cmp ax,bp ; compare to collating table length
  931. jae @F ; char not in table
  932. xlat
  933. @@: ; AL = AX = collating value
  934. cmp ax,dx ; compare collating values
  935. ifdef DBCS ; DBCS tail byte must not use
  936. ; collating table
  937. jnz cnNot_Same
  938. mov al,es:[di-1] ; get previous 2nd string character
  939. invoke testkanj
  940. jz cnDo_Next ; if it was not DBCS lead byte
  941. mov al,es:[di] ; get tail byte from 2nd string
  942. cmp es:[si],al ; compare with 1st strings tail byte
  943. jnz cnNot_Same
  944. inc si ; pass tail byte
  945. inc di
  946. dec cx
  947. cnDo_Next:
  948. loop cnNextChar
  949. cnNot_Same:
  950. else ; Not DBCS
  951. loope cnNextChar ; until unequal or no more left
  952. endif
  953. pop ds ; restore DS
  954. assume ds:TRANGROUP
  955. pop bx ; restore BX
  956. pop bp ; restore BP
  957. ret
  958. ;* If no collating table is available, simply compare raw ASCII values.
  959. ; Don't we wish we could just do this all the time? Sigh.
  960. cnNoCollTable:
  961. rep cmps byte ptr es:[si],[di]
  962. ret
  963. CmpName endp
  964. ;*** CmpTime - compare entries by date/time
  965. ;
  966. ; ENTRY ES:BX = ptr to one entry
  967. ; ES:BP = ptr to another entry
  968. ;
  969. ; EXIT BX = unchanged
  970. ; BP = unchanged
  971. ; Condition flags set for same, above, or below
  972. ; comparing BX entry to BP entry.
  973. ;
  974. ; USED: CX,SI,DI
  975. ;
  976. ; NOTE Filetime and filedate fields in our private entry
  977. ; structure must be adjacent and in that order.
  978. CmpTime proc
  979. mov si,bx
  980. mov di,bp
  981. add si,filedate + size filedate - 1
  982. add di,filedate + size filedate - 1
  983. mov cx,size filetime + size filedate
  984. std
  985. repe cmps byte ptr es:[si],[di]
  986. cld
  987. ret
  988. CmpTime endp
  989. ;*** CmpSize - compare entries by size
  990. ;
  991. ; ENTRY ES:BX = ptr to one entry
  992. ; ES:BP = ptr to another entry
  993. ;
  994. ; EXIT BX = unchanged
  995. ; BP = unchanged
  996. ; Condition flags set for same, above, or below
  997. ; comparing BX entry to BP entry.
  998. ;
  999. ; USED: CX,SI,DI
  1000. CmpSize proc
  1001. mov si,bx
  1002. mov di,bp
  1003. add si,filesize + size filesize - 1
  1004. add di,filesize + size filesize - 1
  1005. mov cx,size filesize
  1006. std
  1007. repe cmps byte ptr es:[si],[di]
  1008. cld
  1009. ret
  1010. CmpSize endp
  1011. ;*** CmpType - compare entries by file type (subdirectory or not)
  1012. ;
  1013. ; ENTRY ES:BX = ptr to one entry
  1014. ; ES:BP = ptr to another entry
  1015. ;
  1016. ; EXIT BX = unchanged
  1017. ; BP = unchanged
  1018. ; Condition flags set for same, above, or below
  1019. ; comparing BX entry to BP entry.
  1020. ;
  1021. ; USED: AX
  1022. CmpType proc
  1023. mov al,es:[bx].fileattr
  1024. mov ah,es:[bp].fileattr
  1025. and ax,(ATTR_DIRECTORY shl 8) + ATTR_DIRECTORY
  1026. cmp ah,al
  1027. ret
  1028. CmpType endp
  1029. ;*** DefaultAttr - set default attribute conditions
  1030. ;
  1031. ; ENTRY nothing
  1032. ;
  1033. ; EXIT CY clear
  1034. ;
  1035. ; USED
  1036. ;
  1037. ; EFFECTS
  1038. ;
  1039. ; AttrSpecified, AttrSelect are updated with new attribute conditions.
  1040. DefaultAttr proc
  1041. mov AttrSpecified,ATTR_HIDDEN+ATTR_SYSTEM ; specify H and S
  1042. mov AttrSelect,0 ; H and S must be off
  1043. clc ; return success
  1044. ret
  1045. DefaultAttr endp
  1046. ;*** DisplayTotals - display grand total stats
  1047. ;
  1048. ; If we searched subdirectories, display the total # files found
  1049. ; and total size of files found.
  1050. ; Display disk space remaining.
  1051. ;
  1052. ; ENTRY FileCntTotal, FileSizTotal contain correct values
  1053. ; Bits contains setting of /s
  1054. ; FCB contains drive #
  1055. ;
  1056. ; EXIT nothing
  1057. ;
  1058. ; USES AX,DX
  1059. ; FileSiz
  1060. DisplayTotals proc
  1061. test Bits,mask subd
  1062. jz dtFree ; no subdirectories- do bytes free
  1063. invoke Crlf2 ; start on new line
  1064. call UseLine
  1065. mov dx,offset TRANGROUP:Total_Ptr
  1066. invoke Std_Printf ; "Total:",cr,lf
  1067. call UseLine
  1068. mov ax,word ptr FileCntTotal ; AX = # files found mod 64K
  1069. mov si,offset TRANGROUP:FileSizTotal
  1070. mov di,offset TRANGROUP:FileSiz
  1071. movsw
  1072. movsw ; move total size to size variable
  1073. call DisplayCntSiz ; display file count & size
  1074. dtFree:
  1075. mov ah,GET_DRIVE_FREESPACE ; AH = DOS Get Free Space function
  1076. mov dl,byte ptr ds:FCB ; DL = drive#
  1077. int 21h ; call DOS
  1078. cmp ax,-1 ; check 'invalid drive' return code
  1079. jz dtRet ; can't get drive space - return
  1080. mul cx
  1081. mul bx
  1082. mov Bytes_Free,ax
  1083. mov Bytes_Free+2,dx
  1084. mov dx,offset TRANGROUP:BytMes_Ptr
  1085. invoke Std_Printf ; "nnn bytes free",cr,lf
  1086. call UseLine
  1087. dtRet: ret
  1088. DisplayTotals endp
  1089. ;*** FileIsDevice - see if file looks like a device
  1090. ;
  1091. ; ENTRY PathPos = ptr to pathname
  1092. ; PathCnt = length of pathname w/o terminating char
  1093. ; DirBuf is DOS DTA
  1094. ;
  1095. ; EXIT ZR = set if file looks like a device
  1096. ;
  1097. ; USED AX,BX,CX,DX,DI
  1098. ;
  1099. ; EFFECTS
  1100. ;
  1101. ; DTA buffer holds results of Find First function
  1102. ;
  1103. ; NOTES
  1104. ;
  1105. ; We try to flag devices in two ways. First, we try
  1106. ; the DOS Find First function. It returns attribute bit 6
  1107. ; set on a successful find if it identifies a device name.
  1108. ; Unfortunately, it returns 'path not found' for a device
  1109. ; name terminated with colon, such as "CON:". So, we look
  1110. ; for any colon in the pathname after the 2nd character,
  1111. ; and flag the pathname as a device if we find one.
  1112. FileIsDevice proc
  1113. mov dx,PathPos ; DX = ptr to pathname
  1114. mov di,dx
  1115. add di,PathCnt ; DI = ptr to byte after pathname
  1116. xor bl,bl ; BL = NUL to terminate pathname with
  1117. xchg bl,byte ptr [di] ; BL = saved pathname terminating char
  1118. xor cx,cx ; CX = attribute mask (normal search)
  1119. mov ah,FIND_FIRST ; AH = DOS Find First function code
  1120. int 21h ; call DOS
  1121. xchg bl,byte ptr [di] ; restore pathname terminating char
  1122. jc piCol ; didn't find a dir entry, check for colon
  1123. ; Found a dir entry, see if Find First thinks it's a device.
  1124. test byte ptr DirBuf.Find_Buf_Attr,ATTR_DEVICE
  1125. jz piCol ; device attribute not set, look for colon
  1126. xor cx,cx ; it's a device, return ZR flag
  1127. jmp short piRet
  1128. ; Device attribute not returned by Find First function. But
  1129. ; let's check for a colon anywhere in the pathname after the
  1130. ; second byte.
  1131. ;
  1132. ; DI = ptr to byte after pathname
  1133. piCol: dec di ; DI = ptr to last char in pathname
  1134. mov al,COLON_CHAR ; AL = colon char to search for
  1135. mov cx,PathCnt ; CX = # chars to scan
  1136. dec cx
  1137. dec cx ; ignore 1st two chars of pathname
  1138. or cx,cx
  1139. js piRet ; if < 2 chars in pathname, just return
  1140. or di,di ; clear ZR in case CX = 0
  1141. std ; scan downward
  1142. repne scasb
  1143. cld ; restore default upward direction
  1144. ; After scanning, the ZR flag is set to indicate presence of a colon.
  1145. piRet: ret
  1146. FileIsDevice endp
  1147. ;*** FindFirst - find first directory entry to display
  1148. ;*** FindNext - find next directory entry to display
  1149. ;
  1150. ; ENTRY Bits<inmem> = set if entries are loaded in TPA
  1151. ; AttrSpecified, AttrSelect are set
  1152. ;
  1153. ; EXIT CY = clear if successful
  1154. ; BX = offset in TPA buffer of directory entry found
  1155. ;
  1156. ; If unsuccessful,
  1157. ; CY = set
  1158. ; AX = DOS error code
  1159. ; DOS Get Extended Error call will get error code
  1160. ;
  1161. ; NOTE: if entries were loaded into TPA, AX contains
  1162. ; ERROR_NO_MORE_FILES when no more entries are available,
  1163. ; but DOS Get Extended Error call WON'T return the correct
  1164. ; error. That's ok, because we'll see the value in AX
  1165. ; and recognize it as a non-error condition.
  1166. ;
  1167. ; USED AX,CX,DX,SI,DI
  1168. ;
  1169. ; EFFECTS
  1170. ;
  1171. ; Entries in memory may be marked as output.
  1172. ; If not sorted, entry is loaded at TPA.
  1173. ;
  1174. ; NOTES
  1175. ;
  1176. ; If we don't find a qualifying file, we return after the final
  1177. ; DOS Find File call. A DOS Get Extended Error call will then
  1178. ; indicate an appropriate condition.
  1179. FindFirst proc
  1180. mov ax,offset TRANGROUP:GetFirst
  1181. jmp short ffFindEntry
  1182. FindNext:
  1183. mov ax,offset TRANGROUP:GetNext
  1184. ; AX = address of correct disk get routine to use.
  1185. ffFindEntry:
  1186. push es ; save TRANGROUP seg addr
  1187. test Bits,mask inmem
  1188. jz ffDisk ; entries not in memory, search disk
  1189. ; Entries are loaded in memory to sort out. Find the first one.
  1190. ; There will always be one, or LoadEntries would've failed.
  1191. call FindInMem ; find first entry in TPA
  1192. jmp short ffRet ; return what TPA search returns
  1193. ; Get entry from disk.
  1194. ffDisk:
  1195. call ax ; get entry from disk
  1196. jc ffGetErr ; get & return error
  1197. mov es,Tpa ; ES = seg addr of TPA
  1198. xor di,di ; ES:DI = ptr to TPA
  1199. mov bx,di ; BX = offset of entry in TPA
  1200. call LoadEntry ; load entry to TPA
  1201. clc ; return success
  1202. jmp short ffRet
  1203. ffGetErr:
  1204. invoke Get_Ext_Error_Number ; AX = DOS error code
  1205. stc
  1206. ffRet: pop es ; ES = TRANGROUP seg addr again
  1207. ret
  1208. FindFirst endp
  1209. ;*** FindInMem - find next directory entry in TPA buffer
  1210. ;
  1211. ; ENTRY TPA is loaded (see LoadEntries)
  1212. ;
  1213. ; EXIT BX = offset in TPA of entry found
  1214. ;
  1215. ; If no more files,
  1216. ; CY = set
  1217. ; AX = DOS 'no more files' error code
  1218. ;
  1219. ; USED AX,BX,CX,DX,SI,DI,BP,ES
  1220. ;
  1221. ; EFFECTS
  1222. ;
  1223. ; Entry found is flagged as 'used' (see EntryStruc).
  1224. FindInMem proc
  1225. mov es,Tpa ; ES = TPA seg addr
  1226. xor bx,bx ; ES:BX = ptr to 1st entry in TPA
  1227. cld ; make sure default string direction is up
  1228. call FindOneInMem ; locate an entry
  1229. jc fiNoMore ; none left, set up 'no more files' error
  1230. ; BX = ptr to entry in TPA
  1231. fiBest:
  1232. mov bp,bx ; BP = ptr to best entry so far
  1233. fiNext:
  1234. call FindNextInMem ; locate next entry
  1235. jc fiFound ; no more, best entry so far wins
  1236. ; BX = ptr to next entry
  1237. call CmpEntry ; compare it to best found so far (BP)
  1238. jnb fiNext ; it's not better, go look at next one
  1239. jmp fiBest ; it's better, go mark it as best so far
  1240. fiNoMore:
  1241. ; No more entries available in TPA. Set up 'no more files' error.
  1242. mov ax,ERROR_NO_MORE_FILES ; AX = 'no more files' error code
  1243. stc ; return error
  1244. jmp short fiRet
  1245. fiFound:
  1246. mov bx,bp ; BX = ptr to best entry found
  1247. mov byte ptr es:[bx],1 ; mark entry 'used'
  1248. clc ; return success
  1249. fiRet: ret
  1250. FindInMem endp
  1251. ;*** FindNextChild - find next subdirectory in current directory
  1252. ;
  1253. ; ENTRY BX = ptr to last child found, ASCIIZ filename
  1254. ; DirBuf is established DTA
  1255. ;
  1256. ; EXIT BX = ptr (same addr) to next child found, ASCIIZ filename
  1257. ;
  1258. ; If failure,
  1259. ; CY = set
  1260. ; DOS Get Extended Error call will get error
  1261. ;
  1262. ; USED AX,CX,DX,SI,DI,BP
  1263. ;
  1264. ; EFFECTS
  1265. ;
  1266. ; DirBuf is used for find first/next calls.
  1267. ;
  1268. ; NOTES
  1269. ;
  1270. ; We keep on checking files until DOS returns an error. If
  1271. ; the error is 'no more files' and the temp filename is not
  1272. ; the initial high tag, copy the temp to the child's name spot
  1273. ; and return success. Otherwise, send the error back to caller.
  1274. ;
  1275. ; This routine depends on DS,ES,CS, & SS all being equal.
  1276. FindNextChild proc
  1277. sub sp,12 ; make temp filename buf on stack
  1278. shove 00FFh ; temp filename = high tag
  1279. mov bp,sp ; BP = ptr to temp filename buf
  1280. shove "*"
  1281. shove ".*"
  1282. call GetDriveLtr ; AX = "d:"
  1283. push ax
  1284. mov dx,sp ; DX = ptr to "d:*.*",0 on stack
  1285. ; See that the stack is restored properly at the end of this proc.
  1286. mov cx,ATTR_DIRECTORY ; CX = attributes for file search
  1287. mov ah,FIND_FIRST
  1288. int 21h ; DOS- Find First matching file
  1289. jc fcRet ; return error
  1290. call CheckChild ; check child against last, temp
  1291. fcNext: mov cx,ATTR_DIRECTORY ; CX = attributes for file search
  1292. mov ah,FIND_NEXT
  1293. int 21h ; DOS- Find Next matching file
  1294. jc fcErr ; examine error
  1295. call CheckChild ; check child against last, temp
  1296. jmp fcNext ; go find another child
  1297. fcErr:
  1298. invoke Get_Ext_Error_Number ; AX = extended error code
  1299. cmp ax,ERROR_NO_MORE_FILES ; no more files?
  1300. jne short fcNope ; some other error- return it
  1301. ; We ran out of files. See if we qualified at least one.
  1302. cmp byte ptr [bp],0FFh
  1303. je fcNope ; temp filename is unused- no child
  1304. ; Move temp filename to child name position.
  1305. mov si,bp ; SI = ptr to temp filename
  1306. mov di,bx ; DI = ptr to child name pos'n
  1307. fcMove: lodsb ; AL = next byte of filename
  1308. stosb ; store byte
  1309. or al,al
  1310. jz fcRet ; byte was zero, return success (CY clear)
  1311. jmp fcMove ; go move another byte
  1312. fcNope: stc ; return error
  1313. fcRet: lahf
  1314. add sp,20 ; restore stack
  1315. sahf
  1316. ret
  1317. FindNextChild endp
  1318. ;*** FindOneInMem - find the first available entry in TPA
  1319. ;*** FindNextInMem - find the next available entry in TPA
  1320. ;
  1321. ; ENTRY ES = TPA seg addr
  1322. ; BX = ptr to entry in TPA
  1323. ;
  1324. ; EXIT BX = ptr to entry found
  1325. ; CY = set if no more entries available in TPA
  1326. ;
  1327. ; USED AL
  1328. FindOneInMem proc
  1329. mov al,es:[bx] ; examine 'used' byte of starting entry
  1330. cmp al,1
  1331. je FindNextInMem ; entry has already been used
  1332. cmp al,0FFh
  1333. je foNoMore ; 0FFh, we're at the end of the list
  1334. ; BX = ptr to entry that hasn't been output yet.
  1335. clc ; return success
  1336. ret
  1337. FindNextInMem:
  1338. add bx,size EntryStruc ; BX = ptr to next entry
  1339. jmp FindOneInMem ; go look at it
  1340. foNoMore:
  1341. stc ; ran out of entries, return failure
  1342. ret
  1343. FindOneInMem endp
  1344. ;*** GetEnvValue - get value of our environment variable
  1345. ;
  1346. ; ENTRY DS, ES = TRANGROUP seg addr
  1347. ;
  1348. ; EXIT CY = set if environment variable not in environment
  1349. ;
  1350. ; Otherwise:
  1351. ; SI = ptr to environment variable asciiz value in TRANGROUP
  1352. ;
  1353. ; USED AX,BX,CX,DX,DI
  1354. ; (We assume the (almost) worst, since we don't know about
  1355. ; Find_Name_In_Environment.)
  1356. ;
  1357. ; EFFECTS
  1358. ;
  1359. ; ScanBuf is loaded with value text
  1360. GetEnvValue proc
  1361. push es ; save ES
  1362. mov si,offset TRANGROUP:DirEnvVar ; DS:SI = ptr to variable name
  1363. invoke Find_Name_In_Environment
  1364. jc geRet ; name not found in environment
  1365. ; ES:DI = ptr to value of environment variable
  1366. ; We're assuming DS, CS, and SS are unchanged.
  1367. push ds
  1368. push es
  1369. pop ds
  1370. pop es
  1371. assume ds:nothing
  1372. ; DS = seg addr of environment variable value (in environment segment)
  1373. ; ES = TRANGROUP seg addr
  1374. mov si,di ; DS:SI = ptr to value string
  1375. mov di,offset TRANGROUP:ScanBuf ; ES:DI = ptr to dest buffer
  1376. @@: lodsb
  1377. or al,al
  1378. stosb
  1379. loopnz @B ; move the string, including trailing null
  1380. push es
  1381. pop ds ; DS = TRANGROUP seg addr again
  1382. assume ds:TRANGROUP
  1383. mov si,offset TRANGROUP:ScanBuf ; SI = ptr to var value
  1384. geRet: pop es ; restore ES
  1385. ret
  1386. GetEnvValue endp
  1387. ;*** GetFirst - get first directory entry from disk
  1388. ;
  1389. ; ENTRY DOS DTA established at DirBuf
  1390. ; FCB contains drive # and filename
  1391. ; Current directory (on selected drive) is the one to search
  1392. ; AttrSpecified & AttrSelect masks set
  1393. ;
  1394. ; EXIT CY = clear if success
  1395. ; DirBuf contains extended FCB for file found
  1396. ;
  1397. ; If unsuccessful,
  1398. ; CY = set
  1399. ; Ready for DOS Get Extended Error call
  1400. ;
  1401. ; USED AX,DX
  1402. ;
  1403. ; EFFECTS
  1404. ;
  1405. ; FCB-7 = 0FFh to mark extended FCB
  1406. ; FCB-1 = attribute mask to find all files
  1407. ; These fields should remain unmodified for GetNext calls.
  1408. ;
  1409. ;
  1410. ;*** GetNext - get next directory entry from disk
  1411. ;
  1412. ; ENTRY As for GetFirst, plus
  1413. ; FCB-7 set up as extended FCB w/ find-all attribute byte
  1414. ;
  1415. ; EXIT As for GetFirst
  1416. ;
  1417. ; USED AX,DX
  1418. GetFirst proc
  1419. mov byte ptr ds:FCB-7,0FFh ; signal extended FCB
  1420. mov byte ptr ds:FCB-1,ATTR_ALL
  1421. ; find any file
  1422. mov dx,FCB-7 ; DX = ptr to extended FCB
  1423. mov ah,DIR_SEARCH_FIRST ; AH = DOS Find First function code
  1424. int 21h ; call DOS
  1425. shl al,1 ; CY = set if error
  1426. jc gfRet ; return error
  1427. jmp short gfFound ; go look at attr's
  1428. GetNext:
  1429. mov dx,FCB-7 ; DX = ptr to extended FCB
  1430. mov ah,DIR_SEARCH_NEXT ; AH = DOS Find Next function code
  1431. int 21h ; call DOS
  1432. shl al,1 ; CY = set if error
  1433. jc gfRet ; return error
  1434. ;* Found an entry. Check attributes.
  1435. gfFound:
  1436. mov al,[DirBuf+8].dir_attr ; AL = file attributes
  1437. mov ah,AttrSpecified ; AH = mask of pertinent attr's
  1438. and al,ah ; AL = pertinent attr's of file
  1439. and ah,AttrSelect ; AH = attr settings to match
  1440. cmp al,ah
  1441. jne GetNext ; attr's don't match, look for another
  1442. gfRet: ret
  1443. GetFirst endp
  1444. ;*** ListDir - search for and list files in the current directory
  1445. ;
  1446. ; List header, files, and trailer for current directory on selected
  1447. ; drive. Header & trailer are listed if at least one file is found.
  1448. ; If no qualifying files are found, no display output occurs.
  1449. ;
  1450. ; ENTRY Current directory (on selected drive) is the one to be listed
  1451. ; FCB contains selected drive # and filename spec
  1452. ; Option bits, attribute masks, and sort codes set up
  1453. ;
  1454. ; EXIT CY = clear if no error
  1455. ; FileCnt = # files found & displayed
  1456. ;
  1457. ; If error,
  1458. ; CY = set
  1459. ; Ready for DOS Get Extended Error call
  1460. ;
  1461. ; USED AX,BX,CX,DX,SI,DI,BP
  1462. ; FileSiz
  1463. ;
  1464. ; EFFECTS
  1465. ;
  1466. ; FileCntTotal, FileSizTotal are updated.
  1467. ; Files found are listed. A directory header and trailer are
  1468. ; displayed only if files are found.
  1469. ListDir proc
  1470. xor ax,ax
  1471. mov FileCnt,ax ; zero file count
  1472. mov word ptr FileSiz,ax ; zero file size accumulator
  1473. mov word ptr FileSiz+2,ax
  1474. cmp DestBuf,0 ; check for sort code
  1475. je @F ; no sort
  1476. call LoadEntries ; load entries for sorted listing
  1477. jnc @F ; no error - continue
  1478. invoke Get_Ext_Error_Number ; AX = DOS error code
  1479. stc
  1480. jmp short ldErr ; return error
  1481. @@:
  1482. call FindFirst ; find first file
  1483. jc ldErr ; not found, return error
  1484. ; BX = offset in TPA buffer of entry found
  1485. call DisplayHeader ; if at least one file, display header
  1486. call DisplayFile ; display the file entry
  1487. ldNext:
  1488. call FindNext ; find another file
  1489. jc ldErr ; not found
  1490. call DisplayFile ; display entry
  1491. jmp ldNext ; go find another one
  1492. ldErr:
  1493. cmp ax,ERROR_FILE_NOT_FOUND
  1494. je ldDone ; file not found, we're done
  1495. cmp ax,ERROR_NO_MORE_FILES
  1496. je ldDone ; no more files, we're done
  1497. stc
  1498. jmp short ldRet
  1499. ldDone:
  1500. cmp FileCnt,0
  1501. je @F ; no files found, just return
  1502. call DisplayTrailer ; display trailing info
  1503. @@: clc ; return success
  1504. ldRet: ret
  1505. ListDir endp
  1506. ;*** LoadEntries - attempt to load entries from current directory
  1507. ;
  1508. ; Load all qualifying directory entries from the current directory
  1509. ; into the TPA. If an error is returned by FindFirst/FindNext calls
  1510. ; other than 'no more files', return to caller with carry flag set.
  1511. ; If we run out of buffer space, display a message that we haven't
  1512. ; enough memory to sort this directory, but return without error.
  1513. ; Other routines know whether or not entries have been loaded by
  1514. ; the 'inmem' flag bit, which we set here.
  1515. ;
  1516. ; The TPA is usually 64K - 512 bytes long. At 20 bytes per entry,
  1517. ; this allows sorting over 3000 entries in a directory.
  1518. ;
  1519. ; ENTRY Tpa = buffer seg addr
  1520. ; BytCnt = buffer length, in bytes
  1521. ; Current directory (on selected drive) is the one to load
  1522. ; FCB contains drive # and filespec
  1523. ; Bits, AttrSpecified, AttrSelect, & DestBuf (sort codes) are set
  1524. ;
  1525. ; EXIT CY = set if error
  1526. ; If error, DOS Get Extended Error will get error info
  1527. ;
  1528. ; USED AX,CX,DX,SI,DI
  1529. ;
  1530. ; EFFECTS
  1531. ;
  1532. ; Inmem bit of Bits = set if load succeeded.
  1533. ; Tpa buffer contains directory entries.
  1534. ; Byte after last entry = 0FFh.
  1535. LoadEntries proc
  1536. push es ; save TRANGROUP seg addr
  1537. mov es,Tpa ; ES = TPA seg addr
  1538. xor di,di ; ES:DI = destination ptr
  1539. and Bits,not mask inmem ; signal entries not loaded
  1540. call GetFirst ; look for first file
  1541. jc leRet ; return any error
  1542. call LoadEntry ; load entry into TPA
  1543. leNext: call GetNext ; get another file
  1544. jc leLoaded ; assume any error is no more files
  1545. mov ax,BytCnt ; AX = size of TPA
  1546. sub ax,di ; AX = bytes left in TPA
  1547. cmp ax,size EntryStruc+2 ; insist on entry size + 2 bytes
  1548. jb leOk ; not enough memory left, give up
  1549. call LoadEntry ; load entry into TPA
  1550. jmp leNext ; go get another file
  1551. leLoaded:
  1552. mov byte ptr es:[di],0FFh ; mark end of entry list
  1553. or Bits,mask inmem ; signal entries loaded in memory
  1554. leOk: clc ; return no error
  1555. leRet: pop es ; ES = TRANGROUP seg addr again
  1556. ret
  1557. LoadEntries endp
  1558. ;*** LoadEntry - load directory entry from DirBuf ext'd FCB
  1559. ;
  1560. ; ENTRY ES:DI = ptr to load point in TPA
  1561. ; DirBuf contains extended FCB of entry to load
  1562. ;
  1563. ; EXIT ES:DI = ptr to next byte available in TPA
  1564. ;
  1565. ; USED AX,CX,SI
  1566. ;
  1567. ; NOTES
  1568. ;
  1569. ; I could've used symbolic offsets and sizes of fields from
  1570. ; the dir_entry struc to do this, but this is time-critical,
  1571. ; so I hard-wired the structure of the DOS 4.x returned FCB,
  1572. ; as well as our private directory entry structure.
  1573. ;
  1574. ; We force a zero size for subdirectory files. A zero size is
  1575. ; ordinarily returned for subdirectories, but with Novell
  1576. ; Netware 286 or 386 loaded, we can't depend on it. Bug #1594.
  1577. LoadEntry proc
  1578. mov si,offset TRANGROUP:Dirbuf+8 ; DS:SI = ptr to filename
  1579. xor al,al ; AL = 0
  1580. stosb ; 'used' byte = false
  1581. mov cx,11
  1582. rep movsb ; transfer filename & extension
  1583. lodsb ; AL = attrib byte
  1584. stosb ; store attrib byte
  1585. add si,dir_time-dir_attr-1 ; skip to time field
  1586. movsw ; transfer time
  1587. movsw ; transfer date
  1588. inc si ; skip alloc unit
  1589. inc si
  1590. and al,ATTR_DIRECTORY
  1591. jnz leSetDirSize ; force zero size for subdir
  1592. movsw
  1593. movsw ; transfer size
  1594. ret
  1595. leSetDirSize:
  1596. xor ax,ax
  1597. stosw
  1598. stosw ; store zero size
  1599. ret
  1600. LoadEntry endp
  1601. ;*** NoOrder - turn sorting off
  1602. ;
  1603. ; ENTRY nothing
  1604. ;
  1605. ; EXIT CY clear
  1606. ;
  1607. ; USED AX
  1608. ;
  1609. ; EFFECTS
  1610. ;
  1611. ; DestBuf is updated with sort code bytes. See DestBuf description.
  1612. NoOrder proc
  1613. mov DestBuf,0 ; no sort
  1614. clc ; no error
  1615. ret
  1616. NoOrder endp
  1617. ;*** OnOffSw - record occurence of on/off option switch
  1618. ;
  1619. ; ENTRY DI = index into word list of switches
  1620. ;
  1621. ; EXIT CY clear
  1622. ;
  1623. ; USED AX,CX
  1624. ;
  1625. ; EFFECTS
  1626. ;
  1627. ; Bits modified to indicate option state.
  1628. OnOffSw proc
  1629. mov cx,di ; CX = index into word list of options
  1630. shr cx,1
  1631. shr cx,1 ; CX = bit position of option
  1632. mov ax,1
  1633. shl ax,cl ; AX = bit mask of option
  1634. test di,2 ; check if it is a negated option
  1635. jz @F ; it's negated
  1636. or Bits,ax ; turn option on
  1637. jmp short ooRet
  1638. @@: not ax ; AX = complemented bit mask of option
  1639. and Bits,ax ; turn option off
  1640. ooRet: clc ; always return success
  1641. ret
  1642. OnOffSw endp
  1643. ;*** ParseAttr - parse and record /A option
  1644. ;
  1645. ; ENTRY BX = ptr to system parser result buffer for /A occurence
  1646. ;
  1647. ; EXIT CY = set if error occurs parsing attribute conditions
  1648. ;
  1649. ; For parse error, we set up for Std_EPrintf call:
  1650. ; AX = parse error code, like system parser
  1651. ; DX = ptr to message block
  1652. ;
  1653. ; USED AX,CX,DX,DI
  1654. ;
  1655. ; EFFECTS
  1656. ;
  1657. ; AttrSpecified, AttrSelect are updated with new attribute conditions.
  1658. ; If parse error occurs, attribute conditions parsed so far hold.
  1659. ;
  1660. ; For parse error, we set up for Std_EPrintf call:
  1661. ; Msg_Disp_Class = parse error message class
  1662. ; Message block (see DX) is set up for parse error message
  1663. ParseAttr proc
  1664. push si ; save SI
  1665. mov AttrSpecified,0 ; cancel all attribute conditions
  1666. ; Each /A invocation starts by assuming all files are to be listed.
  1667. mov si,word ptr [bx].ValuePtr ; SI = ptr to string after /A
  1668. paLoop: mov dx,1 ; DX = 1 (for un-negated attribute)
  1669. lodsb ; AL = next char in string
  1670. or al,al
  1671. jz paOk ; it's terminating null, we're done
  1672. cmp al,'-'
  1673. jne @F ; not '-', go look for letter
  1674. dec dx ; DX = 0 (for negated attribute)
  1675. lodsb ; AL = next char
  1676. @@:
  1677. mov di,offset TRANGROUP:AttrLtrs ; DI = ptr to attrib letter list
  1678. mov cx,NUM_ATTR_LTRS ; CX = length of attrib letter list
  1679. repne scasb ; look for our letter in the list
  1680. jne paErr ; not found, return error
  1681. not cx
  1682. add cx,NUM_ATTR_LTRS ; CX = attrib bit #, 0-5
  1683. ; Note that we rely on AttrLtrs to be in the attribute bit order,
  1684. ; starting from bit 0.
  1685. ; Record this attribute bit in AttrSpecified.
  1686. mov al,1
  1687. shl al,cl ; AL = mask for our bit
  1688. or AttrSpecified,al ; set it in the 'specified' mask
  1689. ; Record the selected state for this attribute in AttrSelect.
  1690. ; DX = 0 or 1, the selected state for this attribute.
  1691. not al ; AL = mask for all other bits
  1692. and AttrSelect,al ; clear our bit
  1693. shl dl,cl ; DL = our bit state in position
  1694. or AttrSelect,dl ; set selected attr state
  1695. jmp paLoop ; go look at next char
  1696. ; The attribute letter string is invalid.
  1697. paErr:
  1698. call SetupParamError ; set message up for Std_EPrintf
  1699. stc ; return error
  1700. jmp short paRet
  1701. paOk: clc ; return success
  1702. paRet: pop si ; restore SI
  1703. ret
  1704. ParseAttr endp
  1705. ;*** ParseLine - parse a line of text
  1706. ;
  1707. ; Parse text until an EOL (CR or NUL) is found, or until a parse
  1708. ; error occurs.
  1709. ;
  1710. ; ENTRY DS:SI = ptr to text
  1711. ; CS, DS, ES = TRANGROUP seg addr
  1712. ;
  1713. ; EXIT AX = last return code from system parser
  1714. ; CX = # positional parameters (pathnames) found - 0 or 1
  1715. ;
  1716. ; If parse error occurred, we're set up for Std_EPrintf call:
  1717. ; DX = ptr to message block
  1718. ;
  1719. ; USED BX,CX,DX,SI,DI
  1720. ;
  1721. ; EFFECTS
  1722. ;
  1723. ; Bits may contain new option settings.
  1724. ; DestBuf may contain new series of sort codes.
  1725. ; AttrSpecified, AttrSelect may contain new attribute conditions.
  1726. ; SrcBuf may contain a new default pathname/filespec.
  1727. ; PathPos, PathCnt updated for new pathname.
  1728. ;
  1729. ; If parse error occurred, we're set up for Std_EPrintf call:
  1730. ; Msg_Disp_Class = parse error class
  1731. ; Byte after last parameter in text is zeroed to make ASCIIZ string
  1732. ; Message block (see DX) is set up for parse error message
  1733. ParseLine proc
  1734. mov di,offset TRANGROUP:Parse_Dir ; ES:DI = ptr to parse block
  1735. xor cx,cx ; CX = # positionals found
  1736. plPars:
  1737. invoke Parse_With_Msg ; call parser
  1738. cmp ax,END_OF_LINE
  1739. je plRet ; EOL encountered, return
  1740. cmp ax,RESULT_NO_ERROR
  1741. jne plRet ; parse error occurred, return
  1742. ; Parse call succeeded. We have a filespec or a switch.
  1743. ; DX = ptr to result buffer
  1744. mov bx,dx ; BX = ptr to parse result buffer
  1745. cmp byte ptr [bx],RESULT_FILESPEC
  1746. je plFil ; we have a filespec
  1747. call ParseSwitch ; else we have a switch
  1748. jc plRet ; error parsing switch, return
  1749. jmp plPars ; parse more
  1750. plFil: call CopyPathname ; copy pathname into our buffer
  1751. jmp plPars ; parse more
  1752. plRet: ret
  1753. ParseLine endp
  1754. ;*** ParseOrder - parse and record /O option
  1755. ;
  1756. ; ENTRY BX = ptr to system parser result buffer for /O occurence
  1757. ;
  1758. ; EXIT CY = set if error occurs parsing order
  1759. ;
  1760. ; For parse error, we set up for Std_EPrintf call:
  1761. ; AX = parse error code, like system parser
  1762. ; DX = ptr to message block
  1763. ;
  1764. ; USED AX,CX,DX,DI
  1765. ;
  1766. ; EFFECTS
  1767. ;
  1768. ; DestBuf is updated with sort code bytes. See DestBuf description.
  1769. ;
  1770. ; For parse error, we set up for Std_EPrintf call:
  1771. ; Msg_Disp_Class = parse error message class
  1772. ; Message block (see DX) is set up for parse error message
  1773. ParseOrder proc
  1774. push si ; save SI
  1775. push bx ; save ptr to result buffer
  1776. mov si,word ptr [bx].ValuePtr ; SI = ptr to order letters
  1777. mov bx,offset TRANGROUP:DestBuf ; BX = ptr to sort code buffer
  1778. mov al,[si] ; AL = 1st char of order string
  1779. or al,al
  1780. jnz poLtr ; not NUL, go parse letters
  1781. ; We have /O alone. Set standard sort order.
  1782. ; Note hardwired dependency on character order in OrderLtrs.
  1783. mov byte ptr [bx],5 ; sort 1st by group (subdirs 1st)
  1784. inc bx
  1785. mov byte ptr [bx],1 ; then by name
  1786. inc bx
  1787. mov byte ptr [bx],2 ; then by extension
  1788. inc bx
  1789. jmp short poOk ; return success
  1790. ; We have /O<something>. Parse sort order letters.
  1791. poLtr: xor dl,dl ; DL = 0 (upward sort)
  1792. lodsb ; AL = next sort order letter
  1793. or al,al
  1794. jz poOk ; NUL found, return success
  1795. cmp al,'-'
  1796. jne @F ; not '-', go look for letter
  1797. mov dl,80h ; DL = downward sort mask
  1798. lodsb ; AL = next char
  1799. @@:
  1800. mov di,offset TRANGROUP:OrderLtrs ; DI = ptr to list of letters
  1801. mov cx,NUM_ORDER_LTRS ; CX = length of list
  1802. repne scasb ; look for our letter in the list
  1803. jne poErr ; not found, return error
  1804. neg cx
  1805. add cx,NUM_ORDER_LTRS ; CL = sort order code, 1-5
  1806. or cl,dl ; CL = sort code with up/dn bit
  1807. mov [bx],cl ; store sort order code in buffer
  1808. inc bx ; BX = ptr to next spot in buffer
  1809. cmp bx,offset TRANGROUP:EndDestBuf
  1810. jae poErr ; too many letters
  1811. jmp poLtr ; go look at next char
  1812. ; The sort order string is invalid.
  1813. poErr: pop bx ; BX = ptr to result buffer
  1814. call SetupParamError ; set message up for Std_EPrintf
  1815. stc ; return failure
  1816. jmp short poRet
  1817. poOk: mov byte ptr [bx],0 ; mark end of sort code list
  1818. pop bx ; BX = ptr to result buffer
  1819. clc ; return success
  1820. poRet: pop si ; restore SI
  1821. ret
  1822. ParseOrder endp
  1823. ;*** ParseSwitch - parse a switch
  1824. ;
  1825. ; ENTRY BX = ptr to parse result buffer after system parser processed
  1826. ; a switch
  1827. ;
  1828. ; EXIT CY = set if parse error occurred
  1829. ;
  1830. ; If parse error occurred, we're set up for Std_EPrintf call:
  1831. ; AX = parse error code, like system parser
  1832. ; DX = ptr to message block
  1833. ;
  1834. ; USED AX,BX,DX
  1835. ;
  1836. ; EFFECTS
  1837. ;
  1838. ; Bits may contain new option settings.
  1839. ; DestBuf may contain new series of sort codes.
  1840. ; AttrSpecified, AttrSelect may contain new attribute conditions.
  1841. ;
  1842. ; If parse error occurred, we're set up for Std_EPrintf call:
  1843. ; Msg_Disp_Class = parse error class
  1844. ; Byte after last parameter in text is zeroed to make ASCIIZ string
  1845. ; Message block (see DX) is set up for parse error message
  1846. ParseSwitch proc
  1847. push cx ; save CX
  1848. push di ; save DI
  1849. mov ax,[bx].SynPtr ; AX = synonym ptr
  1850. mov di,offset TRANGROUP:Dir_Sw_Ptrs
  1851. ; ES:DI = ptr to list of synonym ptrs
  1852. mov cx,NUM_DIR_SWS ; CX = # of dir switches in list
  1853. cld ; scan direction = upward
  1854. repne scasw ; locate synonym ptr in list
  1855. sub di,offset TRANGROUP:Dir_Sw_Ptrs + 2
  1856. ; DI = index into word list of synonym ptrs
  1857. call cs:SwHandlers[di] ; use same index into call table
  1858. pop di ; restore DI
  1859. pop cx ; restore CX
  1860. ret
  1861. ; Order in this table must correspond to order in Dir_Sw_Ptrs list.
  1862. ; Simple on/off switches must occur first in both lists, and must be
  1863. ; in order of option bits in Bits, starting with bit 0.
  1864. SwHandlers label word
  1865. dw OnOffSw ; /-W
  1866. dw OnOffSw ; /W
  1867. dw OnOffSw ; /-P
  1868. dw OnOffSw ; /P
  1869. dw OnOffSw ; /-S
  1870. dw OnOffSw ; /S
  1871. dw OnOffSw ; /-B
  1872. dw OnOffSw ; /B
  1873. dw OnOffSw ; /-L ;M010
  1874. dw OnOffSw ; /L ;M010
  1875. dw NoOrder ; /-O
  1876. dw ParseOrder ; /O
  1877. dw DefaultAttr ; /-A
  1878. dw ParseAttr ; /A
  1879. ParseSwitch endp
  1880. break <DIR utility routines>
  1881. ;*** UTILITY ROUTINES
  1882. ;*** ChangeDir - change directory on target drive
  1883. ;
  1884. ; ENTRY FCB contains drive #
  1885. ; DS:DX = ptr to ASCIIZ string w/o drive specifier
  1886. ;
  1887. ; EXIT Changed current directory on drive
  1888. ;
  1889. ; If error,
  1890. ; CY = set
  1891. ; DOS Get Extended Error call will get error
  1892. ;
  1893. ; USED AX,DX,SI,DI
  1894. ;
  1895. ; EFFECTS
  1896. ;
  1897. ; DirBuf is used to build "d:string".
  1898. ChangeDir proc
  1899. mov di,offset TRANGROUP:DirBuf
  1900. call GetDriveLtr ; AX = "d:"
  1901. stosw ; put drive specifier in buffer
  1902. mov si,dx ; SI = ptr to argument string
  1903. cdLoop:
  1904. lodsb
  1905. stosb ; move byte to buffer
  1906. or al,al
  1907. jne cdLoop ; continue until null transferred
  1908. mov dx,offset TRANGROUP:DirBuf ; DX = ptr to "d:string"
  1909. mov ah,CHDIR
  1910. int 21h ; change directory
  1911. ret ; return what CHDIR returns
  1912. ChangeDir endp
  1913. ;*** CmpAscz - compare two ASCIIZ strings alphanumerically
  1914. ;
  1915. ; ENTRY DS:SI = ptr to one ASCIIZ string
  1916. ; ES:DI = ptr to another ASCIIZ string
  1917. ;
  1918. ; EXIT flags set after REPE CMPSB
  1919. ;
  1920. ; USED AL,CX,SI,DI
  1921. ;
  1922. ; NOTES
  1923. ;
  1924. ; Maximum run of comparison is length of DS:SI string.
  1925. ; This ensures that two identical strings followed by
  1926. ; random characters will compare correctly.
  1927. CmpAscz proc
  1928. push di
  1929. mov di,si
  1930. xor al,al
  1931. mov cx,0FFFFh
  1932. repne scasb
  1933. not cx
  1934. pop di
  1935. repe cmpsb
  1936. ret
  1937. CmpAscz endp
  1938. ;*** CopyPathname - copy pathname to our buffer
  1939. ;
  1940. ; ENTRY BX = ptr to parse result buffer after system parser processed
  1941. ; a filespec
  1942. ;
  1943. ; EXIT nothing
  1944. ;
  1945. ; USED AX
  1946. ;
  1947. ; EFFECTS
  1948. ;
  1949. ; SrcBuf may contain a new pathname/filespec.
  1950. ; PathPos, PathCnt updated for new pathname.
  1951. CopyPathname proc
  1952. push si
  1953. lds si,dword ptr [bx].ValuePtr ; load far ptr from result buffer
  1954. invoke Move_To_SrcBuf ; copy pathname to SrcBuf
  1955. pop si
  1956. ret
  1957. CopyPathname endp
  1958. ;*** CountFile - update counters with current file
  1959. ;
  1960. ; ENTRY BX = offset of entry in TPA buffer
  1961. ;
  1962. ; EXIT nothing
  1963. ;
  1964. ; USED AX,DX
  1965. ;
  1966. ; EFFECTS
  1967. ;
  1968. ; FileCnt, FileCntTotal, FileSiz, FileSizTotal are updated.
  1969. CountFile proc
  1970. push es ; save TRANGROUP seg addr
  1971. mov es,Tpa ; ES = TPA seg addr
  1972. inc FileCnt ; # files this directory
  1973. inc word ptr FileCntTotal ; # files total
  1974. jnz @F
  1975. inc word ptr FileCntTotal+2
  1976. @@:
  1977. mov ax,word ptr es:[bx].filesize ; AX = low word of file size
  1978. mov dx,word ptr es:[bx].filesize+2 ; DX = high word of file size
  1979. add word ptr FileSiz,ax
  1980. adc word ptr FileSiz+2,dx ; size of this directory
  1981. add word ptr FileSizTotal,ax
  1982. adc word ptr FileSizTotal+2,dx ; total size of files listed
  1983. pop es ; ES = TRANGROUP seg addr again
  1984. ret
  1985. CountFile endp
  1986. ;*** DisplayBare - display filename in bare format
  1987. ;
  1988. ; ENTRY BX = offset of entry in TPA buffer
  1989. ;
  1990. ; EXIT DX = # char's displayed, including dot
  1991. ;
  1992. ; USED AX,CX,SI,DI
  1993. ;
  1994. ; EFFECTS
  1995. ;
  1996. ; Filename is displayed in name.ext format, followed by cr/lf.
  1997. ; If /s is on, complete pathname is displayed.
  1998. ;
  1999. ; NOTE
  2000. ;
  2001. ; Directory pseudofiles . and .. and suppressed in bare listing.
  2002. DisplayBare proc
  2003. ; Suppress . and .. files from bare listing.
  2004. mov cx,ds ; CX = saved TRANGROUP seg addr
  2005. mov ds,Tpa ; DS:BX = ptr to file entry
  2006. assume ds:NOTHING
  2007. cmp ds:[bx].filename,'.' ; check 1st char of filename
  2008. mov ds,cx ; DS = TRANGROUP seg addr again
  2009. assume ds:TRANGROUP
  2010. je dbRet ; it's . or .. - don't display
  2011. test Bits,mask subd
  2012. jz dbNameExt ; not /s - display filename only
  2013. invoke Build_Dir_String
  2014. mov di,offset TRANGROUP:BwdBuf ; ES:DI = ptr to dir string
  2015. test Bits,mask lcase ;M010;check for lowercase option
  2016. jz @F ;M010;lowercase not needed
  2017. mov si,di ;M010;DS:SI --> ASCIIZ string in BwdBuf
  2018. call LowercaseString ;M010;path string is in BwdBuf
  2019. @@: xor al,al ; AL = 0
  2020. mov cx,0FFFFh
  2021. cld
  2022. repne scasb ; ES:DI = ptr to byte after null
  2023. dec di ; ES:DI = ptr to null byte
  2024. ifdef DBCS
  2025. push si
  2026. push di
  2027. mov si,offset TRANGROUP:BwdBuf
  2028. dec di
  2029. call CheckDBCSTailByte
  2030. pop di
  2031. pop si
  2032. jz dbTailByte ; if last char is double byte
  2033. endif
  2034. cmp byte ptr es:[di-1],'\'
  2035. je @F ; already terminated w/ '\'
  2036. ifdef DBCS
  2037. dbTailByte:
  2038. endif
  2039. mov ax,'\' ; AX = '\',0
  2040. stosw ; add to dir string
  2041. @@:
  2042. mov String_Ptr_2,offset TRANGROUP:BwdBuf
  2043. mov dx,offset TRANGROUP:String_Buf_Ptr
  2044. invoke Std_Printf ; display device & directory path
  2045. dbNameExt:
  2046. call DisplayDotForm ; display name.ext
  2047. invoke CrLf2 ; display cr/lf
  2048. call UseLine ;M007;Allow /p with /b
  2049. dbRet: ret
  2050. DisplayBare endp
  2051. ;*** DisplayDotForm - display filename in compressed dot format
  2052. ;
  2053. ; Display name.ext, with no cr/lf's. Dot is displayed only
  2054. ; if the filename has a nonblank extension.
  2055. ;
  2056. ; ENTRY BX = offset of entry in TPA buffer
  2057. ;
  2058. ; EXIT DX = # char's displayed, including dot
  2059. ;
  2060. ; USED AX,CX,SI,DI
  2061. ;
  2062. ; EFFECTS
  2063. ;
  2064. ; Filename is displayed in name.ext format.
  2065. ;
  2066. ; NOTE
  2067. ;
  2068. ; We allow for bogus filenames that have blanks embedded
  2069. ; in the name or extension.
  2070. ; Bugbug: might be a good performance gain if we buffered
  2071. ; up the output and used DOS function 9.
  2072. DisplayDotForm proc
  2073. push ds ; save TRANGROUP seg addr
  2074. push es ; save ES
  2075. mov ax,cs:Tpa ; AX = TPA seg addr
  2076. mov ds,ax ; DS:BX = ptr to entry
  2077. assume ds:nothing
  2078. mov es,ax ; ES:BX = ptr to entry
  2079. mov di,bx ; ES:DI = ptr to entry
  2080. add di,filename + size filename - 1
  2081. ; ES:DI = ptr to last char in name field
  2082. mov cx,size filename ; CX = length of name field
  2083. mov al,' '
  2084. std ; scan down
  2085. repe scasb ; scan for nonblank
  2086. ; Assume file name has at least one character.
  2087. inc cx ; CX = # chars in name
  2088. mov dx,cx ; DX = # chars to be displayed
  2089. mov si,bx ; DS:SI = ptr to entry
  2090. add si,filename ; DS:SI = ptr to name
  2091. NextNameChar:
  2092. cld
  2093. lodsb ; AL = next char
  2094. ifdef DBCS
  2095. invoke testkanj
  2096. jz @f ; if this is not lead byte
  2097. invoke Print_Char ; display lead byte
  2098. dec cx
  2099. jz ExtChar ; if this is end
  2100. lodsb ; get tail byte
  2101. jmp short NameChar10 ; display tail byte
  2102. @@:
  2103. endif
  2104. test Bits,mask lcase ;M010;check for lowercase option
  2105. jz @F ;M010;lowercase not required
  2106. call LowerCase ;M010;filename char is in AL
  2107. ifdef DBCS
  2108. NameChar10:
  2109. endif
  2110. @@: invoke Print_Char ; display it
  2111. loop NextNameChar
  2112. ifdef DBCS
  2113. ExtChar:
  2114. endif
  2115. ; Now do extension.
  2116. mov di,bx ; ES:DI = ptr to entry
  2117. add di,fileext + size fileext - 1
  2118. ; ES:DI = ptr to last char in ext field
  2119. mov cx,size fileext ; CX = length of ext field
  2120. mov al,' '
  2121. std ; scan down
  2122. repe scasb ; scan for nonblank
  2123. je ddDone ; no nonblank chars in ext
  2124. inc cx ; CX = # chars in ext
  2125. add dx,cx ; DX = total # chars to be displayed
  2126. inc dx ; including dot
  2127. mov al,'.'
  2128. invoke Print_Char
  2129. mov si,bx ; DS:SI = ptr to entry
  2130. add si,fileext ; DS:SI = ptr to ext
  2131. NextExtChar:
  2132. cld
  2133. lodsb ; AL = next char
  2134. ifdef DBCS
  2135. invoke testkanj
  2136. jz @f ; if this is not lead byte
  2137. invoke Print_Char ; display lead byte
  2138. dec cx
  2139. jz ddDone ; if this is end
  2140. lodsb ; get tail byte
  2141. jmp short ExtChar10 ; display tail byte
  2142. @@:
  2143. endif
  2144. test CS:Bits,mask lcase ;M010;check for lowercase option
  2145. jz @F ;M010;lowercase not required
  2146. call LowerCase ;M010;fileext char is in AL
  2147. ifdef DBCS
  2148. ExtChar10:
  2149. endif
  2150. @@: invoke Print_Char ; display it
  2151. loop NextExtChar
  2152. ddDone: pop es ; restore ES
  2153. pop ds ; DS = TRANGROUP seg addr again
  2154. assume ds:TRANGROUP
  2155. cld ; leave direction flag = up
  2156. ret
  2157. DisplayDotForm endp
  2158. ;*** DisplayFile - display file entry, update counters
  2159. ;
  2160. ; ENTRY BX = offset of entry in TPA buffer
  2161. ; Bits contains /w, /p settings
  2162. ;
  2163. ; EXIT nothing
  2164. ;
  2165. ; USED AX,CX,DX,SI,DI,BP
  2166. ;
  2167. ; EFFECTS
  2168. ;
  2169. ; Entry is displayed.
  2170. ; If not /b,
  2171. ; Cursor is left at end of entry on screen.
  2172. ; FileCnt, FileCntTotal, FileSiz, FileSizTotal are updated.
  2173. ; If /b,
  2174. ; Cursor is left at beginning of next line.
  2175. ; Cnt's and Siz's aren't updated.
  2176. DisplayFile proc
  2177. test Bits,mask bare
  2178. jz dfNorm ; not /b - do normal display
  2179. call DisplayBare ; display file in bare format
  2180. jmp short dfRet
  2181. dfNorm: call DisplayNext ; pos'n cursor for next entry
  2182. test Bits,mask wide
  2183. jz dfFull ; full format
  2184. call DisplayWide ; wide format
  2185. jmp short dfCnt
  2186. dfFull: call DisplayName ; display filename & extension
  2187. call DisplayTheRest ; display size, date, time
  2188. dfCnt: call CountFile ; update file counters
  2189. dfRet: ret
  2190. DisplayFile endp
  2191. ;*** DisplayHeader - display directory header of working directory
  2192. ;
  2193. ; ENTRY Current directory (on selected drive) is the one to display
  2194. ; LeftOnPage = # lines left on display page
  2195. ;
  2196. ; EXIT nothing
  2197. ;
  2198. ; ERROR EXIT
  2199. ;
  2200. ; Build_Dir_String will exit through CError with "Invalid drive
  2201. ; specification" if there's a problem obtaining the current
  2202. ; directory pathname.
  2203. ;
  2204. ; USED AX,DX,SI,DI
  2205. ;
  2206. ; EFFECTS
  2207. ;
  2208. ; BwdBuf (which is really the same buffer as DirBuf, which
  2209. ; we are using for the DTA) contains the directory string.
  2210. ; LeftOnPage is adjusted.
  2211. DisplayHeader proc
  2212. test Bits,mask bare
  2213. jnz dhRet ; /b - don't display header
  2214. test Bits,mask subd
  2215. jz dhNorm ; not /s
  2216. ; For subdirectory listings, put a blank line before the header.
  2217. invoke Crlf2 ; start with a blank line
  2218. call UseLine
  2219. jmp short dhCom
  2220. dhNorm:
  2221. mov al,BLANK ; if not /s, precede by a blank
  2222. invoke Print_Char ; print a leading blank
  2223. dhCom:
  2224. invoke Build_Dir_String
  2225. mov dx,offset TRANGROUP:DirHead_ptr
  2226. invoke Std_Printf ; print header & cr/lf
  2227. call UseLine
  2228. invoke Crlf2 ; another cr/lf
  2229. call UseLine
  2230. dhRet: ret
  2231. DisplayHeader endp
  2232. ;*** DisplayName - display file name & extension
  2233. ;
  2234. ; ENTRY BX = offset of entry in TPA buffer
  2235. ;
  2236. ; EXIT nothing
  2237. ;
  2238. ; USED AX,CX,DX,SI,DI
  2239. ;
  2240. ; EFFECTS
  2241. ;
  2242. ; Filename & extension are displayed in spread format.
  2243. ; Cursor is left at end of extension.
  2244. DisplayName proc
  2245. push ds ; save TRANGROUP seg addr
  2246. mov ds,Tpa ; DS:BX = ptr to entry
  2247. assume ds:nothing
  2248. mov si,bx ; DS:SI = ptr to entry
  2249. add si,filename ; DS:SI = ptr to filename
  2250. mov di,offset TRANGROUP:CharBuf ; ES:DI = ptr to CharBuf
  2251. mov cx,8
  2252. cld
  2253. rep movsb ; move filename to CharBuf
  2254. mov al,' '
  2255. stosb ; add a blank
  2256. mov cx,3
  2257. rep movsb ; add extension
  2258. xor al,al
  2259. stosb ; add a NULL
  2260. pop ds ; DS = TRANGROUP seg addr again
  2261. assume ds:TRANGROUP
  2262. test Bits,mask lcase ;M010;check for lowercase option
  2263. jz @F ;M010;lowercase not required
  2264. mov si,offset TRANGROUP:CharBuf ;M010;DS:SI --> ASCIIZ string
  2265. call LowercaseString ;M010;filename.ext string is in CharBuf
  2266. @@: mov String_Ptr_2,offset TRANGROUP:CharBuf
  2267. mov dx,offset TRANGROUP:String_Buf_Ptr
  2268. invoke Std_Printf ; print filename & extension
  2269. ret
  2270. DisplayName endp
  2271. ;*** DisplayNext - move display cursor to next entry position
  2272. ;
  2273. ; ENTRY LeftOnLine = # entries can still be printed on this line
  2274. ; LeftOnPage = # lines can still be printed for this page
  2275. ; FileCnt = # files in this dir displayed before this one
  2276. ; Bits contains /w setting
  2277. ;
  2278. ; EXIT nothing
  2279. ;
  2280. ; USED AX,DX
  2281. ;
  2282. ; EFFECTS
  2283. ;
  2284. ; LeftOnLine will be updated to reflect the entry about to be
  2285. ; displayed.
  2286. ; LeftOnPage may be updated.
  2287. DisplayNext proc
  2288. cmp FileCnt,0
  2289. je dn1st ; 1st file in directory
  2290. cmp LeftOnLine,0
  2291. jng dnEol ; no more room on this line
  2292. ; We are in wide mode (LeftOnLine is always 0 otherwise) and
  2293. ; we still have room for more on this line.
  2294. ; Tab to next position.
  2295. mov dx,offset TRANGROUP:Tab_Ptr
  2296. invoke Std_Printf
  2297. jmp short dnDone
  2298. dnEol:
  2299. ; Start this entry on a new line.
  2300. invoke Crlf2 ; start on new line
  2301. call UseLine
  2302. dn1st: mov al,PerLine
  2303. mov LeftOnLine,al ; reset # entries left on line
  2304. dnDone: dec LeftOnLine ; reflect the entry about to be displayed
  2305. ret
  2306. DisplayNext endp
  2307. ;*** DisplayTheRest - display file size/dir, date, time
  2308. ;
  2309. ; ENTRY BX = offset of entry in TPA buffer
  2310. ; Display cursor is at end of file extension
  2311. ;
  2312. ; EXIT nothing
  2313. ;
  2314. ; USED AX,CX,DX,SI,DI,BP
  2315. ;
  2316. ; EFFECTS
  2317. ;
  2318. ; File size, date, & time are displayed.
  2319. DisplayTheRest proc
  2320. push es ; save TRANGROUP seg addr
  2321. mov es,Tpa ; ES = TPA seg addr
  2322. mov bp,bx ; BP = offset of entry in TPA
  2323. test es:[bp].fileattr,ATTR_DIRECTORY
  2324. jz drNonDir ; not a directory file
  2325. ; For a directory file, display <DIR> instead of size.
  2326. mov dx,offset TRANGROUP:DMes_Ptr
  2327. invoke Std_Printf
  2328. jmp short drCom ; skip to common fields
  2329. drNonDir:
  2330. ; For a non-directory file, display file size.
  2331. mov dx,word ptr es:[bp].filesize
  2332. mov File_Size_Low,dx
  2333. mov dx,word ptr es:[bp].filesize+2
  2334. mov File_Size_High,dx
  2335. mov dx,offset TRANGROUP:Disp_File_Size_Ptr
  2336. invoke Std_Printf
  2337. drCom:
  2338. ; For all files, display date & time.
  2339. mov ax,es:[bp].filedate ; AX = date word
  2340. or ax,ax ; test for null date (DOS 1.x)
  2341. jz drDone ; no date, skip date/time display
  2342. mov bx,ax ; BX = date word
  2343. and ax,1Fh ; AX = day of month
  2344. mov dl,al ; DL = day of month
  2345. mov ax,bx ; AX = date word
  2346. mov cl,5
  2347. shr ax,cl ; shift day out
  2348. and al,0Fh ; AL = month
  2349. mov dh,al ; DH = month
  2350. mov cl,bh
  2351. shr cl,1 ; CL = year - 1980
  2352. xor ch,ch ; CX = year - 1980
  2353. add cx,80 ; CX = 2-digit year
  2354. cmp cl,100
  2355. jb @F ; not year 2000 yet, skip ahead
  2356. sub cl,100 ; adjust for 21st century
  2357. @@: xchg dh,dl ; DX = month/day
  2358. mov DirDat_Yr,cx ; move year to msg block
  2359. mov DirDat_Mo_Day,dx ; move month/day to msg block
  2360. mov cx,es:[bp].filetime ; CX = file time
  2361. jcxz drPrint ; no time field - go print
  2362. shr cx,1
  2363. shr cx,1
  2364. shr cx,1 ; CH = hours
  2365. shr cl,1
  2366. shr cl,1 ; CL = minutes
  2367. xchg ch,cl ; CX = hr/min
  2368. mov DirTim_Hr_Min,cx ; move time to msg block
  2369. drPrint:mov dx,offset TRANGROUP:DirDatTim_Ptr
  2370. invoke Std_Printf ; print date & time
  2371. drDone: pop es ; ES = TRANGROUP seg addr again
  2372. mov bx,bp ; BX = offset of entry in TPA again
  2373. ret
  2374. DisplayTheRest endp
  2375. ;*** DisplayTrailer - display trailing lines for directory listing
  2376. ;
  2377. ; ENTRY LeftOnPage = # lines left on display page
  2378. ; FileCnt = # files listed
  2379. ; FileSiz = total size of files listed
  2380. ;
  2381. ; EXIT nothing
  2382. ;
  2383. ; USED
  2384. ;
  2385. ; EFFECTS
  2386. ;
  2387. ; Trailing info lines are displayed
  2388. DisplayTrailer proc
  2389. test Bits,mask bare
  2390. jnz dtrRet ; /b - don't display trailer
  2391. invoke Crlf2 ; start on new line
  2392. call UseLine
  2393. mov ax,FileCnt ; AX = # files found
  2394. DisplayCntSiz:
  2395. ; DisplayTotals uses this entry point.
  2396. ;
  2397. ; AX = # files
  2398. ; FileSiz = dword total size of files
  2399. mov Dir_Num,ax ; load # files
  2400. mov dx,offset TRANGROUP:DirMes_Ptr ; DX = ptr to message block
  2401. invoke Std_Printf ; "nnn File(s)"
  2402. mov dx,offset TRANGROUP:Bytes_Ptr
  2403. invoke Std_Printf ; "nnn bytes",cr,lf
  2404. call UseLine
  2405. dtrRet: ret
  2406. DisplayTrailer endp
  2407. ;*** DisplayWide - display filename in wide format
  2408. ;
  2409. ; ENTRY BX = offset of entry in TPA buffer
  2410. ;
  2411. ; EXIT nothing
  2412. ;
  2413. ; USED AX,CX,DX,SI,DI
  2414. ;
  2415. ; EFFECTS
  2416. ;
  2417. ; Name.ext is displayed. Cursor left at end of field (padded
  2418. ; with blanks). Subdirectory files are displayed as [name.ext].
  2419. DisplayWide proc
  2420. push ds ; save TRANGROUP seg addr
  2421. mov ds,Tpa ; DS:BX = ptr to entry
  2422. assume ds:nothing
  2423. test ds:[bx].fileattr,ATTR_DIRECTORY
  2424. jz @F ; not a subdirectory file
  2425. mov al,'['
  2426. invoke Print_Char ; prefix subdirectory
  2427. @@: call DisplayDotForm ; display name.ext
  2428. ; DX = # chars displayed in name.ext
  2429. test ds:[bx].fileattr,ATTR_DIRECTORY
  2430. jz @F ; not a subdirectory file
  2431. mov al,']'
  2432. invoke Print_Char ; postfix subdirectory
  2433. @@:
  2434. ; Pad field with blanks.
  2435. mov cx,size filename + size fileext + 1
  2436. ; CX = field size
  2437. sub cx,dx ; CX = # pad char's
  2438. jcxz dwDone
  2439. mov al,' '
  2440. @@: invoke Print_Char
  2441. loop @B
  2442. dwDone: pop ds ; DS = TRANGROUP seg addr again
  2443. assume ds:TRANGROUP
  2444. ret
  2445. DisplayWide endp
  2446. ;*** EndPage - end the current display page
  2447. ;
  2448. ; ENTRY LeftOnPage = # lines left on display page
  2449. ; Current directory (on selected drive) is the one being listed
  2450. ; Bits contains /p setting
  2451. ;
  2452. ; EXIT LeftOnPage = # lines left for next page
  2453. ;
  2454. ; USED AX,DX
  2455. ;
  2456. ; EFFECTS
  2457. ;
  2458. ; Pause is invoked to display a message and wait for a keystroke.
  2459. ; BwdBuf (same as DirBuf) used to build directory string.
  2460. EndPage proc
  2461. test Bits,mask pagd
  2462. jz epNew ; paged display isn't enabled
  2463. push bx ; save BX
  2464. push cx ; save CX
  2465. invoke Pause ; "Press any key to continue..."
  2466. invoke Build_Dir_String
  2467. mov dx,offset TRANGROUP:DirCont_Ptr
  2468. invoke Printf_Crlf ; "(continuing <dir>)", cr/lf
  2469. pop cx ; restore CX
  2470. pop bx ; restore BX
  2471. epNew: mov ax,LinPerPag ; AX = # lines per page
  2472. dec ax ; AX = # lines till next EndPage
  2473. mov LeftOnPage,ax ; LeftOnPage = countdown variable
  2474. ret
  2475. EndPage endp
  2476. ;*** GetDriveLtr - get target drive letter
  2477. ;
  2478. ; ENTRY FCB contains drive #
  2479. ;
  2480. ; EXIT AX = "d:"
  2481. ;
  2482. ; USED nothing
  2483. GetDriveLtr proc
  2484. mov al,ds:Fcb ; AL = target drive #
  2485. or al,al
  2486. jnz @F ; not current drive default, skip ahead
  2487. mov al,ds:CurDrv ; AL = current drive #
  2488. inc al ; AL = 1-based drive #
  2489. @@: add al,'A'-1 ; AL = target drive letter
  2490. mov ah,':' ; AX = "d:"
  2491. ret
  2492. GetDriveLtr endp
  2493. ;*** SetupParamError - set up for Std_EPrintf parameter parse error message
  2494. ;
  2495. ; Do for our /O and /A string parsers what Parse_With_Msg does
  2496. ; for system parser calls. Set up a message substitution block,
  2497. ; etc. for invalid value strings. I copied the procedure from
  2498. ; Setup_Parse_Error_Msg.
  2499. ;
  2500. ; ENTRY BX = ptr to system parser result buffer (contains ptr to str)
  2501. ;
  2502. ;
  2503. ; EXIT AX = system parser error return code for bad param format
  2504. ; DX = ptr to message description block for Std_EPrintf
  2505. ;
  2506. ; USED SI
  2507. ;
  2508. ; EFFECTS
  2509. ;
  2510. ; Msg_Disp_Class = parse error message class
  2511. ; Message block (see DX) is set up for parse error message
  2512. SetupParamError proc
  2513. mov ax,9 ; parse error #
  2514. mov Msg_Disp_Class,PARSE_MSG_CLASS
  2515. mov Extend_Buf_Ptr,ax
  2516. mov si,word ptr [bx].ValuePtr
  2517. mov String_Ptr_2,si
  2518. mov Extend_Buf_Sub,ONE_SUBST
  2519. mov dx,offset TRANGROUP:Extend_Buf_Ptr
  2520. ret
  2521. SetupParamError endp
  2522. ;*** UseLine - use a display line, start a new page if none left
  2523. ;
  2524. ; ENTRY nothing
  2525. ;
  2526. ; EXIT nothing
  2527. ;
  2528. ; USED flags
  2529. UseLine proc
  2530. dec LeftOnPage
  2531. ifndef NEC_98
  2532. cmp LeftOnPage,2
  2533. else ;NEC_98
  2534. cmp LeftOnPage,1 ;NEC04 Canged Page Line (23 to 24)
  2535. endif ;NEC_98
  2536. ja ulRet
  2537. call EndPage
  2538. ulRet: ret
  2539. UseLine endp
  2540. ;*** ZeroTotals - zero grand total file count, size
  2541. ;
  2542. ; ENTRY nothing
  2543. ;
  2544. ; EXIT nothing
  2545. ;
  2546. ; USED AX
  2547. ;
  2548. ; EFFECTS
  2549. ;
  2550. ; FileCntTotal & FileSizTotal are zeroed.
  2551. ;
  2552. ; NOTES
  2553. ;
  2554. ; FileCntTotal & FileSizTotal must be juxtaposed, in that order.
  2555. ZeroTotals proc
  2556. mov di,offset TRANGROUP:FileCntTotal
  2557. mov cx,size FileCntTotal+size FileSizTotal
  2558. xor al,al
  2559. rep stosb
  2560. ret
  2561. ZeroTotals endp
  2562. ;*** CtrlCHandler - our own control-c handler
  2563. ;
  2564. ; Make sure user's default directory gets restored. See notes
  2565. ; at InstallCtrlCHandler.
  2566. ;
  2567. ; ENTRY control-c
  2568. ;
  2569. ; EXIT to OldCtrlCHandler
  2570. ;
  2571. ; USED DS,flags
  2572. ;
  2573. ; EFFECTS
  2574. ;
  2575. ; Restore user's default directory.
  2576. ;
  2577. ; NOTES
  2578. ;
  2579. ; This handler is only installed after calling PathCrunch,
  2580. ; which sets UserDir1, so the restoration will work.
  2581. ;
  2582. ; The original control-c vector will be restored, whether
  2583. ; or not this one is invoked, in the HeadFix routine.
  2584. CtrlCHandler proc far
  2585. ;SR;
  2586. ; Save all registers used: ds, dx, ax. I know ax is being used by the
  2587. ;CtrlC handler, am not sure about ds & dx. Save them to be safe
  2588. ;
  2589. push ds
  2590. push cs
  2591. pop ds ; DS = TRANGROUP seg addr
  2592. push ax
  2593. push dx
  2594. invoke RestUDir ; restore user's default directory
  2595. pop dx
  2596. pop ax
  2597. pop ds
  2598. jmp cs:OldCtrlCHandler ; go to previous int 23 handler
  2599. CtrlCHandler endp
  2600. ;M010;start
  2601. ;*** LowerCase - convert ASCII character in AL to lowercase
  2602. ;
  2603. ; ENTRY AL = character to be displayed
  2604. ;
  2605. ; EXIT AL is lowercase
  2606. ;
  2607. ; USED nothing
  2608. LowerCase proc
  2609. assume ds:NOTHING,es:NOTHING
  2610. cmp al,'A' ; ensure AL is in range 'A'-'Z'
  2611. jb lcRet
  2612. cmp al,'Z'
  2613. ja lcRet
  2614. or al,20h ; convert to ASCII lowercase (UpperCase+32)-->LowerCase
  2615. lcRet: ret
  2616. LowerCase endp
  2617. ;*** LowercaseString - convert ASCIIZ string at DS:SI to lowercase
  2618. ;
  2619. ; ENTRY DS:SI points to start of ASCIIZ string
  2620. ; ES = DS
  2621. ;
  2622. ; EXIT nothing
  2623. ;
  2624. ; USED AL,SI
  2625. LowercaseString proc
  2626. assume ds:NOTHING,es:NOTHING
  2627. push di ; save di
  2628. mov di,si ; ES:DI --> ASCIIZ string
  2629. cld
  2630. NextChar:
  2631. lodsb ; get character from string into al
  2632. or al,al ; are we at end of string?
  2633. jz EndOfString
  2634. ifdef DBCS
  2635. invoke testkanj
  2636. jz @f ; if this is not lead byte
  2637. stosb ; store lead byte
  2638. lodsb ; get tail byte
  2639. or al,al
  2640. jz EndOfString ; if end
  2641. stosb ; store tail byte
  2642. jmp short NextChar
  2643. @@:
  2644. endif
  2645. call LowerCase ; convert character to lowercase
  2646. stosb ; store character back into buffer
  2647. jmp SHORT NextChar ; repeat until end of string
  2648. EndOfString:
  2649. pop di ; restore di
  2650. ret
  2651. LowercaseString endp
  2652. ;M010;end
  2653. ifdef DBCS
  2654. ;
  2655. ; Check if the character position is at Tail Byte of DBCS
  2656. ;
  2657. ; input: ds:si = start address of the string
  2658. ; ds:di = character position to check
  2659. ; output: ZF = 1 if at Tail Byte
  2660. ;
  2661. CheckDBCSTailByte proc near
  2662. push ax
  2663. push cx
  2664. push di
  2665. mov cx,di ; save character position
  2666. cdtb_check:
  2667. cmp di,si
  2668. jz cdtb_next ; if at the top
  2669. dec di ; go back
  2670. mov al,[di] ; get character
  2671. invoke testkanj
  2672. jnz cdtb_check ; if DBCS lead byte do next
  2673. inc di ; adjust
  2674. cdtb_next:
  2675. sub cx,di ; if the length is odd then
  2676. xor cl,1 ; the character position is
  2677. test cl,1 ; at the tail byte
  2678. pop di
  2679. pop cx
  2680. pop ax
  2681. ret
  2682. CheckDBCSTailByte endp
  2683. endif
  2684. TRANCODE ends
  2685. end
  2686.