D.MOD 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. MODULE D;
  2. (*
  3. * REPERTOIRE
  4. * Release 1.6
  5. * By Charles Bradford and Cole Brecheen
  6. * (c) Copyright 1985-1990 PMI
  7. * Green Bay Wisconsin
  8. * All rights reserved
  9. * (414) 468-6040
  10. *
  11. * $Header: D:/logfiles/demos/d.mov 1.2 03 Dec 1990 07:01:24 coleb $
  12. *
  13. *)
  14. (*
  15. Directory Management With D.MOD
  16. D.MOD is a sample director manager. Its purpose is
  17. to illustrate the use of Repertoire's Drectory module.
  18. See section 7.10. It makes more convenient the four most
  19. frequently performed operations in the PC/MS-DOS
  20. operating system: listing, deleting, renaming, and
  21. copying files. It lists directories using both the left
  22. and right sides of the screen; it allows prompted file
  23. erasure; it allows prompted renaming and directory-
  24. shifting of files; and it allows prompted file copying
  25. and moving with safety checks to prevent accidental
  26. erasures.
  27. Listing Directories.
  28. To list the entire current directory of the default
  29. drive using both sides of the screen, enter "d" and
  30. press <RETURN>. If the screen fills, the program
  31. suspends the listing until you press a key. Unlike the
  32. MS-DOS DIR /W (wide) command, which lists only file
  33. names, D provides complete information about each file.
  34. To list the entire current directory of a drive
  35. other than the default drive (say, the A: drive), type
  36. "d a" and press <RETURN>. Notice that D does not
  37. require a trailing colon to specify a drive letter--it
  38. assumes that any single-character program parameter is
  39. a drive letter. To list all files with extensions of
  40. .ltr in the subdirectory \letters, enter "d \letters\*.ltr"
  41. or "d letters\*.ltr". If \letters is not on the
  42. default drive, enter "d a:letters\*.ltr" or
  43. "d a:\letters\*.ltr". To list all the files in the
  44. \letters subdirectory, enter "d letters\". The
  45. trailing slash tells D to list a subdirectory instead
  46. of a file in the current directory named letters.
  47. D expands the power of the asterisk as an expansion
  48. character. For example, to list all files beginning
  49. with the letter A, regardless of extension, you need
  50. only enter "a*" as D's command-line parameter.
  51. Entering "art*xt" would list all files beginning with
  52. 'art' and ending (in the extension part of the name)
  53. with 'xt'. It would list ARTICLE.TXT, for example, or
  54. ARTWORK.EXT. Multiple asterisks are allowed in a
  55. single command.
  56. Erasing Files.
  57. Suppose you want to erase all documents in the
  58. \letters subdirectory on drive B: that are more than a
  59. year old. Using D, you can enter "d b:\letters\/e" and
  60. press <RETURN>. The trailing /e tells D to invoke its
  61. file-erasing function. D will display a full directory
  62. entry for the first file in the \letters subdirectory,
  63. followed by the prompt "Erase?" If the date indicates
  64. that the file is more than a year old, you can press Y
  65. to erase it. Press N to leave the file on the disk. D
  66. will continue to display directory entries and ask for
  67. permission to erase them until it can find no more
  68. matching files or until you press Q, for quit.
  69. Copying Files.
  70. D allows you to decide both whether to copy each
  71. matching file and whether to destroy any files of the
  72. same name on the destination disk. Suppose, for
  73. example, you want to make sure that two disks each have
  74. the same 30-file set of implementation modules for a
  75. large program you're developing. For each of the 30
  76. files, you have to determine which disk has either the
  77. larger or the more recent version of the file.
  78. On the DOS command line, enter "d a:*imp/c". The
  79. trailing /c tells D that it is to COPY matching files.
  80. The program will ask, "Copy to what drive:\path?"
  81. Enter "b" and press <RETURN>. No trailing colon is
  82. required. You can copy to the current drive by merely
  83. pressing <RETURN>. For each of the 30 implementation
  84. modules on drive A:, D will display complete directory
  85. information and ask, "Copy?" Press Y to copy the file,
  86. N to skip it, and Q to terminate the program.
  87. If you press Y, D will determine whether the
  88. destination disk contains a file of the same name. If
  89. it does, D will display complete directory information
  90. for that file and ask, "Destroy?" You can look at the
  91. date and, if the file on the destination disk is less
  92. recent than the file on the source disk, press Y. If
  93. you press N, D will prompt you to "Enter new name, or
  94. <RETURN> to skip." To copy the file to the destination
  95. disk under a different name, type in the new name and
  96. press <RETURN>. D will again determine whether the
  97. destination disk contains a file of the same name. If
  98. it doesn't, D will copy the file. If you only press
  99. <RETURN> when prompted for a new name, D will not copy
  100. the file on the source disk, and will go to the next
  101. matching file.
  102. After you've answered yes or no to D's prompts on
  103. each of the 30 .MOD files on drive A:, reverse the
  104. process by entering "d b:*.MOD/c" and entering "a" when
  105. asked "Copy to what drive:\path?" Each time D asks
  106. whether you want to destroy a file on drive A:, press N
  107. if the file is identical. At the end of the process
  108. you'll have the most recent 30-file set of
  109. implementation modules on each disk.
  110. Renaming Files.
  111. D allows you to rename files and move them between
  112. directories without recopying them using much the same
  113. syntax that you employ with its other functions. For
  114. example, to move selected files with .LTR extensions
  115. from the root directory of your hard disk to the \LTRS
  116. subdirectory, enter:
  117. C>d *ltr \ltrs\*ltr/r
  118. D will respond as follows:
  119. F1.LTR 50950 2-02-86 8:04p |Rename \ltrs\F1.ltr? no
  120. F3.LTR 23557 2-02-86 1:31p |Rename \ltrs\F3.ltr? yes
  121. F2.LTR 34821 2-02-86 2:59p |Rename \ltrs\F2.ltr? no
  122. C>_
  123. The trailing /r is the command that tells D to
  124. rename the files that match its first command-line
  125. parameter. D renames the files in accordance with the
  126. same rules used in the DOS RENAME operation, with the
  127. exception that D does not require separate asterisks on
  128. each side of the period.
  129. Moving Files
  130. A trailing /m modifies both the renaming and the
  131. copying operations. A trailing /m causes D first to
  132. determine whether the two file specifications are on
  133. different drives. If they are, D copies files to the
  134. destination drive just as it does when you use the /c
  135. command, but it also erases from the source drive any
  136. files that are successfully copied. If the files are on
  137. the same drive, a trailing /m causes D to erase any
  138. conflicting file names from the destination directory;
  139. the rename operation normally aborts if a file of the
  140. same name is in the destination directory.
  141. Batch Mode
  142. A trailing /b causes any yes/no prompt automatically
  143. to be answered Yes.
  144. *)
  145. IMPORT BigSets;
  146. IMPORT Drectory;
  147. IMPORT EnvironUtils;
  148. IMPORT ErrorManager;
  149. IMPORT ErrStrgs;
  150. IMPORT KbdInput;
  151. IMPORT LowLevel;
  152. IMPORT M2Strings;
  153. IMPORT Numbers;
  154. IMPORT HandleIO;
  155. IMPORT FAPI;
  156. IMPORT PosUtils;
  157. IMPORT StrConv;
  158. IMPORT StrEdit;
  159. IMPORT StringIO;
  160. IMPORT SYSTEM;
  161. IMPORT InitCompilerMods;
  162. CONST
  163. blank = ' ';
  164. null = '';
  165. VAR
  166. SecondStr, DirMask: ARRAY [0..79] OF CHAR;
  167. FileInfo: Drectory.FileInfoRec;
  168. BatchMode, exiting, moving, renaming, copying, deleting,
  169. OnTheLeft : BOOLEAN;
  170. SavedMessage : CARDINAL;
  171. TheDrive : CHAR;
  172. BytesPerSector, SectorsPerCluster,
  173. ClustersOnDisk: CARDINAL;
  174. KindOfDisk : Drectory.DiskTypes;
  175. ClusterSize : LONGINT;
  176. PROCEDURE yes() : BOOLEAN;
  177. VAR
  178. choice : CARDINAL;
  179. BEGIN
  180. (*yes*)
  181. IF BatchMode THEN
  182. StringIO.WriteStr(StringIO.outp, 'yes');
  183. RETURN TRUE;
  184. END;
  185. choice := KbdInput.KeyHit( KbdInput.YorN );
  186. IF KbdInput.CAPkey(choice) = ORD('Y') THEN
  187. StringIO.WriteStr(StringIO.outp, 'yes');
  188. RETURN TRUE;
  189. ELSE
  190. StringIO.WriteStr(StringIO.outp, 'no');
  191. IF KbdInput.CAPkey(choice) = ORD('Q') THEN
  192. exiting := TRUE;
  193. END;
  194. RETURN FALSE;
  195. END;
  196. END yes;
  197. PROCEDURE IsDriveLetter( TheStr: ARRAY OF CHAR ): BOOLEAN;
  198. BEGIN
  199. RETURN (M2Strings.Length(TheStr) = 1)
  200. AND ( (CAP(TheStr[0]) >= 'A') AND (CAP(TheStr[0]) <= 'Z'));
  201. END IsDriveLetter;
  202. PROCEDURE Punctuate( VAR TheStr: ARRAY OF CHAR );
  203. VAR
  204. index, PlaceCount: CARDINAL;
  205. BEGIN
  206. index := M2Strings.Length( TheStr );
  207. IF index > 0 THEN
  208. DEC( index );
  209. PlaceCount := 2;
  210. REPEAT
  211. IF PlaceCount > 0 THEN
  212. IF index > 0 THEN
  213. DEC( index );
  214. END;
  215. DEC( PlaceCount );
  216. ELSE
  217. PlaceCount := 2;
  218. M2Strings.Insert( ',', TheStr, index );
  219. DEC( index );
  220. END;
  221. UNTIL (index = 0) OR (NOT PosUtils.IsNumericChar(TheStr[index]));
  222. END;
  223. END Punctuate;
  224. PROCEDURE DifferentDrives( str1, str2: ARRAY OF CHAR ): BOOLEAN;
  225. VAR
  226. DriveChar1, DriveChar2: CHAR;
  227. BEGIN
  228. IF IsDriveLetter(str1) OR (str1[1] = ':') THEN
  229. DriveChar1 := CAP(str1[0]);
  230. ELSE
  231. DriveChar1 := CAP(Drectory.GetDefaultDrive());
  232. END;
  233. IF IsDriveLetter(str2) OR (str2[1] = ':') THEN
  234. DriveChar2 := CAP(str2[0]);
  235. ELSE
  236. DriveChar2 := CAP(Drectory.GetDefaultDrive());
  237. END;
  238. RETURN DriveChar1 # DriveChar2;
  239. END DifferentDrives;
  240. PROCEDURE MakeInfoStr( FileInfo: Drectory.FileInfoRec; VAR TheStr: ARRAY
  241. OF CHAR );
  242. VAR
  243. dumstr: ARRAY [0..79] OF CHAR;
  244. BEGIN
  245. StrEdit.AssignStr( FileInfo.name, TheStr );
  246. WHILE M2Strings.Length(TheStr) < 12 DO
  247. StrEdit.Append( TheStr, ' ' );
  248. END;
  249. IF Drectory.SubdirectoryFile IN FileInfo.attribute THEN
  250. StrEdit.Append( TheStr, ' <DIR>' );
  251. ELSE
  252. StrConv.LongIntegerToStr( FileInfo.size, 0, dumstr );
  253. IF FileInfo.size < 1000000 THEN
  254. (* No room for commas if the string is longer than 6 chars. *)
  255. Punctuate( dumstr );
  256. END;
  257. StrEdit.RightJustify( dumstr, 8 );
  258. StrEdit.Append( TheStr, dumstr );
  259. END;
  260. StrConv.DateToStr( FileInfo.month, FileInfo.day, FileInfo.year,
  261. dumstr );
  262. StrEdit.Append( TheStr, ' ' );
  263. StrEdit.Append( TheStr, dumstr );
  264. StrConv.TimeToStr( FileInfo.hour, FileInfo.minute, FileInfo.second,
  265. FileInfo.second, dumstr );
  266. M2Strings.Delete( dumstr, M2Strings.Length(dumstr) - 7, 6 );
  267. StrEdit.Append( TheStr, ' ' );
  268. StrEdit.Append( TheStr, dumstr );
  269. END MakeInfoStr;
  270. PROCEDURE SayNotFound();
  271. VAR
  272. BytesFree : LONGINT;
  273. label, BytesFreeStr : ARRAY [0..79] OF CHAR;
  274. BEGIN
  275. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  276. Drectory.FreeDiskSpace(TheDrive,BytesFree) );
  277. StrConv.LongIntegerToStr(BytesFree, 1, BytesFreeStr);
  278. Punctuate( BytesFreeStr );
  279. Drectory.VolumeLabel(TheDrive, label);
  280. StringIO.WriteStr(StringIO.outp, 'File not found on ');
  281. StringIO.WriteStr(StringIO.outp, label);
  282. StringIO.WriteStr(StringIO.outp, '; ');
  283. StringIO.WriteStr(StringIO.outp, BytesFreeStr);
  284. StringIO.WriteEol(StringIO.outp, ' bytes free.');
  285. END SayNotFound;
  286. PROCEDURE WriteBarAndPrompt( FileInfoStr, ActionProposed,
  287. NewName: ARRAY OF CHAR );
  288. VAR
  289. tmpstr: ARRAY [0..79] OF CHAR;
  290. BEGIN
  291. StrEdit.AssignStr( FileInfoStr, tmpstr );
  292. StrEdit.Append( tmpstr, blank );
  293. StrEdit.Append( tmpstr, CHR(186) );
  294. StrEdit.Append( tmpstr, blank );
  295. StrEdit.Append( tmpstr, ActionProposed );
  296. IF M2Strings.Length(NewName) > 0 THEN
  297. StrEdit.Append( tmpstr, blank );
  298. StrEdit.Append( tmpstr, NewName );
  299. END;
  300. StrEdit.Append( tmpstr, '? ' );
  301. StringIO.WriteStr( StringIO.outp, tmpstr );
  302. END WriteBarAndPrompt;
  303. PROCEDURE ExpandAsterisk(VAR TheMask : ARRAY OF CHAR);
  304. VAR
  305. base, spot, indx : CARDINAL;
  306. BEGIN
  307. (*ExpandAsterisk*)
  308. indx := M2Strings.Pos('*',TheMask);
  309. WHILE indx<=HIGH(TheMask) DO
  310. TheMask[indx] := '?';
  311. base := indx;
  312. WHILE (base > 0)
  313. AND NOT (M2Strings.Pos( TheMask[base-1], ':\/' ) <= 2) DO
  314. DEC(base);
  315. END;
  316. spot := PosUtils.Positn( '.', TheMask, base );
  317. IF (spot>HIGH(TheMask)) THEN
  318. (*There's no period.*)
  319. StrEdit.InsertTimes('?', TheMask, indx, 12 - (M2Strings.Length(TheMask) - base) );
  320. TheMask[ base + 8 ] := '.';
  321. ELSIF (spot>indx) THEN
  322. (*Asterisk was in the filename part, not extension part.*)
  323. StrEdit.InsertTimes('?', TheMask, indx, 8 - (spot - base) );
  324. ELSE
  325. (*Asterisk was in the extension part.*)
  326. StrEdit.InsertTimes('?', TheMask, indx, 4 - (M2Strings.Length(TheMask) - spot) );
  327. END;
  328. indx := M2Strings.Pos('*',TheMask);
  329. END;
  330. END ExpandAsterisk;
  331. PROCEDURE PrepareDirMask(VAR TheStr : ARRAY OF CHAR);
  332. VAR
  333. spot : CARDINAL;
  334. BEGIN
  335. TheDrive := 'z';
  336. (*for default*)
  337. deleting := FALSE;
  338. copying := FALSE;
  339. renaming := FALSE;
  340. moving := FALSE;
  341. StrEdit.CrunchBlanks(TheStr);
  342. IF (M2Strings.Length(TheStr)>=2) THEN
  343. IF TheStr[M2Strings.Length(TheStr)-2]='/' THEN
  344. IF CAP( TheStr[M2Strings.Length(TheStr)-1] ) = 'B' THEN
  345. M2Strings.Delete(TheStr, M2Strings.Length(TheStr)-2, 2);
  346. StrEdit.CutTrailingChars(blank, TheStr);
  347. BatchMode := TRUE;
  348. ELSE
  349. BatchMode := FALSE;
  350. END;
  351. deleting := CAP( TheStr[M2Strings.Length(TheStr)-1] ) = 'E';
  352. copying := CAP( TheStr[M2Strings.Length(TheStr)-1] ) = 'C';
  353. renaming := CAP( TheStr[M2Strings.Length(TheStr)-1] ) = 'R';
  354. moving := CAP( TheStr[M2Strings.Length(TheStr)-1] ) = 'M';
  355. M2Strings.Delete(TheStr, M2Strings.Length(TheStr)-2, 2);
  356. StrEdit.CutTrailingChars(blank, TheStr);
  357. END;
  358. END;
  359. spot := M2Strings.Pos(blank,TheStr);
  360. IF spot<=HIGH(TheStr) THEN
  361. M2Strings.Copy(TheStr, spot+1, M2Strings.Length(TheStr)-1-spot, SecondStr);
  362. M2Strings.Delete(TheStr, spot, M2Strings.Length(SecondStr)+1);
  363. ELSE
  364. SecondStr := null;
  365. END;
  366. IF M2Strings.Length(TheStr) = 0 THEN
  367. StrEdit.AssignStr( '*.*',TheStr);
  368. ExpandAsterisk( TheStr );
  369. RETURN;
  370. END;
  371. IF M2Strings.Pos( '..', TheStr ) = ( HIGH(TheStr) - 1 ) THEN
  372. StrEdit.Append(TheStr, '\*.*');
  373. END;
  374. IF ((TheStr[M2Strings.Length(TheStr)-1]='\') OR
  375. (TheStr[M2Strings.Length(TheStr)-1]='/')) THEN
  376. StrEdit.Append(TheStr, '*.*');
  377. ELSIF IsDriveLetter(TheStr) THEN
  378. StrEdit.Append(TheStr, ':*.*');
  379. END;
  380. IF TheStr[1]=':' THEN
  381. TheDrive := TheStr[0];
  382. IF M2Strings.Length(TheStr)=2 THEN
  383. StrEdit.Append(TheStr, '*.*');
  384. END;
  385. END;
  386. ExpandAsterisk( TheStr );
  387. END PrepareDirMask;
  388. PROCEDURE SplitPathName(VAR PathName, TheMask : ARRAY OF CHAR);
  389. VAR
  390. TmpStr : ARRAY [0..79] OF CHAR;
  391. spot : CARDINAL;
  392. BEGIN
  393. (*SplitPathName*)
  394. IF IsDriveLetter(TheMask) THEN
  395. StrEdit.AssignStr( TheMask, PathName );
  396. StrEdit.Append( PathName, ':' );
  397. StrEdit.AssignStr( null, TheMask );
  398. RETURN;
  399. END;
  400. StrEdit.AssignStr( null, PathName);
  401. spot := 0;
  402. WHILE spot+1<=M2Strings.Length(TheMask) DO
  403. IF ((TheMask[spot]='\') OR (TheMask[spot]='/'
  404. ) OR (TheMask[spot]=':')) THEN
  405. M2Strings.Copy(TheMask, 0, spot+1, TmpStr);
  406. StrEdit.Append(PathName, TmpStr);
  407. M2Strings.Delete(TheMask, 0, 1+spot);
  408. spot := 0;
  409. ELSE
  410. INC(spot);
  411. END;
  412. END;
  413. END SplitPathName;
  414. PROCEDURE EraseOneFile( PathName, FileName: ARRAY OF CHAR ): BOOLEAN;
  415. VAR
  416. Fname : ARRAY [0..79] OF CHAR;
  417. BEGIN
  418. StrEdit.AssignStr( FileName, Fname );
  419. M2Strings.Insert(PathName, Fname, 0);
  420. IF Drectory.DeleteFile(Fname) = StringIO.NoError THEN
  421. RETURN TRUE;
  422. ELSE
  423. RETURN FALSE;
  424. END;
  425. END EraseOneFile;
  426. PROCEDURE EraseFiles();
  427. VAR
  428. PathName, Fname, TmpStr : ARRAY [0..79] OF CHAR;
  429. DirHandle: CARDINAL;
  430. BEGIN
  431. (*EraseFiles*)
  432. DirHandle := 0FFFFH;
  433. SavedMessage := Drectory.FindFirstFile( DirMask, DirHandle, FileInfo );
  434. IF SavedMessage # StringIO.NoError THEN
  435. SayNotFound();
  436. RETURN;
  437. END;
  438. SplitPathName(PathName, DirMask);
  439. REPEAT
  440. MakeInfoStr( FileInfo, TmpStr );
  441. IF NOT (Drectory.SubdirectoryFile IN FileInfo.attribute) THEN
  442. WriteBarAndPrompt( TmpStr, 'Erase', '' );
  443. IF yes() THEN
  444. IF NOT EraseOneFile( PathName, FileInfo.name ) THEN
  445. END;
  446. END;
  447. StringIO.WriteEol(StringIO.outp, null);
  448. END;
  449. SavedMessage := Drectory.FindNextFile( DirHandle, FileInfo );
  450. UNTIL (SavedMessage#StringIO.NoError) OR exiting;
  451. IF 0 # FAPI.DOSFINDCLOSE( DirHandle ) THEN END;
  452. END EraseFiles;
  453. PROCEDURE CopyFiles();
  454. VAR
  455. PathName1, PathName2 : ARRAY [0..79] OF CHAR;
  456. OldHandle, DirHandle : CARDINAL;
  457. OldHandleOpen : BOOLEAN;
  458. SavedMessage : CARDINAL;
  459. SavedFileMode : BITSET;
  460. TmpStr1, NewFullName, OldFullName : ARRAY [0..79] OF CHAR;
  461. PROCEDURE CheckDest( VAR PathName, FileName: ARRAY OF CHAR ): BOOLEAN;
  462. VAR
  463. TmpStr, NewFileName: ARRAY [0..79] OF CHAR;
  464. FinishedChecking : BOOLEAN;
  465. TmpFileInfo: Drectory.FileInfoRec;
  466. DirHandle: CARDINAL;
  467. BEGIN
  468. DirHandle := 0FFFFH;
  469. REPEAT
  470. FinishedChecking := TRUE;
  471. M2Strings.Concat(PathName, FileName, NewFileName);
  472. SavedMessage := Drectory.FindFirstFile(NewFileName, DirHandle,
  473. TmpFileInfo);
  474. IF NOT ((SavedMessage = StringIO.FileNotFound) OR (SavedMessage=
  475. StringIO.NoMoreFiles)) THEN
  476. IF SavedMessage # StringIO.NoError THEN
  477. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  478. SavedMessage );
  479. ELSE
  480. MakeInfoStr( TmpFileInfo, TmpStr );
  481. StringIO.WriteEol(StringIO.outp, null);
  482. WriteBarAndPrompt( TmpStr, 'Destroy', '' );
  483. IF NOT yes() THEN
  484. StringIO.WriteEol(StringIO.outp, null);
  485. StringIO.WriteStr(StringIO.outp,
  486. 'Enter new name, or <RETURN> to skip: ');
  487. StringIO.ReadStr(StringIO.inp, FileName);
  488. IF M2Strings.Length(FileName)=0 THEN
  489. IF 0 # FAPI.DOSFINDCLOSE( DirHandle ) THEN END;
  490. RETURN FALSE;
  491. ELSE
  492. SplitPathName( PathName, FileName );
  493. FinishedChecking := FALSE;
  494. END;
  495. END;
  496. END;
  497. END;
  498. UNTIL FinishedChecking OR exiting;
  499. IF 0 # FAPI.DOSFINDCLOSE( DirHandle ) THEN END;
  500. RETURN TRUE;
  501. END CheckDest;
  502. BEGIN
  503. (*CopyFiles*)
  504. DirHandle := 0FFFFH;
  505. IF Drectory.FindFirstFile( DirMask, DirHandle, FileInfo )
  506. # StringIO.NoError THEN
  507. SayNotFound();
  508. RETURN;
  509. END;
  510. IF M2Strings.Length(SecondStr)=0 THEN
  511. StringIO.WriteStr(StringIO.outp, ' Copy to what drive:\path? ');
  512. StringIO.ReadStr(StringIO.inp, SecondStr );
  513. END;
  514. SplitPathName( PathName2, SecondStr );
  515. SplitPathName( PathName1, DirMask );
  516. REPEAT
  517. MakeInfoStr( FileInfo, TmpStr1 );
  518. IF NOT (Drectory.SubdirectoryFile IN FileInfo.attribute) THEN
  519. WriteBarAndPrompt( TmpStr1, 'Copy', '' );
  520. IF yes() THEN
  521. M2Strings.Concat(PathName1, FileInfo.name, OldFullName);
  522. SavedFileMode := HandleIO.DefaultFileMode;
  523. HandleIO.DefaultFileMode := BITSET{ 5 };
  524. (* Read-only access; deny no other access *)
  525. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  526. HandleIO.OpenFile(OldHandle, OldFullName) );
  527. OldHandleOpen := TRUE;
  528. HandleIO.DefaultFileMode := SavedFileMode;
  529. IF M2Strings.Length(SecondStr) = 0 THEN
  530. StrEdit.AssignStr( FileInfo.name, TmpStr1 );
  531. ELSE
  532. StrEdit.AssignStr( SecondStr, TmpStr1 );
  533. END;
  534. IF CheckDest( PathName2, TmpStr1 ) THEN
  535. M2Strings.Concat(PathName2, TmpStr1, NewFullName);
  536. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  537. Drectory.CopyFile(OldHandle, NewFullName));
  538. IF moving THEN
  539. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  540. HandleIO.CloseHandle(OldHandle));
  541. OldHandleOpen := FALSE;
  542. IF NOT EraseOneFile( PathName1, FileInfo.name ) THEN
  543. HALT;
  544. END;
  545. END;
  546. END;
  547. IF OldHandleOpen THEN
  548. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  549. HandleIO.CloseHandle(OldHandle));
  550. OldHandleOpen := FALSE;
  551. END;
  552. END;
  553. StringIO.WriteEol(StringIO.outp, null);
  554. END;
  555. SavedMessage := Drectory.FindNextFile( DirHandle, FileInfo );
  556. UNTIL (SavedMessage # StringIO.NoError) OR exiting;
  557. IF 0 # FAPI.DOSFINDCLOSE( DirHandle ) THEN END;
  558. END CopyFiles;
  559. PROCEDURE RenameFiles();
  560. VAR
  561. mask2, path2, path1 : ARRAY [0..79] OF CHAR;
  562. PROCEDURE GetNewName(VAR InfoStr, OldName, NewName : ARRAY OF CHAR);
  563. VAR
  564. TmpOld : ARRAY [0..79] OF CHAR;
  565. ndx : CARDINAL;
  566. BEGIN
  567. (*GetNewName*)
  568. StrEdit.AssignStr( null, NewName);
  569. M2Strings.Copy(InfoStr, 0, M2Strings.Pos(blank,InfoStr), OldName);
  570. StrEdit.AssignStr( OldName, TmpOld);
  571. ndx := M2Strings.Pos('.',TmpOld);
  572. IF ndx>HIGH(TmpOld) THEN
  573. StrEdit.Append(TmpOld, '*');
  574. ExpandAsterisk(TmpOld);
  575. ELSIF (ndx<8) THEN
  576. M2Strings.Insert('*', TmpOld, ndx);
  577. ExpandAsterisk(TmpOld);
  578. END;
  579. ndx := 0;
  580. REPEAT
  581. IF mask2[ndx]='?' THEN
  582. IF TmpOld[ndx]#'?' THEN
  583. StrEdit.Append(NewName, TmpOld[ndx]);
  584. END;
  585. ELSE
  586. StrEdit.Append(NewName, mask2[ndx]);
  587. END;
  588. INC(ndx);
  589. UNTIL (ndx>=M2Strings.Length(mask2));
  590. END GetNewName;
  591. VAR
  592. TmpStr1, TmpStr2, OldName, InfoStr, NewName : ARRAY [0..79] OF CHAR;
  593. DirHandle: CARDINAL;
  594. BEGIN
  595. (*RenameFiles*)
  596. DirHandle := 0FFFFH;
  597. IF Drectory.FindFirstFile(DirMask, DirHandle, FileInfo)
  598. # StringIO.NoError THEN
  599. SayNotFound();
  600. RETURN;
  601. END;
  602. IF M2Strings.Length(SecondStr)=0 THEN
  603. StringIO.WriteStr(StringIO.outp, ' New name: ');
  604. StringIO.ReadStr(StringIO.inp, mask2);
  605. ELSE
  606. StrEdit.AssignStr( SecondStr, mask2);
  607. END;
  608. IF M2Strings.Length(mask2)=0 THEN
  609. StrEdit.AssignStr( '\*.*', mask2);
  610. END;
  611. IF DifferentDrives( DirMask, mask2 ) THEN
  612. copying := TRUE;
  613. renaming := FALSE;
  614. RETURN;
  615. END;
  616. SplitPathName(path2, mask2);
  617. SplitPathName(path1, DirMask);
  618. IF M2Strings.Length(path2)=0 THEN
  619. StrEdit.AssignStr( path1, path2);
  620. END;
  621. ExpandAsterisk(mask2);
  622. REPEAT
  623. IF NOT (Drectory.SubdirectoryFile IN FileInfo.attribute) THEN
  624. MakeInfoStr( FileInfo, InfoStr );
  625. GetNewName(InfoStr, OldName, NewName);
  626. StrEdit.AssignStr( path2, TmpStr1);
  627. StrEdit.Append(TmpStr1, NewName);
  628. WriteBarAndPrompt( InfoStr, 'Rename', TmpStr1 );
  629. IF yes() THEN
  630. M2Strings.Concat(path1, OldName, TmpStr1);
  631. M2Strings.Concat(path2, NewName, TmpStr2);
  632. IF moving THEN
  633. IF Drectory.RenameFile(TmpStr1,TmpStr2) # StringIO.NoError THEN
  634. IF NOT EraseOneFile( path2, NewName ) THEN
  635. HALT;
  636. ELSE
  637. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  638. Drectory.RenameFile(TmpStr1,TmpStr2));
  639. END;
  640. END;
  641. ELSE
  642. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  643. Drectory.RenameFile(TmpStr1,TmpStr2));
  644. END;
  645. END;
  646. StringIO.WriteEol(StringIO.outp, null);
  647. ELSE
  648. StringIO.WriteStr(StringIO.outp, "Can't rename '");
  649. StringIO.WriteStr(StringIO.outp, FileInfo.name);
  650. StringIO.WriteEol(StringIO.outp, "' ");
  651. END;
  652. UNTIL (Drectory.FindNextFile(DirHandle, FileInfo) # StringIO.NoError)
  653. OR exiting;
  654. IF 0 # FAPI.DOSFINDCLOSE( DirHandle ) THEN END;
  655. END RenameFiles;
  656. PROCEDURE UpToClusterSize(VAR TheRealSize : LONGINT);
  657. VAR
  658. clusters, NewSize : LONGINT;
  659. BEGIN
  660. clusters := TheRealSize DIV ClusterSize;
  661. INC(clusters);
  662. NewSize := ClusterSize * clusters;
  663. IF (TheRealSize + ClusterSize) # NewSize THEN
  664. TheRealSize := NewSize;
  665. END;
  666. END UpToClusterSize;
  667. PROCEDURE ListFiles();
  668. VAR
  669. choice : CARDINAL;
  670. DirHandle, resultcode, linecnt : CARDINAL;
  671. VolLabel, ListedBytes, BytesFreeStr : ARRAY [0..16] OF CHAR;
  672. TmpStr, ThePath : ARRAY [0..79] OF CHAR;
  673. TmpNum, ByteCnt, BytesFree : LONGINT;
  674. dummy : BOOLEAN;
  675. BEGIN
  676. (*ListFiles*)
  677. ByteCnt := Numbers.Lc( 0 );
  678. OnTheLeft := TRUE;
  679. Drectory.VolumeLabel(TheDrive, VolLabel);
  680. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  681. Drectory.GetCurrentDir(TheDrive,ThePath));
  682. DirHandle := 0FFFFH;
  683. SavedMessage := Drectory.FindFirstFile(DirMask, DirHandle, FileInfo);
  684. IF SavedMessage # StringIO.NoError THEN
  685. SayNotFound();
  686. RETURN;
  687. END;
  688. ErrStrgs.WriteErrToHandle( StringIO.ErrorOutp,
  689. Drectory.FreeDiskSpace(TheDrive,BytesFree));
  690. linecnt := 1;
  691. REPEAT
  692. TmpNum := FileInfo.size;
  693. UpToClusterSize(TmpNum);
  694. ByteCnt := ByteCnt + TmpNum;
  695. MakeInfoStr( FileInfo, TmpStr );
  696. IF OnTheLeft THEN
  697. StringIO.WriteStr(StringIO.outp, TmpStr);
  698. ELSE
  699. M2Strings.Insert(' ', TmpStr, 0);
  700. TmpStr[1] := CHR(186);
  701. StringIO.WriteStr(StringIO.outp, TmpStr);
  702. INC(linecnt);
  703. IF linecnt=26 THEN
  704. choice := KbdInput.KeyHit( KbdInput.AnyKeyNum );
  705. IF KbdInput.CAPkey(choice) = ORD('Q') THEN
  706. ErrorManager.StraightToDOS('');
  707. END;
  708. StringIO.WriteStr(StringIO.outp, '_');
  709. linecnt := 1;
  710. ELSE
  711. StringIO.WriteEol(StringIO.outp, null);
  712. END;
  713. END;
  714. OnTheLeft := NOT (OnTheLeft);
  715. SavedMessage := Drectory.FindNextFile( DirHandle, FileInfo );
  716. UNTIL SavedMessage # StringIO.NoError;
  717. IF NOT OnTheLeft THEN
  718. INC(linecnt);
  719. IF linecnt>=25 THEN
  720. choice := KbdInput.KeyHit( KbdInput.AnyKeyNum );
  721. IF KbdInput.CAPkey(choice) = ORD('Q') THEN
  722. ErrorManager.StraightToDOS('');
  723. END;
  724. END;
  725. StringIO.WriteEol(StringIO.outp, null);
  726. END;
  727. StrConv.LongIntegerToStr(ByteCnt, 1, ListedBytes);
  728. Punctuate( ListedBytes );
  729. StrConv.LongIntegerToStr(BytesFree, 1, BytesFreeStr);
  730. Punctuate( BytesFreeStr );
  731. M2Strings.Insert(';', ThePath, 0);
  732. M2Strings.Insert(VolLabel, ThePath, 0);
  733. M2Strings.Insert(' ', ThePath, 0);
  734. StrEdit.Append(ThePath, '; ');
  735. StrEdit.Append(ThePath, BytesFreeStr);
  736. StrEdit.Append(ThePath, ' free. Files above occupy ');
  737. StrEdit.Append(ThePath, ListedBytes);
  738. StrEdit.Append(ThePath, '.');
  739. StringIO.WriteStr(StringIO.outp, ThePath);
  740. IF linecnt<=23 THEN
  741. StringIO.WriteEol(StringIO.outp, null);
  742. END;
  743. IF 0 # FAPI.DOSFINDCLOSE( DirHandle ) THEN END;
  744. END ListFiles;
  745. BEGIN
  746. (*D*)
  747. exiting := FALSE;
  748. BigSets.AppendSet( KbdInput.YorN, "{'q', 'Q'}" );
  749. EnvironUtils.GetProgParams(DirMask);
  750. PrepareDirMask(DirMask);
  751. Drectory.GetDiskInfo( TheDrive, BytesPerSector, SectorsPerCluster,
  752. ClustersOnDisk, KindOfDisk );
  753. ClusterSize := Numbers.Lc( BytesPerSector * SectorsPerCluster );
  754. IF deleting THEN
  755. EraseFiles();
  756. ELSIF moving OR renaming THEN
  757. RenameFiles();
  758. IF copying THEN
  759. (* We do this because we may have discovered differing drive names. *)
  760. CopyFiles();
  761. END;
  762. ELSIF copying THEN
  763. CopyFiles();
  764. ELSE
  765. ListFiles();
  766. END;
  767. END D.
  768.