; CFG2 SCRIPT FOR GENERATING THE CDU HTML FILES ; TSECFGEXPR '{\<\%HEAD}|{^\#send}' ; TSECFGOPTS 'ix' ;=========================================================================== ; 20020725 MSD 002 Corrected a reference to #NUMBERS. (Should have been #NUM.) ; 20020101 MSD 001 Corrected a couple of typos. ; 20010301 MSD 000 Initial development. ;=========================================================================== #define CDUWEBSITE http://www.glod.net #define CDUEMAIL cdu@glod.net #define HEADA H1 #define HEADB H2 #define HEADC H3 #define < <; #define > >; #define & &; #define CODE_START
#define CODE_END;=========================================================================== #switch !MAKECLEAN ;=========================================================================== #file INDEXhtml cdu.htm #file TUTORhtml cdutut.htm #file VERSIONShtml cduver.htm #file FAQhtml cdufaq.htm #file REFhtml cduref.htm #file WrdItemFil WrdItem.ini #source WrdItemSrc WrdItem.ini #source VersionSrc Version.ini #includ VersionSrc #define TITLE CDU %PVERSION% ;=========================================================================== ; *Fully* disable switch expressions after "subroutines" are generated. #margin 1 ;=========================================================================== #define WrdName #define WrdExamp #send WrdItemFil ;
Welcome to CDU, the ChAoS Disk Utility. This program is a low-level disk utility aimed at sector-level manipulation of disks. An obvious application for CDU is doing backups on a disk image basis. However, it can be used for a much broader range of tasks. For example, it has been used to save and restore floppy disk images, to search for and recover "lost" photograph image files on a Smart Media card and to locate "bad" sectors on hard disks.
The main benefit of using CDU are that it is a command-line utility and so lends itself to repetitive tasks better than GUI apps. Also, it operates by interpreting a simple script language and so can be made, for example, to do automatic compares after a copy operation.
<%HEADB%> Requirements %HEADB%>In order to work, CDU merely requires that you have the MSdos executable file. Although it will run under Windows 95 and so on, when backing up, we would definitely recommend booting off of an MSdos floppy disk.
Note that CDU can, in theory at least, backup any operating system - if the BIOS can access the disk, then you should be able to manipulate it. When accessing a disk at the sector level, CDU knows nothing of partition tables, files systems and so on. This was a deliberate policy so that one could, for example, use an MSdos bootable floppy containing CDU to backup a hard disk that was dedicated entirely to, say, the Linux operating system.
<%HEADB%> Package Contents %HEADB%>You should have the following:
cdu.exe | The CDU executable file. |
---|---|
*.cdu | Some example CDU script files. |
%VERSIONSHTML% | Change history of the CDU program. |
%TUTORHTML% | CDU's Tutorial. |
%INDEXHTML% | This introduction to CDU. |
%FAQHTML% | A file of Frequently Asked Questions. |
%REFHTML% | A CDU Reference Manual. |
To actually run CDU, only the executable is required. The program can be used interactively. However, it would normally be used by specifying commands on the command-line which, of course, could cause CDU to load and run a script file.
If you are a first-time user of CDU, We suggest that you read the tutorial.
<%HEADB%> Licence %HEADB%>CDU is a public domain program. You are free to re-distribute CDU to third parties if:
"The authors disclaim all warranties as to this software, whether express or implied, including without limitation any implied warranties of merchantability, fitness for a particular purpose, functionality or data integrity or protection."<%HEADB%> Copyright %HEADB%>
CDU was written by Mark ("Captain ChAoS") Davis with a small contribution from Mark Edmunds. By virtue of the fact that ChAoS had a hand in writing this program:
We're not sure that the terms "public domain" and "copyright" aren't mutually exclusive. Even so, this software is:
If you have any bug reports or suggestions, you can contact the authors at the CDU email address.
If you like CDU, perhaps you'll like the rest of the ChAoS Utilities - please visit the web site. #close * ;=========================================================================== #define QIden My IDE Drives Are Not Identified Properly. Why? #define QComm Can I Use CDU Via A Communications Channel? #say Generating FAQ HTML file. #send FAQhtml
Unfortunately, the IDE "get drive parameters" command is not usable via the earlier versions of the extended INT13 API. Hence, we have plagiarized code to access the hardware directly. It goes without saying that this is a Bad Thing. This is especially true in view of the fact that, although we've tried software from several different sources, none of it works consistently on all machines.
Version three of the API allows the programmer to send arbitrary IDE commands to a hard drive and this could be used to get the drive parameters. However, at the time of writing (March, 2001), we've not actually come across any machines that have a version three API.
Hence, if you want your drive identified by name, then you're stuck with this kludge. Now you know why, at the last minute before releasing a beta-test version of this software, we decided to make the IDENTIFY switch default to an off state...
<%HEADB%> %QCOMM% %HEADB%>Yes! However, by default, CDU handles the keyboard via (non-standard) MSdos and BIOS function calls. These, of course, won't work when you are trying to use CDU via a communications channel. For example, CDU will not work correctly if you try to use it via a TELNET link unless you enable the STDKB switch.
For more information on this topic, see the entry for the STDKB switch in the reference manual.
#close * ;=========================================================================== #say Generating Change Log HTML file. #send VERSIONShtml0.0.059 | Fixed the problem whereby a forced "sad" beep was sometimes done on exit from an interactive session even if sounds were off. |
---|---|
0.0.054 | Slight cosmetic alterations to the printing of offsets when sector addresses are printed. |
0.0.050 | When CONFIRM is disabled, the program will now inhibit the question asked when if thinks BUFSIZ is being made too large;; it will now merely set BUFSIZ to whatever the user has requested. |
0.0.049 | If VERBOSE is enabled, CDU will now dump the version and API bits when the INT13 extended interface is probed. (In fact, it'll only do this if the interface is deemed to exist. You can still have a look at these bits, even if the interface is deemed not to exist, by enabling DEBUG instead.) |
0.0.042 | Adopt the new "standard" format for the files that keep track of the program's version number. This will allow easy generation of the current version of the program and, in particular, the web site can automatically generate a list of current program version numbers. |
0.0.030 | Added FWRITE and HWRITE which are type-specific enable switches for floppies and hard drives, respectively. The old switch, WRITE, has been retained;; setting WRITE will have the effect of setting FWRITE and HWRITE so, in effect, old .CDU scripts will still work. Note that only WRITE is tested when writing to volumes. The new words only apply (at the moment, at any rate) to disks. |
0.0.026 | Altered the default state of the IDENTIFY switch to be off - we think it's dangerous to leave it enabled by default until we can make the IDE identification process reliable. |
The ChAoS Disk Utility, or "CDU", is a command-line based program intended to manipulate sectors on a disk at low-level. Its main use is for disk-to-disk or disk-to-file backups, although, because of the flexibility of the command-line interface, it can also be pressed into service when partition tables, boot records and so on have to be manipulated.
;Since CDU is such a potentially destructive program, by default it asks ;quite a number of "Are You Sure?" questions. While getting familiar with ;CDU, we'd recommend that you don't disable these.
;However, when the time comes, to facilitate the writing of .CDU script ;files that run repetitive backups where the commands are known to ;be correct, these confirmation questions can be disabled by using the ;CONFIRM directive.
At present, there is one important CDU limitation point of which you should be aware:
All devices must use a 512 byte sector size. We tried, at first, to make CDU handle any combination of sector size but there was a problem - using a compiler with a maximum of 32-bit integers means that, if one was to store sizes and offsets as byte relative, disk and file sizes would be limited to only four gigabytes and disks, of course, are already much bigger than that. Therefore, we're currently employing a scheme whereby all offsets and size are sector relative. As a result, handling differing sector sizes becomes much more difficult. Therefore, for the time being at least, CDU will only handle the standard IBM PC sector size.
This has repercussions for non-block devices. In particular, if the length of a file is not a multiple of 512 bytes, the "remainder" is ignored.
This should not be too much of a limitation if you stick to manipulating standard IBM PC volumes. However, CD-ROMs, for example may very well be "out of bounds" to CDU.
;----------------------------------------------------------------------------- ;In order to have a "standard" environment to run this tutorial, do the following:
Create a temporary directory somewhere and make it your "current" directory.
Make sure that the CDU.EXE program is on your system's search path but don't put it into your temporary directory.
Obtain a scratch 3.5" floppy diskette. Format it and make sure that it has no "bad" sectors on it by checking the totals at the end of the format.
CDU is command-line based and we've tried to build as much flexibility in as possible by allowing anything that appears on the command-line as parameters to be included in a "response" file. Indeed, the only significant differences between the command-line parameters and those in a response file is that the former has "CDU" at the start of the line and that the latter can have comments included.
CDU will always read the "response" file CDU.CDU (if it exists) before it executes the command-line. Thus, if one uses something like: %CODE_START% CDU @EXAMPLES %CODE_END%
Or:
%CODE_START% CDU INCLUDE EXAMPLES %CODE_END%CDU will run the CDU.CDU file and then execute commands in the command-line cited response file. In this case, CDU.CDU will be executed first and then EXAMPLES.CDU will be executed.
It's time to actually execute CDU so let's try this:
%CODE_START% CDU %CODE_END%CDU always tells you its version number regardless of how little or much it does. In this case, it "knows" that there is nothing to do and, hence, it displays a little text to tell you what it is and a hint about how to get more help.
Try invoking the help page - CDU will produce loads of output and, thus, you may wish to pipe it to your favourite text viewer or editor:
%CODE_START% CDU HELP %CODE_END%The help pages give the full grammar of CDU's script "language".
Let's try provoking CDU into giving us some information about the disk drives that it can "see". Try this:
%CODE_START% CDU INFO %CODE_END%On our machine, we get:
%CODE_START% CDU V0.6.038 Mar 02 2001 HD0: 1547 MB HD1: 6173 MB FD0: 1440 KB %CODE_END%Each line (except the "sign-on" text) starts with the name of a disk stream device. (In the rest of this tutorial, we have removed the sign-on text since it is always present and may actually be different to the text generated by your copy of CDU.) In our case, we have three disk drives. Namely, HD0, HD1 and FD0. It's time to meet the DETAIL directive. Run this:
%CODE_START% CDU DETAIL ON INFO %CODE_END%Our results are:
%CODE_START% HD0: i13ex 0003169152 512 786 64 63 HD1: i13ex 0012643155 512 787 255 63 FD0: i13ex 0000002880 512 80 2 18 %CODE_END%This tells us that CDU is using the extended INT13 API to access all three drives. It also tells us the last logical sector number, the sector length in bytes, the number of cylinders, the number of heads and the number of sectors on each track.
By the way, the DETAIL word cited above is one of CDU's "switches" - it takes one of only two states: "on" or "off". When changing the state of a switch, one can follow it by an ON word, an OFF word or neither. If you leave the new state out, it will toggle the value. Hence, since the DETAIL switch defaults to an "off" state, the previous command line could've been written as follows and produced the same results:
%CODE_START% CDU DETAIL INFO %CODE_END%In fact, this command can be shortened even further since, just for convenience, the sequence "DETAIL ON INFO" has a synonym. Therefore, the command could've been specified as:
%CODE_START% CDU VINFO %CODE_END%Commands can be strung together both on the command-line and within response files. The limitation on line length in the latter is fairly large and unlikely to seriously hamper the programmer.
Let's try another simple directive - this next one, the VERBOSE directive, is another switch. Once more, it merely alters the amount of "drivel" that CDU generates. In the case of VERBOSE, it's usually only employed when bug hunting a script:
%CODE_START% CDU VERBOSE INFO %CODE_END%This will produce a whole load of junk including some interesting information gleaned when CDU tries to "interrogate" the disk devices. (Once again, notice that the short form of "VERBOSE ON" has been used.)
When running commands, CDU does not interrogate the hard drives at an arbitrary point - only certain commands provoke a probe of the disk drives. The list is as follows:
The reason why only certain commands start a disk probe is that the user can manipulate the list of disks "seen" by CDU before the disk probe is done. Given that your disk list included an entry for hard drive zero ("HD0"), try the following:
%CODE_START% CDU DELETE HD0 VINFO %CODE_END%On our machine, this gives:
%CODE_START% HD1: i13ex 0012643155 512 787 255 63 FD0: i13ex 0000002880 512 80 2 18 %CODE_END%Notice that "HD0" has mysteriously gone missing from the list.
The justification for including such facilities is that the disk detection procedure is not fool-proof. Hence, you may have to fiddle with the system until CDU "gets it right". Usually, you do not.
In addition to be able to delete and add drives to the disk list, you can also dictate which disk interface CDU will use on a particular drive. For example, let's say that I want to remove HD0 from list (that is, prevent CDU from "seeing" it) and to force HD1 to be accessed via the bog-standard INT13 API instead of the go-faster INT13EX API:
%CODE_START% CDU DELETE HD0 IFACE HD1 INT13 VINFO %CODE_END%This gives us:
%CODE_START% HD1: i13 0012643155 512 787 255 63 FD0: i13ex 0000002880 512 80 2 18 %CODE_END%Note that, as before, HD0 is missing but that also the interface entry for HD1 has changed from "i13ex" to "i13". (In fact, I sometimes have to force an INT13 interface when accessing floppy drives - MSdos and Win95 appear to be very touchy in this respect.)
;----------------------------------------------------------------------------- ;One of the reasons behind wanting to write CDU was that we could find no commercial backup programs that would allow us to do fool-proof backups. Let us explain: let's say that you have two hard drives and, in the absence of removable storage devices of a sufficiently large capacity, you employ a disk-to-disk backup strategy. That is, each time you want to backup, you copy the entire contents, on a cylinder-by-cylinder basis, from the master disk to the backup. If you want to do a restore, this is no problem - you merely copy the data in the other direction.
However, one day, you're a bit tired and you copy from, HD1 to HD0 instead of from HD0 to HD1. Result? Disaster! You've over-written your master disk with an out-of-date backup. So, how can we avoid this situation?
The fact is that each IDE hard drive has an identifier that comprises the make/model string and serial number of the drive. The combination of these two items is unique - no two drives have the same combination of strings. So, how does this help us? Well, if the backup program can retrieve this information and you assign a disk name to each of your hard disks, you're much less likely to make a mistake.
In fact, given the above non-removable hard drive scenario, the benefit isn't so great. However, we backup, using the same disk-to-disk copy strategy, on removable media. Not only is it possible to get the wrong hard drive number, but we can end up with the wrong drive in the wrong drive bay . As a result, it's possible that even though we've nominated the correct drive numbers, being in the wrong drive bays means that the copy will still be in the wrong direction. If, though, we can specify drive names and the program can identify the drives via those names, things are much better.
So far, so good. But, there's a problem - in their wisdom, the writers of the INT13EX API did not see fit to allow the programmer to do a "get drive parameters". The very latest versions of this API do have a command that allows the programmer to send an arbitrary command to the drive and that could, indeed, be used to retrieve the disk parameters. However, we've yet to see a machine that has that version of the API. So, for now at least, we're stuck with the kludge - we've written our own software that goes directly to the disk hardware to get the identification information that we need.
It goes without saying that this is not an ideal situation. Since, though, it does appear to work, we've left the code in. However, since it isn't totally reliable on all machines, we've turned it off by default.
Enough waffle - let's play with this magic facility! Try this:
%CODE_START% CDU IDENTIFY INFO %CODE_END%On our machine, we get:
%CODE_START% HD0: 1547 MB WDCAC21600H:WD-WM3365525706 HD1: 6173 MB FUJITSUMPC3064AT:05022143 FD0: 1440 KB %CODE_END%Note that some drivel has appear at the end of each hard disk line. That's the combination of make/model string and serial number. In fact, CDU removes all non-printable characters from the data and concatenates the two strings using a colon.
Assuming that you do have something that is recognisably close to what we have above, it's time to make a script file that'll allow us to use these disk serial numbers.
Run the above command again but, this time, re-direct it to a file called NAMES.CDU in your current (temporary) directory, thus:
%CODE_START% CDU IDENTIFY INFO > NAMES.CDU %CODE_END%Now, using your favourite text editor, alter it to look like this (but using your own serial numbers of course):
%CODE_START% IDENTIFY ON NAME JIM WDCAC21600H:WD-WM3365525706 NAME BILL FUJITSUMPC3064AT:05022143 %CODE_END%Now try the following so that CDU will run your newly-created script file:
%CODE_START% CDU @NAMES INFO %CODE_END%We get the following results:
%CODE_START% HD0: 1547 MB JIM WDCAC21600H:WD-WM3365525706 HD1: 6173 MB BILL FUJITSUMPC3064AT:05022143 FD0: 1440 KB %CODE_END%Note the appearance of the strings "JIM" and "BILL" that identify the two drives HD0 and HD1.
Finally, rename the file NAMES.CDU to CDU.CDU and try this:
%CODE_START% CDU INFO %CODE_END%You should have been presented with the same results as before. When CDU starts up, it tries to find a file called CDU.CDU in the current directory and, if it can't find it, it looks in the "program" directory (that is, where the executable was stored). As soon as it finds a file called CDU.CDU, it runs it. Hence, because we renamed the NAMES.CDU file as CDU.CDU, it will now run it every time CDU is run with the temporary directory as the "current" directory.
So, given that CDU.CDU is executed correctly, instead of using "DISK HD0" and "DISK HD1", we could use "DISK JIM" and "DISK BILL" respectively. Note, too, by the way, that we have included an "IDENTIFY ON" directive in the CDU.CDU file so that drive identification is turned on no matter what default is currently in use.
Since some people may not be able to use the disk naming facility and we'd like all user's systems to be in a common state for the duration of this tutorial, delete the CDU.CDU file, now. (You can always replace it after you've finished using the tutorial.)
Please note the following:
Before using CDU for the first time, it's a good idea to just use "CDU INFO" to find out what drives it can "see". If the set of drives detected doesn't match what you were expecting, then use something like "CDU VERBOSE VINFO" instead. In other words, do the same thing again after invoking "waffle" mode.
Note that drives get disqualified if they don't appear to have extended INT13, ordinary INT13 or, if compiled in, the CHS values of a "get drive parameters" are not valid. The latter can happen if an "alien" floppy is put in the drive and a "DIR A:" is done.
A floppy drive will also not be "seen" if the operating system thinks that there is no floppy in the drive. In other words, it is sometimes necessary, before accessing a floppy disk, to make an attempt to access it by using the standard operating system commands. For example, a simply "DIR A:" is usually enough to allow CDU to access a floppy diskette.
CDU is a "stream based" program. In other words, the command operate on data streams and, with few exceptions, the commands operate in a similar manner regardless of the type of stream upon which it is operating.
The stream types are as follows:
DISK streams are the most fundamental. CDU accesses disk streams via the INT13 and INT13EX APIs and it's this stream type that would probably be used, for example, to backup a hard disk. Disk stream names are similar to those produced by the INFO command, above. Therefore, on our machine, we have three disk streams named "DISK HD0", DISK HD1" and "DISK FD0".
Most uses will be familiar with VOLUME streams. Your boot hard disk is probably "VOLUME C:" and your floppy drive is more than likely accessed by citing volume "VOLUME A:". Volume streams are almost as useful as disk streams. Note CDU may very well be able to access a "strange" device (a SmartMedia card reader, for example) as a volume stream whereas it would have no chance accessing it as a disk stream. (Quite simply, because it ain't a physical hard disk or floppy drive.)
FILE streams are merely MSdos files. Hence, an example of a file stream name would be "FILE FLOPPY.IMG". (We have adopted the standard extension of .IMG for disk image files. We suggest that you do the same since, at a later stage, we may alter CDU to recognise such a name automatically and, therefore, reduce the complexity of the CDU command-line.)
An ARCHIVE stream is merely a file which has been compressed via the GZIP system. Hence, an example name would be "ARCHIVE FLOPPY.GZ". (Once again, we suggest that you stick to the "standard" extension.) CDU always compresses a single file into each archive file. Please note that these are standard GZIP files and, hence, can be accessed by other compression programs.
A BYTE stream is an infinite sequence of a single data byte. The "name" of the stream is, in fact, merely the numeric value of the required byte. For example, to generate an infinite stream of exclamation mark characters, you could use the stream names "BYTE 0x21" or "BYTE 33".
You should note that, at least with the current version of CDU, when a stream name is required, you must always supply the stream type and stream name.
;----------------------------------------------------------------------------- ;Making sure that you've still got your scratch floppy disk in the drive, try searching for bad sectors on it. For this, we will first try the DUMP command:
%CODE_START% CDU DUMP DISK FD0 RANGE :+1 %CODE_END%When you run this, will present you with something ike the following:
%CODE_START% COMMAND: DUMP source disk FD0 range start:start Do you wish to execute this dump? (Y/N): %CODE_END%Note that we've asked to dump only the first sector of the diskette by citing the range "RANGE :+1". (The syntax of the RANGE clause is explained in a separate section.)
CDU has asked you to confirm that you want to carry on with the DUMP command. Reply with a 'Y'. After a very short pause, CDU should give a "happy" beep and the output on the screen should change to:
%CODE_START% COMMAND: DUMP source disk FD0 range start:start Do you wish to execute this dump? (Y/N): Y DUMP: 0000000001 0000000000 100% Dump completed %CODE_END%The line of text starting with "DUMP:" is user "comfort". That is, it serves merely to let you know that something is happening. The first number is the number of sectors processed so far (here, just the one) and the second number is the number of sectors that remain unprocessed (none, of course). The last number is the percentage of the task that's been done so far and, in this case, we've finished the task so it reads one hundred percent. Finally, "Dump completed" tells us that all went OK.
In this instance, the DUMP command hasn't actually done anything with the data that it's read. (Mind you, it has indicated that the data is readable, of course. In other words, you've done a bad sector search on the diskette's first sector.) Let's make something more interesting happen:
%CODE_START% CDU DETAIL DUMP DISK FD0 RANGE :+1 %CODE_END%As before, CDU will ask whether you want to continue and you should reply with a 'Y'. (From now on, always reply with a "yes" to the "do you want to execute" questions unless otherwise stated.) This time, you will note that CDU has printed the contents of the first diskette sector on the screen.
Having seen the DUMP command in action, let's try doing a COPY command.
;----------------------------------------------------------------------------- ;The COPY command requires that you nominate an input stream and an output stream. Let's assume that we want to take the whole of the floppy's image and stuff it into a file on our hard disk. Do this:
%CODE_START% CDU COPY DISK FD0 TO FILE FLOPPY.IMG %CODE_END%While the COPY runs, you'll see that the comfort text steadily changes the numbers until each operation has been carried out. At the end, CDU should have given you a happy beep. After that copy, a DIR command now shows the following. (Please note that for the purpose of writing this tutorial, we are running CDU under Win95, not MSdos.)
%CODE_START% FLOPPY IMG 1,474,560 04/03/01 14:31 FLOPPY.IMG %CODE_END%Have a look in the FLOPPY.IMG file using your favourite text viewer or editor. Hereinafter, we assume that you've the sense to do this when we say "look at the data" or whatever. Yes, you've guessed it! The data from your floppy disk is, indeed, in the FLOPPY.IMG file.
Note, by the way, that CDU will not ask you whether you want to overwrite any existing target file - it just goes ahead and does it. This is a damned good reason for adopting the "standard" CDU file extensions;; if you overwrite anything by accident, at least it's likely to be a file of the same type... You could, of course, set the "read only" attribute of an image file if the data was particularly valuable.
Using DISK streams isn't the only way of accessing the floppy - let's try saving our floppy disk image yet again but, this time, we'll copy it as a VOLUME stream. (In the following command, we are assuming that your floppy appears as drive A:;; if it does not, then merely substitute the correct drive letter.) Try this:
%CODE_START% CDU COPY VOLUME A: TO FILE FLOPPY2.IMG %CODE_END%The files in the current directory now look like this:
%CODE_START% FLOPPY IMG 1,474,560 04/03/01 14:31 FLOPPY.IMG FLOPPY2 IMG 1,474,560 04/03/01 14:37 FLOPPY2.IMG %CODE_END%You've seen an example of how to access FILE and VOLUME streams but now let's try making an ARCHIVE. As you might expect, we can use a variation on a command we've already used. Let's try making a compressed image of our scratch floppy. Type this:
%CODE_START% CDU COPY DISK FD0 TO ARCHIVE FLOPPY.GZ %CODE_END%The resulting file that you get will, of course, depend upon the data that was originally on the diskette. (Even though you formatted it, unless you did an "unconditional" format, most of the original data that was on there will still be on the diskette.)
After the previous command has run, on our machine, the directory listing looks like this:
%CODE_START% FLOPPY IMG 1,474,560 04/03/01 14:31 FLOPPY.IMG FLOPPY2 IMG 1,474,560 04/03/01 14:37 FLOPPY2.IMG FLOPPY GZ 1,060,555 04/03/01 14:40 FLOPPY.GZ %CODE_END%Since the latest file that we've created was a compressed one, FLOPPY.GZ is somewhat smaller than FLOPPY.IMG. As we've already said, the compression format used is a pretty standard one and so we can do this sort of thing:
%CODE_START% [WIN95] C:\Z\z>gzip -l floppy compressed uncompress ratio uncompressed_name 1060555 1474560 28.0% floppy %CODE_END%Finally, we introduce one more stream type: the BYTE stream. For example, Let us assume that you wanted a file that consisted of one thousand sectors worth of exclamation marks. This would do what we wanted:
%CODE_START% CDU COPY BYTE '!' RANGE :+1000 TO FILE PLING.TXT %CODE_END%The files that we have now look like this:
%CODE_START% FLOPPY IMG 1,474,560 04/03/01 14:31 FLOPPY.IMG FLOPPY2 IMG 1,474,560 04/03/01 14:37 FLOPPY2.IMG FLOPPY GZ 1,060,555 04/03/01 14:40 FLOPPY.GZ PLING TXT 512,000 04/03/01 14:43 PLING.TXT %CODE_END% ;----------------------------------------------------------------------------- ;If we had been backing up data, we might want to check that the copy really was the same as the original. What we need to do, of course, is a COMPARE command. Let's first see if our original diskette backup was, indeed, a true copy:
%CODE_START% CDU COMPARE DISK FD0 WITH FILE FLOPPY.IMG %CODE_END%Our results are:
%CODE_START% COMMAND: COMPARE source disk FD0 source file FLOPPY.IMG Do you wish to execute this compare? (Y/N): Y COMPARE: 0000002880 0000000000 100% Compare completed %CODE_END%From this, you can see that all the data was compared (we are at "100%") and that the compare completed OK (from the last line of text).
You should be able to compare any of the following items against each other and have them compare "OK": FD0, A:, FLOPPY.IMG, FLOPPY2.IMG, FLOPPY.GZ. In particular, try this:
%CODE_START% CDU COMPARE FILE FLOPPY2.IMG WITH ARCHIVE FLOPPY.GZ %CODE_END%This will compare the second disk image (taken, if you remember, from "VOLUME A:") against the compressed file FLOPPY.GZ. Note that any data streams can be compared and that ARCHIVEs are always compressed when being written to and decompressed when being read if you specify them as an ARCHIVE stream. In other words, this compare will fail:
%CODE_START% CDU COMPARE FILE FLOPPY2.IMG WITH FILE FLOPPY.GZ %CODE_END%In fact, if you try the above, CDU will almost certainly complain that FLOPPY.GZ is shorter than FLOPPY2.IMG and, therefore, cannot be identical. It will, though, allow you to continue and do the compare anyway. If you do that, you'll see something like this:
%CODE_START% ERROR: Compare fails! ERROR: First source not exhausted ERROR: Second source not exhausted Compare failed - SourceA: sector 0 Compare failed - SourceB: sector 0 ERROR: Compare FAILED %CODE_END%Now let's try something that takes a bit longer to complete. This time, we'll try to capture the whole floppy image into a file using the COPY command and then check that the new copy is OK by using COMPARE. We will, however, being using a script file to do this.
Edit a new file called, say, FLOPPY.CDU and place in it this text:
%CODE_START% CONFIRM OFF SOUND ON_ERROR COPY DISK FD0 TO FILE FLOPPY.IMG SOUND ON COMPARE DISK FD0 WITH FILE FLOPPY.IMG %CODE_END%The first line will stop CDU asking the "Do you want to do this?" questions. We're not doing any potentially destructive writing, so this is OK for now. The second line will stop us getting a happy beep if the COPY goes OK. (If the COPY fails, then the script will still terminate with a sad beep because we used "BEEP ON_ERROR" rather than "BEEP OFF".) The third line will backup up the entire diskette as no RANGE is specified. The fourth line re-enables the sound maker so that we'll get a beep whatever the outcome of the COMPARE on the last line. The COMPARE, of course, just ensures that the COPY went OK.
Now run this file by typing:
%CODE_START% CDU @FLOPPY %CODE_END%This should have copied a new floppy image to FLOPPY.IMG (notice that CDU did not ask you whether it was OK to overwrite the existing copy) and carried on to do a compare with no user intervention.
;----------------------------------------------------------------------------- ;We now turn our attention to the SEARCH facility. Each MSdos floppy should have the byte sequence "55AA" in the last two bytes of the first sector. Let's assume that we want to look for it and confirm that it exists. Try this at the command-line:
%CODE_START% CDU CONFIRM DETAIL SEARCH DISK FD0 FOR \x55\xAA %CODE_END%You should find that the pattern is found at offset 0x1FE. (Since there should be about forty lines of output, you'll have to pipe the output to a text viewer if your screen is only showing twenty-five lines.) Please note that, for once, case is important - the character following the text escapement back-slash must be lower-case. In other words, while "\x55\xAA" is all right, "\X55\XAA" would not work. This is one of the few places where case is significant to CDU.
Of course, since the floppy disk image is identical to the copy in the .IMG file on disk, this should produce the same result:
%CODE_START% CDU CONFIRM DETAIL SEARCH FILE FLOPPY.IMG FOR \x55\xAA %CODE_END% ;----------------------------------------------------------------------------- ;Sector ranges are specified by citing a start sector and an end sector which are separated by a colon.
Each of these two sector numbers are made up of two parts, the absolute part and the relative part. Just before the command is executed, the relative part is added to (or subtracted from) the absolute part.
The absolute part can be either a simple number or it can be one of two words that indicate the start or end of the device's stream. So, for example, both "2880" and "END" can be used to refer to the last sector of a standard three inch floppy diskette. In order to refer to the sector before the last sector, one could use "2879" or the more lucid "END-1".
Let's say you want to copy all of a floppy except the first hundred sectors and the last hundred sectors. You could use a range of "100:2781". However, this range can also be written as "START+100:END-100".
If one of the sector numbers in a range has the absolute part missing, then that relative part is treated as a length and the absolute part is copied from the other sector number's absolute part.
For example, the first hundred sectors on our three inch floppy can be specified as:
%CODE_START% "0:99" or "START:START+99" or "START:+100" %CODE_END%Note that when calculating "length" sector numbers, the calculation is applied taking into account any relative sector number. For instance, in the previous example, the start of the range was at the start of the diskette. That is, the range started at sector zero. What if, though, we wanted the next fifty sectors? Well, there are three ways we could do it:
%CODE_START% "100:149" or "START+100:START+49" or "START+100:+50" %CODE_END%Also note that in the last form, the final length of "+50" was applied after the "+100" has been applied to "START".
We can use negative lengths in a similar manner. When the length is negative, then that sector number that has an absolute part is deemed to be the ending sector of the range. Another example: what if we wanted the last hundred sectors of the floppy diskette? Take a look at this:
%CODE_START% "2780:2879" or "END-99:END" or "-100:END" %CODE_END%Note, in that last form, by the way, that "END:-100" won't work because, when the length is applied to the "end of range" sector number, it'll end up being smaller than the "start of range" sector number and CDU will not allow that.
For "completeness", as it were, let's say that we want the fifty sectors before those in the last example. Consider these:
%CODE_START% "2730:2779" or "END-149:END-100" or "-50:END-100" %CODE_END%As the required block gets more difficult to calculate by hand, of course, the more benefit these is in using offsets and length rather than merely calculating absolute sector numbers. (In fact, some of the above examples were written sometime ago. While validating some new ones we'd added, we discovered that we'd got one of the hand-calculated ones wrong - now d'you see how useful relative sector numbers and length are?)
Now for a final couple of examples of CDU "idiom".
If you wanted only the first sector of a stream, one might see the use of ":+1". The start absolute sector number will default to START giving "START:+1". Since the end number has no absolute part but it does have a relative part, the relative part is tread as a length (in this case, a single sector) and the resulting block is deemed to begin at the start sector. In other words, the resulting range is "START:START+0".
In a similar manner, the last sector of a stream can be specified using "-1:". The expansion of this is as follows: the ending sector number isn't present and so it defaults to END giving a result of "-1:END". The start sector has no absolute part so, once again, we assume it's a length and it's negative and so specifies that the block will finish at the ending sector number. Hence, it's equivalent to "END-0:END".
As we've already seen, using ":-1" will not work because this would expand to "START:-1" and, thence, to "START:START-1". Since, in this case, the start sector is less than the end sector, CDU will not accept the range.
It should be noted that our two idiom examples could also be written as ":START" and "END:", respectively.
;----------------------------------------------------------------------------- ;Since any low-level disk utility can be so destructive, we have made the CDU default state as "read only" as far as DISK and VOLUME streams are concerned. So far in this tutorial, we have only caused files to be written and we allow that by default since we assume that the operating system is "safe". Let us now try writing to a DISK device.
We will start by "washing" your scratch floppy - this is where you zap the diskette's contents so you'd better make sure that it's an unwanted floppy... The following command will cause all of the floppy to be overwritten with 0xAA bytes except for the first cylinder. (We don't write over that since the BIOS may then refuse to read the diskette at all.)
%CODE_START% CDU COPY BYTE 0XAA TO DISK FD0 OFFSET 36 %CODE_END%The above command will not work because we have forgotten to set CDU into the "write enable" state. Alter the command-line until it reads:
%CODE_START% CDU FWRITE COPY BYTE 0XAA TO DISK FD0 OFFSET 36 %CODE_END%Note that we have used OFFSET which is an alternative form of the RANGE clause. Since, in this instance, we don't want to bother specifying an end of range sector number, we let that default to the last sector number value. Therefore, the RANGE clause would look like "RANGE 36" and "OFFSET 36" reads so much better. Note, though, that the two words have an identical effect - as we have already stated, CDU allows synonyms for many of its "reserved" words.
Assuming that the wash went OK, have a look at the first couple of cylinders on the floppy. (As before, you'll have to find some way to pause or view CDU's output.)
%CODE_START% CDU DETAIL DUMP DISK FD0 RANGE :+72 %CODE_END%Notice that, starting at sector number 36, all of each sector is filled with the required 0xAA byte. This pattern should, of course, be continued all of the way until the end of the diskette.
An an aside, try re-copying the diskette data to a second archive:
%CODE_START% CDU COPY DISK FD0 TO ARCHIVE FLOPPY2.GZ %CODE_END%Notice the size of our second archive:
%CODE_START% FLOPPY IMG 1,474,560 04/03/01 14:58 FLOPPY.IMG FLOPPY2 IMG 1,474,560 04/03/01 14:37 FLOPPY2.IMG FLOPPY GZ 1,060,555 04/03/01 14:40 FLOPPY.GZ PLING TXT 512,000 04/03/01 14:43 PLING.TXT FLOPPY2 GZ 3,241 06/03/01 17:05 FLOPPY2.GZ FLOPPY CDU 154 04/03/01 14:57 FLOPPY.CDU %CODE_END%Since the majority of the diskette's data now consists of the same bit pattern, the compression algorithm of the archiving library has really gone to town - our FLOPPY2.GZ is only a little over three thousand bytes long!
A few words on the differences between WRITE, FWRITE and HWRITE are in order: FWRITE has to be enabled in order for CDU to write to a floppy DISK stream. Likewise, HWRITE controls writes to hard DISK streams. However, plain old WRITE will allow either ;; essentially, setting the state of the WRITE switch sets the FWRITE and HWRITE switches to the same state. (It's a historical thing - earlier versions of CDU used WRITE to control access to floppies and hard disks.)
Hence, unless there's a really good reason to do otherwise, if you intend to write to a floppy, use FWRITE and if you intend to write to a hard disk, use HWRITE. That way, if you get the wrong target, CDU may very well refuse to do anything. However, it will not stop you writing to the wrong device of the right type!
Finally, note that writing to VOLUME streams requires that WRITE be used - at present, CDU does not distinguish between floppy and hard drive volumes. (This may change at a later date.)
OK - let's try restoring our floppy to its former state. Let us write the original archive back onto it:
%CODE_START% CDU FWRITE COPY ARCHIVE FLOPPY.GZ TO DISK FD0 %CODE_END%Once again, convince yourself that it's done the Right Thing:
%CODE_START% CDU CONFIRM COMPARE VOLUME A: WITH FILE FLOPPY2.IMG %CODE_END%Notice that we use CONFIRM to inhibit the "d'you want to do this?" question. This could be a good time to make one thing clear: while DISK FD0 is equivalent to VOLUME A:, this is not true for hard drives. Even if, say, your DISK HD0 is partitioned as a large single volume, the first sector of VOLUME C: is not the first sector of the disk. For this reason, I tend to use DISK streams when backing up a device. That way, I know I've got all the disk's data. (This is especially true if AUTOEND is enabled.)
;----------------------------------------------------------------------------- ;When long disk processes are being carried out, it's not unusual for the perpetrator to take the chance for making a cup of tea, or whatever. Quite often, it'd be nice for the computer to be able to tell you when something has finished. This is the purpose of the REMIND directive.
By default, it's turned off. Hence, when CDU exits, it will only make a single beep depending upon the outcome of the command that ran. If one uses the REMIND directive, however, CDU can be made to "nag" you until you press a key on the keyboard.
Try this:
%CODE_START% CDU CONFIRM BADSCAN DISK FD0 RANGE :+1 %CODE_END%This will merely read-check the first sector on your floppy. Now try this instead:
%CODE_START% CDU CONFIRM REMIND 5 BADSCAN DISK FD0 RANGE :+1 %CODE_END%This will make CDU sound the last beep continuously until you press a key. A good use of this is when you've made a CDU script that backs up your main hard drive. This is likely to take some time so you set your intercom for "baby minder" mode and wander downstairs for a cup of tea. When the backup finishes, whatever the outcome (successful or otherwise), CDU'll keep beeping and you'll be able to hear it over the intercom. Using this facility, you won't have to keep going to check whether the back up has finished yet. (Normally, one knows roughly how long a particular backup should take and tends to only check a little before it is due to finish. The trouble with this approach is that something may have gone wrong as soon as you left the room and the computer may have been sitting there, idle, when you thought it was busy doing a backup.)
;----------------------------------------------------------------------------- ;We have left a large amount of debugging code in CDU. Partly, this is to aid diagnosis of user problems. (We can just ask the user to repeat whatever they did after invoking "maximum waffle" mode.) It also may help the user to sort out any problems they may be having with CDU - by its very nature, CDU isn't a "load 'n' run" application. In order to enable debug mode, merely turn the DEBUG switch on:
%CODE_START% DEBUG ON %CODE_END%Since the above directive produces loads of output, we've added a "filter" facility. The output produced by "DEBUG ON" prints, as the first item on each line, the function entry point name. One can use the TRACE directive to dictate which functions will be listed and which will be ignored. The strings after the TRACE directive is a wild-card string that will be tested against the current function name before the debug output is actually printed.
To illustrate the effects of the TRACE directive, note the difference in output when you run the following two examples:
%CODE_START% CDU DEBUG INFO CDU TRACE *DISK* DEBUG INFO %CODE_END%We have not documented the functions names, by the way;; just use DEBUG without invoking TRACE and peruse the output to get an idea of what's in CDU.
;----------------------------------------------------------------------------- ;CDU can be used interactively. We hadn't written CDU with the intention of making it an interactive program but, in the event, it didn't take much code to make it somewhat easier to use interactively so we decided to leave the code in.
By far the best way to start CDU with a view to using it interactively is to use this:
%CODE_START% CDU . %CODE_END%CDU will prompt you with "CDU>" when it requires input. Type "INFO" and a carriage-return. (We'll assume, now, that you have the sense to place a carriage-return at the end of each line we tell you to type.) CDU should display the same information as it would if you had used "CDU INFO" on the command-line.
Note, by the way, that one directive is very useful when using CDU interactively: the PROBE directive makes CDU re-detect the disk drives. Consider this next dialogue:
%CODE_START% CDU> info HD0: 1547 MB HD1: 6173 MB FD0: 1440 KB CDU> del hd0 CDU> info HD1: 6173 MB FD0: 1440 KB CDU> add hd0 CDU> info HD0: ? HD1: 6173 MB FD0: 1440 KB %CODE_END%Note that although CDU had "deleted" (that is, hidden) drive HD0 after we had asked it to, when the ADD was done, the following INFO obviously didn't display the correct information again. This was because when the drive was added back into the drive list, the properties for that drive were added back in their default state. However, we can overcome that like this:
%CODE_START% CDU> info HD0: ? HD1: 6173 MB FD0: 1440 KB CDU> probe CDU> info HD0: 1547 MB HD1: 6173 MB FD0: 1440 KB %CODE_END%Using PROBE forces CDU to take another look at the set of existing disk drives.
Try this - the typo is deliberate, by the way:
%CODE_START% CDU> dunp disk fd0 ERROR: Command name expected %CODE_END%One of the differences between interactive CDU and command-line CDU is that the former will not abort when an error is detected. Hence, in the above example, the misspelt DUMP invocation does not result in program termination.
So, given that CDU won't exit when an error is detected, how do we terminate an interactive CDU session? We use the EXIT word:
%CODE_START% CDU> exit [WIN95] C:\Z\z> %CODE_END%It is worth re-stating that CDU was not primarily intended as an interactive program. Where there is any conflict between the requirements of the two modes, we will lean towards favouring non-interactive use.
For further details, see the INTERACTIVE switch entry in the reference manual.
;----------------------------------------------------------------------------- ;You can define "macros" much in the same way as in many programming languages. For example:
%CODE_START% DEFINE FILENAME "C:\WORK\C\TC\CDU\Z.IMG" %CODE_END%After this macro definition, you could use something like:
%CODE_START% COPY DISK HD0 TO FILE %%FILENAME%% %CODE_END%Note that all text processed by CDU is scanned for the macro expansion characters. (These are the percent signs in the above example.) Text between these characters are tested for environment variable names and CDU text macro names in that order. If either is found, then the corresponding text is substituted. Hence, one can try this:
%CODE_START% CDU SAY "The system path is '%%%%PROMPT%%%%'" %CODE_END%This will display your system's PROMPT environment variable. However, there are one or two caveats that apply when using macro expansion and the SAY directive. For more information, take a look at the section on the VCHAR word in the reference manual.
;----------------------------------------------------------------------------- ;Currently, CDU uses two "track" buffers for handling the data stream and, currently, these are allocated dynamically. However, this area is, at present, giving trouble possibly concerned with segment limitations and the like.
One can, using the BUFSIZ keyword, alter the size of the the buffers allocated. These buffers, by the way, are only allocated when a command (as opposed to a directive) is executed. In fact, it is done each time the disk identification is done.
Note that the buffer sizes are, also "at present", specified in multiples of the IBM standard sector size - viz 512 bytes. Thus, if you wanted CDU to allocate a couple of two KB (2048 byte) buffers, use:
%CODE_START% BUFSIZ 4 %CODE_END%By the way, when errors are detected, CDU may complain that the BUFSIZ parameter is greater than one. The problem with any BUFSIZ greater than one is that the reported location of the error really refers to the first sector of the block that contains the error. Hence, to fully locate a bad sector, BUFSIZ must be set to one. This is exactly what is done by the BADSCAN command.
;----------------------------------------------------------------------------- ;If one wants to do a "read check" a data stream, there's more than one way of doing this. The first way is to use the operating system's "byte bucket". Under MSdos, and derivatives, this is the file called "NUL". Hence, this would read-test the first hard drive:
%CODE_START% CDU CONFIRM COPY DISK HD0 TO FILE NUL %CODE_END%Alternatively, one could do a SEARCH for a string that is unlikely to be found:
%CODE_START% CDU CONFIRM SEARCH DISK HD0 FOR GHGHGHJGHJKGHGHJG %CODE_END%One could also invoke the DUMP word after having left DETAIL in its default OFF state:
%CODE_START% CDU CONFIRM DUMP DISK HD0 %CODE_END%Finally, the "official" way is to use the BADSCAN word. This is similar to the DUMP word except that:
It doesn't allow you to display a sector's contents as it is read.
It will not stop when it detects a read error.
There is no "comfort" displayed at all because:
The BUFSIZ is automatically set to "one" so that sector numbers are reported properly.
For example:
%CODE_START% CDU CONFIRM BADSCAN DISK HD0 %CODE_END%Note that using BADSCAN on a hard disk is, perhaps, three times slower than using DUMP because of the automatic alteration of the BUFSIZ parameter. Hence, if you merely want to know if the stream is readable, use the DUMP word. If you want to know how many sectors are unreadable or you want an accurate list of their sector numbers, use BADSCAN.
Perhaps the fastest way would be to use a combination of techniques: use a plain old DUMP and, if it failed, use the reported sector number in the OFFSET clause of a BADSCAN command. However, doing this means that you'd have to "babysit" your computer because you wouldn't know when the first read failure (if any) is going to occur.
The most convenient, assuming time isn't pressing, would be to use a combination of the BADSCAN command with a REMIND clause and redirect the output to a file:
%CODE_START% CDU CONFIRM NAG 5 BADSCAN DISK HD0 > BADSCAN.TXT %CODE_END%Since this will, at program termination, provide you with a complete list of bad sectors and it does not need babysitting, while it's running, you can have a cup of tea or just get on with something else.
;----------------------------------------------------------------------------- ; #close * ;=========================================================================== #say Generating Reference HTML file. #send REFhtml ;----------------------------------------------------------------------------- ;CDU has a simple strategy when dealing with command-line parameters: whatever can appear on the command-line can be used in a script file and vice-versa. Hence, unlike with most of the other ChAoS Utilities, there's no "options" section.
No script grammar is given here - CDU has quite an extensive HELP page and that is considered the definitive reference for CDU's grammar.
;----------------------------------------------------------------------------- ;When CDU is parsing parameters, it will normally ignore white space and assume that "tokens" are delimited by spaces. Sometimes, of course, one wants to include a space within a parameter. So, how do we do this?
CDU handles this in a similar manner to the MSdos command-line processor. Namely, one puts double-quotes around the entire parameter.
For example, let's say that we want to present the following text as the message of a SAY word:
%CODE_START% Mary had a little lamb %CODE_END%This won't work because CDU will assume that the desired message is the word "Mary" and it will try to look up the word "had" as a directive or command word:
%CODE_START% SAY Mary had a little lamb %CODE_END%This is how it should be done:
%CODE_START% SAY "Mary had a little lamb" %CODE_END%Note that any parameter can have double-quotes - superfluous double-quotes are ignored. For instance, the example command for the INCLUDE word has double-quotes around the file name operand even though the file's name does not contain any spaces. This doesn't matter since CDU will just discard them.
Note that this area contains one of the few differences between the way that command-line parameters are parsed and the way that parameters read from a response file are handled: in the latter it's our code that strips the double-quotes from parameters whereas in the former it's Microsoft's code.
;----------------------------------------------------------------------------- ;CDU will accept a common number format wherever a number is required. One can enter numbers in one of six ways. Only the first (viz, "character" format) is case sensitive:
One can enter a character surrounded by single quotes. This is convenient except in one situation: if that character is a space character, then the whole construct has to be surrounded by double quotes as well. In this instance, it's probably easy to use one of the other modes. (For example, "0x20".)
This format will be familiar to "C" programmers;; the number is expressed in hexadecimal and preceded by the string "0X". For example, an exclamation mark (ASCII decimal 33) can be represented as "0x21".
The number is written in binary and followed by a letter "B". Using this mode, our exclamation mark would be expressed as "100001b".
The number is written in the normal way with no extra strings attached. In decimal, the exclamation character is "33".
Express the number in hexadecimal followed by an "H". The exclamation mark becomes "21h" in this mode.
For really ancient programmers, we provide the octal mode: numbers are expressed as a string of octal digits followed by a letter "O". The exclamation mark thus becomes "41o".
If you want to embed comments in CDU scripts, use the semi-colon character (';;'). The text from the semi-colon until the end of the current line is ignored by the program. For example:
%CODE_START% IDENTIFY TRUE ;; Auto-identify IDE drives. %CODE_END%If you want a semi-colon character to be treated as any other character, you can "escape" it by using two semi-colons next to each other. CDU will treated this pair of characters as a single semi-colon character:
%CODE_START% SAY "This message contains a semi-colon (';;;;') character\n" %CODE_END%The above will result in this text from CDU:
%CODE_START% CDU V0.6.038 Mar 02 2001 This message contains a semi-colon (';;') character %CODE_END% ;----------------------------------------------------------------------------- ;CDU has limited macro capabilities. Any text between a pair of macro characters - a percent sign ('%%') by default - will be "expanded". After this expansion has been done, the process of checking for a macro character is resumed, starting at the first character of the expanded text.
In a similar manner to the comment character, the macro expansion character can be "escaped" by using two percent signs next to each other. For example:
%CODE_START% define AMACRO "Some macro text" say "The *expanded* macro text is '%%AMACRO%%'.\n" say "The *escaped* macro name is '%%%%AMACRO%%%%'.\n" %CODE_END%This will produce output similar to:
%CODE_START% CDU V0.6.038 Mar 02 2001 The *expanded* macro text is 'Some macro text'. The *escaped* macro name is '%%AMACRO%%'. %CODE_END%The text between the macro characters is checked for a matching name to one of two items in this order:
If a match is found, then the text substitution is done as detailed above.
;----------------------------------------------------------------------------- ;It is fairly common for command-line driven programs to allow the user to nominate a "response file". In essence, this allows the user to put into a file whatever they would've liked to have been able to place on the command-line. CDU allows this convention and, indeed, functionally, it's much the same as using the file INCLUDE facility.
The response file syntax also has a fairly common "standard" among command-line driven programs and CDU conforms to this:
%CODE_START% %<%progname%>% %<%params%>% @%<%filename%>% %<%moreparams%>% %CODE_END%Hence, the following two examples will both run the file BATCH.CDU. Both are perfectly valid on the command-line and in a response file (that is, a script file) itself. For preference, we prefer to use the INCLUDE method in script files and the more compact '@' form on the command-line:
%CODE_START% CDU @BATCH ;; We normally use this on the command-line. CDU INCLUDE BATCH ;; This seems more lucid for script files. %CODE_END%Note that CDU will append a default extension of .CDU if the extension-free file can't be found. Also, if you just supply a non-qualified file name, it'll look for the file in the current directory and then in the program directory. These rules apply to all script file includes and, hence, you can make CDU scripts that are not fully qualified and place them in the CDU program directory - no matter what the current directory is set to, they will run fine.
In fact, one could have CDU include some scripts from the current directory and have some of them load from the program directory. Hence, given a line like this:
%CODE_START% INCLUDE "X" %CODE_END%If the file exists in the current (that is, "local") directory, it'll be found and run. If not, then CDU will look in its program directory. Hence, a local copy of X.CDU would "override" any copy in the place from which CDU was executed.
;----------------------------------------------------------------------------- ;Note that each word is followed by an example of its use. To access the definitive grammar reference, invoke the CDU HELP page.
CDU will quite often accept synonyms for words. For example, in the current version of CDU, the following are all equivalent: OFF, DISABLE, INHIBIT, FALSE, NO. Thus, in the following word list documentation, you will find an entry for OFF but no entry for DISABLE. We have not bothered to list all possible synonyms since, as we have already said, the help pages are the definitive reference.
Adds another disk drive to the list "seen" by CDU. This can be used to add drives that CDU, for whatever reason, hasn't been able to interrogate itself. See the associated word, DELETE.
#redef WrdName ALL #redef WrdExamp DELETE ALL #includ WrdItemSrcThis word is used when one wants to refer to all disk drives. Thus, one can easily delete all disk drives seen by CDU by using the above example.
#redef WrdName ARCHIVE #redef WrdExamp COPY DISK BLACKDOT TO ARCHIVE X:\BLACKDOT.GZ #includ WrdItemSrcAn archive is one of the stream types that CDU recognises. At present, only one compression system is handled: the GZIP system. A CDU archive always consists of a single file that has been GZIPped.
#redef WrdName AUTOEND #redef WrdExamp AUTOEND ON #includ WrdItemSrcOn IBM clones, some APIs don't always seem to return the true end-of-disk information when one retrieves the disk drive parameter block. Hence, it is sometimes possible to read past the "end" of the disk. If one is using CDU to backup a drive, one may want to make sure that the whole drive is read and, therefore, CDU has a mechanism that will detect the end of the drive by finding out the address of the last readable sector. Use of this mechanism is controlled by the AUTOEND switch.
#redef WrdName BADSCAN #redef WrdExamp BADSCAN DISK HD0 #includ WrdItemSrcThere are several ways of performing a "bad scan" operation but the "official" way is to use the BADSCAN command. The BADSCAN command will not stop when it detects an error so that it is relatively easy to scan an entire disk for bad sectors. The other important point to bare in mind is that BADSCAN temporarily sets the BUFSIZ to one.
#redef WrdName BEEP #redef WrdExamp BEEP ON_ERROR #includ WrdItemSrcBy default, CDU will give a "happy" beep when a "real" command executes successfully and a "sad" beep when a command fails. This behaviour can be altered by use of this word.
#redef WrdName BUFSIZ #redef WrdExamp BUFSIZ 1 #includ WrdItemSrcCurrently, the two "track" buffers that CDU requires are allocated dynamically. However, this area is, at present, giving trouble possibly concerned with segment limitations and the like.
One can, using the BUFSIZ keyword, alter the size of the the buffers allocated. These buffers, by the way, are only allocated when a command (as opposed to a directive) is executed. In fact, this "delayed disk system initialisation" is exactly what allows one to, for example, enable diagnostics before the disks are "detected".
Note that the buffer sizes are, also "at present", specified in multiples of the IBM standard sector size - viz 512 bytes. Thus, if you wanted two KB (2048 byte) buffers, you would have to say "BUFSIZ 4".
By the way, when errors are detected, CDU may complain that the BUFSIZ parameter is greater than one. The problem with any BUFSIZ greater than one is that the reported location of the error really refers to the first sector of the block that contains the error. Hence, to fully locate a bad sector, BUFSIZ must be set to one. This is exactly what is done by the BADSCAN command.
#redef WrdName BYTE #redef WrdExamp COPY BYTE 0XEE TO VOLUME Z: #includ WrdItemSrcYou use the BYTE word to specify a byte stream object. The word must be followed by a number that represents the byte stream's value.
Note that sector ranges are ignored when applied to byte streams.
Also, note that byte streams are usually employed as stream sources. When used as a stream target, a byte stream behaves as a "bit bucket" and all output to that stream is discarded. (This is, therefore, one of the "unofficial" ways of doing a sector bad scan - you can just use a COPY command specifying a byte stream as the destination.)
#redef WrdName CLS #redef WrdExamp CLS #includ WrdItemSrcYou can clear the screen by using this word. Note that CDU uses a "belt and bracers" approach to clearing the screen - a "proper" clear-screen operation is done or following the emission of a large number of carriage-return / line-feed pairs.
#redef WrdName COMPARE #redef WrdExamp COMPARE DISK FD0 WITH FILE FLOPPY.IMG #includ WrdItemSrcThis command allows you two compare two source streams. The command will compare the two streams until a difference is found, the user interrupts the process or an I/O error is detected. Note that if one stream ends prematurely, this is classed as a "difference".
#redef WrdName CONFIRM #redef WrdExamp CONFIRM DISABLE #includ WrdItemSrcSometimes, especially when using a script file where the commands are known to be correct, one would like to inhibit the majority of the "Is this OK?" questions. This is what the CONFIRM switch controls.
Please note that disabling CONFIRM when writing to a user-specified (for example, via the command-line parameter) disk would probably be considered a rash act...
#redef WrdName COPY #redef WrdExamp COPY DISK FD0 TO FILE FLOPPY.IMG #includ WrdItemSrcThis, perhaps, the most useful of the CDU command set. This is how you copy one stream to another. The COPY command copies the source stream to the target stream until one or other stream terminates, the user interrupts the process or an I/O error is detected.
#redef WrdName DEBUG #redef WrdExamp DEBUG ON #includ WrdItemSrcAs with all non-trivial programs, bugs may well lurk within CDU. Enabling DEBUG will result in lots of output. If you are only interested in a small sub-set of the output, for example just the diagnostics from a single function, one can use the TRACE word to reduce the "clutter" produced.
#redef WrdName DEFINE #redef WrdExamp DEFINE FILENAME "Z.IMG" #includ WrdItemSrcDEFINEs are used in a similar, albeit very limited, manner to the #DEFINE of the "C" pre-processor. Viz, they define a "text macro" that is expanded by using a special syntax.
Note that a text macro can be DEFINEd on the CDU command-line in a batch file and used within an invoked script. Thus, one can get the user to pass "parameters" into the CDU script. (Please note the caveat about using the CONFIRM word under these circumstances.)
#redef WrdName DELAY1 #redef WrdExamp DELAY1 50 #includ WrdItemSrcLike it's sister word, this controls some timing loops in the IDE drive interrogation software. It is documented merely "for completeness". Don't fiddle with it.
#redef WrdName DELAY2 #redef WrdExamp DELAY2 1 #includ WrdItemSrcSee DELAY1,
#redef WrdName DELETE #redef WrdExamp DELETE HD3 #includ WrdItemSrcBy default, CDU will attempt to detect all of the system hard drives via the INT13EX and INT13 APIs. However, this scheme is not fool proof and so we've provided a means of over-riding the normal actions taken. The DELETE word allows you to remove hard drives "seen" by CDU. You can use the ADD word to add drives back into the list.
#redef WrdName DETAIL #redef WrdExamp DETAIL INHIBIT #includ WrdItemSrcThis word increases the amount of detail produced by CDU in certain circumstances. For example, if you enable DETAIL and use the DUMP word, you'll find that the contents of every sector read will be displayed on the screen. Likewise, the only difference between the INFO word and the VINFO word is that the latter has DETAIL enabled automatically.
#redef WrdName DISK #redef WrdExamp COPY DISK HD0 TO DISK HD1 #includ WrdItemSrcThe DISK word is used to specify the disk stream type. Disk streams are accessed via the INT13 or INT13EX APIs. CDU maintains a list of disks and, when the first of a set of certain set of commands is executed, it tries to IDENTIFY them.
Note that the user can dictate the contents of the disk list via the ADD and DELETE words. Also, one can dictate the API used to access each disk via the IFACE word. However, you should only use these words if you really need to control the disk list.
#redef WrdName DOT #redef WrdExamp DOT #includ WrdItemSrcThis word is used to "flush" any outstanding commands when using CDU interactively. See the INTERACTIVE word for more details.
#redef WrdName DUMP #redef WrdExamp DETAIL ON DUMP DISK FD0 RANGE START:+18 #includ WrdItemSrcThe DUMP word merely dumps a sector's data to the standard output. Note that it will not dump the data if DETAIL is disabled. This fact can be used to "read check" a data stream - see also the BADSCAN word.
#redef WrdName END #redef WrdExamp COPY FILE GLOD.IMG TO DISK GLOD RANGE START+100:END-100 #includ WrdItemSrcThe END keyword is used to refer the last sector of a stream's data. (Note that this may, actually, be meaningless;; for example, see the entry relating to BYTE streams.) See the item on sector ranges for details.
#redef WrdName EXIT #redef WrdExamp EXIT #includ WrdItemSrcWhen used interactively, CDU does not exit when errors are detected. This allows typos to go unpunished and for failed commands to be retried. However, in this case, there is only one way to gracefully terminate the program and that is to use the EXIT word.
#redef WrdName FILE #redef WrdExamp DUMP FILE FLOPPY.IMG #includ WrdItemSrcThis is one of the most basic stream types. The word must be followed by a file name that is acceptable to the operating system.
Note that there are limitations when using large files under MSdos. Therefore, please read the entry on file SIZING if you intended to use large files.
#redef WrdName FLUSH #redef WrdExamp FLUSH ENABLE #includ WrdItemSrcThis word causes CDU to automatically "flush" a pending command when an end-of-line is detected. This would only normally we required when using CDU interactively.
#redef WrdName FOR #redef WrdExamp SEARCH FOR "\X55\XAA" IN DISK HD0 :+1000 #includ WrdItemSrcThis word is used to introduce the target text in a SEARCH command.
#redef WrdName FWRITE #redef WrdExamp FWRITE ON #includ WrdItemSrcCDU will only write to floppy disk drives when this switch is enabled. Please see the related WRITE entry.
#redef WrdName HELP #redef WrdExamp HELP #includ WrdItemSrcUse this word to invoke the CDU help page. This page is quite extensive and includes a full CDU script language grammar. (This is why no grammar is given in this document - you should consider the CDU help page as the definitive source.)
#redef WrdName HWRITE #redef WrdExamp HWRITE ENABLE #includ WrdItemSrcCDU will only write to hard disk drives when this switch is enabled. Please see the related WRITE entry.
#redef WrdName I13 #redef WrdExamp INTERFACE HD0 INT13 #includ WrdItemSrcThis is used to specify a required interface when one wants to force CDU to access a particular drive using the standard INT13 method. (See the entry for the IFACE word.)
#redef WrdName I13EX #redef WrdExamp IFACE ALL INT13EX #includ WrdItemSrcThis is used to specify a required interface when one wants to force CDU to access a particular drive using the extended INT13 method. (See the entry for the IFACE word.)
#redef WrdName IDENTIFY #redef WrdExamp IDENTIFY TRUE #includ WrdItemSrcCDU relies on one of two disk interfaces being provided by the BIOS for accessing DISK streams. Namely, the INT13 and INT13EX (extended) API calls. It does attempt to identify which of these interfaces are available but, as with so many IBM PC APIs, they ain't perfect.
In particular, CDU has one trick up its sleeve that we've yet to see in commercial backups program - it can identify disk drives by their unique drive model and serial number strings. (Here, we are not talking about the MSdog volume serial numbers.)
The bad news is that the retrieval of these strings was only built into the latest versions of the INT13EX API and, as yet, we've not actually seen them in the real world. Therefore, CDU attempts to identify the drives by talking directly to the IDE hard drives itself. It goes without saying that this is not a "nice" thing to do but, in the absence of anything better, this is the way that we do things.
As of CDU version 0.6.025, the identification facility has been switched off by default. Since it's not fully reliable, it seems prudent to make the users have to enable it explicitly if they want to use this facility. We toyed with the idea of having the NAME directive enable it automagically but decided against this since one can always add an IDENTIFY directive to one's NAMES.CDU or CDU.CDU files. If we find a machine with the version three INT13 extended API, we may well make this switch enabled by default if the user has a version three API.
#redef WrdName IFACE #redef WrdExamp IFACE HD0 INT13EX #includ WrdItemSrcAs explained in the entry for IDENTIFY word, CDU attempts to identify your drives and interfaces available. If, for whatever reason, it gets it wrong, you would use this word to force CDU to use the interface that you want.
See the entries for the I13 and I13EX words.
#redef WrdName INCLUDE #redef WrdExamp INCLUDE "NAMES" #includ WrdItemSrcIf you want to include one CDU script source in another, use this word. You can nest these "response" files several deep.
CDU will append a default extension of .CDU if the extension-free file can't be found. Also, if you just supply a non-qualified file name, it'll look for the file in the current directory and then in the program directory. (The latter is the place where the executable resides.)
#redef WrdName INFO #redef WrdExamp INFO #includ WrdItemSrcThis word will make CDU dump the current disk drive list to the console. This data will include the current drive serial numbers (if identification has taken place) and various other data concerning the interface being used, drive size and so on.
If DETAIL is enabled, considerably more data is produced.
#redef WrdName INTERACTIVE #redef WrdExamp INTERACTIVE ON #includ WrdItemSrcYou can use CDU interactively, after a fashion, by using something along the lines of:
%CODE_START% CDU @CON %CODE_END%or
%CODE_START% CDU INCLUDE CON %CODE_END%To get the best behaviour from CDU, tell it that it's being used interactively:
%CODE_START% INTERACTIVE TRUE %CODE_END%This will switch interactive behaviour on. Note that when used interactively, CDU displays a small prompt before accepting each line of input.
Normally, CDU only obeys the command currently being constructed when one of two things happens: either the end of the input stream is detected or the first word of the next command forces the last command to execute. This, of course, takes place transparently unless one is using the program interactively. Usually, in such circumstances, one would want an end-of-line to "flush" the current command so that it executes. That's exactly what the FLUSH switch is for:
%CODE_START% FLUSH ENABLE %CODE_END%You may be relieved to know that the DOT word does both of these and, in addition, will open the console standard input stream if it's not already open. Hence, the best way to invoke CDU interactively is merely to type:
%CODE_START% CDU . %CODE_END%Please note the the flushing enabled by the FLUSH word is a bit crude - what CDU actually does is to append a DOT word onto the end of every line typed if FLUSH and INTERACTIVE are enabled. This was a simple kludge that made interactive use much easier at the expense of only a couple of lines of code.
When CDU is used interactively, you must use the EXIT to terminate CDU gracefully.
#redef WrdName NAME #redef WrdExamp NAME FRED ACME:12345 #includ WrdItemSrc
In order to associate a drive model and serial number string, use the NAME directive. For example, if you have a drive which produces "ACME" as the model string and "12345" as the serial number and you want to call it "FRED", invoke the NAME directive as in the above example.
Note that all non-printable characters are filtered out of the string and, when actually using the model and serial number strings, CDU places a colon between them.
#redef WrdName OFF #redef WrdExamp CONFIRM OFF #includ WrdItemSrcThis is the "negative" key word used to turn switches off.
#redef WrdName ON #redef WrdExamp DETAIL ON #includ WrdItemSrcThis is the "positive" key word used to turn switches on.
#redef WrdName ONERROR #redef WrdExamp SOUND ON_ERROR #includ WrdItemSrcAs indicated in the entry for the BEEP word, CDU's behaviour can be altered with reference to the sounds that it makes at the end of a process.
Normally, it'll always beep and you will either hear an "all OK" beep or a "something's wrong" beep. On occasion, one might like CDU to remain silent unless something goes wrong. Using the ONERROR in conjunction with the BEEP switch will have the desired effect.
#redef WrdName PROBE #redef WrdExamp PROBE #includ WrdItemSrcIf the occasion arises where one needs to force CDU to "probe" for drives more than once, use this word to do that. Usually, this happens when using CDU interactively.
#redef WrdName RANGE #redef WrdExamp DUMP DISK FD0 RANGE START+100:END-100 #includ WrdItemSrcSector ranges are specified by citing a start sector and an end sector which are separated by a colon.
Each of these two sector numbers are made up of two parts, the absolute part and the relative part. The latter is known as the "offset". Just before the command is executed, the offset is added (or subtracted from) the absolute part.
The absolute part can be either a simple number or it can be one of two words that indicate the start or end of the device's stream. So, for example, both "2880" and "END" can be used to refer to the last sector of a standard three inch floppy diskette. In order to refer to the sector before the last sector, one could use "2879" or the more lucid "END-1".
Let's say you want to copy all of a floppy except the first hundred sectors and the last hundred sectors. You could use a range of "100:2781". However, this range can also be written as "START+100:END-100".
If one of the sectors numbers in a range has the absolute part missing, then the relative part is treated as length and the absolute part is copied from the other sector number's absolute part.
For example, the last hundred sectors on our three inch floppy can be specified as:
%CODE_START% "2781:2879" or "END-99:END" or "-100:END" %CODE_END%Note, in that last version, by the way, that "END:-100" won't work because, when the length is applied to the "end of range" sector number, it'll end up being smaller then the "start of range" sector number.
In a similar manner, ranges like "START:+100" can be specified and this, as one might expect, means "the first hundred sectors".
#redef WrdName REMIND #redef WrdExamp REMIND 5 #includ WrdItemSrcWhen a long operation is carried out - a full disk backup, for example - it can be very useful for the program to keep "nagging" us when it's finished. For example, if we use the above example command, we can make a cup of tea and listen out on the intercom for the "nagging" that CDU will do when it has finished.
CDU will only perform this action when it exits. It will nag by repeating the last sound it made. So, for example, if the last thing it did was successful, it'll be a "happy" sound. Otherwise, it'll nag using a "sad" sound. This nagging will be inhibited if CDU is being used interactively.
The value following the keyword, by the way, is the number of seconds between "nags". Using a value of zero will disable this feature.
#redef WrdName RETRIES #redef WrdExamp RETRIES 3 #includ WrdItemSrcWhen using the INT13 (rather than the INT13EX) interface, it is up to the programmer to retry disk operations to see if they will succeed after a previous attempt has failed. (For example, if a floppy drive has shut its motor off, the first couple of disk accesses may fail whereas subsequent attempts may succeed.)
In the past, I've found it useful to be able to vary the number of retries that should be done - too many and one gets impatient waiting for a program to time out on a disk that one knows will fail while too few may cause a disk to be rejected which, although marginal, may actually be readable .
#redef WrdName SAY #redef WrdExamp SAY "THIS IS A USER MESSAGE!" #includ WrdItemSrcThis word allows the script writer to send messages to the user. So, for example, "comfort" text can be sent as the script progresses.
Note that text macro are expanded before the text is displayed. Hence, something like this typed at the MSdos command prompt will work as expected:
%CODE_START% CDU SAY "THE COMMAND PROMPT IS SET TO '%%%%PROMPT%%%%'" %CODE_END%The requirement for extra percent signs is explained in the section on VCHAR. (Note also, that the double-quotes are required when the message text contains a space.)
#redef WrdName SCHAR #redef WrdExamp SCHAR '#' #includ WrdItemSrcThere are complications when using text macros concerned with the character used to indicate that an expansion is required and also with the treatment of special (that is, "escaped") characters within the expanded text. This subject is explained in the section on VCHAR. #redef WrdName SEARCH #redef WrdExamp SEARCH VOLUME E: OFFSET 100000 FOR "EXIF\X00" #includ WrdItemSrc
This word allows you to make CDU search for a particular text pattern in a source stream. If one had intended to search for a JPEG file header on the E: drive, the above example would not work - the text search is case sensitive and the JPEG header text is "Exif" not "EXIF". In addition, the "C"-like escapement system that was used in an attempt to search for a trailing zero character (the "\X00" bit) is also case-sensitive and, hence, one would have had to use this instead:
%CODE_START% SEARCH VOLUME E: OFFSET 100000 FOR "Exif\x00" %CODE_END%By the way, when presenting the text search pattern, if the pattern does not contain a space, then the double-quotes are not necessary;; this, for example, is perfectly acceptable:
%CODE_START% SEARCH DISK HD2 FOR FAT %CODE_END% #redef WrdName SIZING #redef WrdExamp SIZING OFF #includ WrdItemSrcThere appears to be no satisfactory way of obtaining a large file's size under MSdos. This is a problem because, if a "range end" sector number is left as the termination value, CDU will complain that the file is not at its end when a copy or compare is executed.
If the file size (in sectors) could be ascertained, then this value would be treated in a similar manner to a disk's "total sector count" value. MSdos does, however, allow us to get at the size of a file if it's less than 2 GB in length. Currently, CDU defaults to a state whereby it will use this value to calculate last sector number values of any source files opened. Since this could, conceivably, cause problems, there is a switch to disable this "file sizing" operation:
SIZING DISABLEThere is a similar problem with DISKs and VOLUMEs. Please consult the entry for the AUTOEND word.
#redef WrdName SOURCE #redef WrdExamp COPY SOURCE DISK HD0 TARGET DISK HD1 #includ WrdItemSrcThis word is used to introduce a source data stream. Like the TARGET word, it can sometimes be implied and, therefore, be omitted completely from the command.
#redef WrdName START #redef WrdExamp COPY FILE GLOD.IMG TO DISK GLOD RANGE START+100:END-100 #includ WrdItemSrcThe START keyword is used to refer the first sector of a stream's data. (Note that this may, actually, be meaningless;; for example, see the entry relating to BYTE streams.) See the item on sector ranges for details.
#redef WrdName STATUS #redef WrdExamp STATUS #includ WrdItemSrcThis word causes CDU to print a list of the current switches and settings.
#redef WrdName STDKB #redef WrdExamp STDKB TRUE #includ WrdItemSrcBy default, CDU uses direct BIOS calls to find out whether a key has been pressed and to retrieve a keys value. The reason for this is that, under standard ANSI "C", there's no portable way of accessing the keyboard in a manner which doesn't "block" the running process.
This matters not when you are banging away at a standard IBM PC keyboard. However, if you try to run CDU over, say, a TELNET connection where all I/O is re-directed, then the BIOS keyboard handling calls won't work correctly. Hence, we have a word to make CDU use standard keyboard calls:
%CODE_START% STDKB TRUE %CODE_END%Note that there is one important limitation when "standard keyboard" is enabled: you cannot interrupt a running CDU program. (Because, as stated, any invocations of the "get keyboard char" library calls would block the running process.) So, if you enable standard keyboard I/O, make sure what you ask for before answering the "execute this command" question!
Also, you may have to press a carriage-return after you answer any questions whereas, in its default state, CDU doesn't require anything other than a "yes" or "no" character before continuing.
#redef WrdName TARGET #redef WrdExamp COPY SOURCE DISK HD0 TARGET DISK HD1 #includ WrdItemSrcThis word is used to introduce a target data stream. Like the SOURCE word, it can sometimes be implied and, therefore, be omitted completely from the command.
#redef WrdName TRACE #redef WrdExamp TRACE *LOGDRIVES* #includ WrdItemSrcSince the DEBUG directive can produce so much output, we've added a "filter" facility. The output produced by "DEBUG ON" prints, as the first item on each line, the function entry point name. One can use the TRACE directive to dictate which function's output will be listed and which will be ignored. The strings after the TRACE directive is a wild-card string that will be tested against the current function name before the debug output is actually printed.
For example, if you wanted to only see the diagnostics relating to handling of the internal list of disk drives, use this:
%CODE_START% CDU IDENTIFY TRACE *DISKTABLE* DEBUG INFO %CODE_END% #redef WrdName VCHAR #redef WrdExamp VCHAR '!' #includ WrdItemSrcWhile macro name expansion defaults to using the percent character and the special character delimiter is a back-slash, these "special" characters can be changed. Why would you want to do this? Well, consider the following: the percent character isn't a good choice if you want to send the commands to an MSdog command-line interpreter since the percent is also special to that. As a result, in order to have CDU "see" a per cent sign in its parameters, you have to use two percents. Thus, while this won't work:
%CODE_START% CDU DEFINE X XXX SAY %%X%% %CODE_END%This will:
%CODE_START% CDU DEFINE X XXX SAY %%%%X%%%% %CODE_END%Try this:
%CODE_START% CDU SAY %%%%PATH%%%% %CODE_END%You'll get a bit of a surprise because the "special" character processing is carried out after macro name expansion. As a result, using the default characters, the PATH environment variable will have all the back-slashes treated as special character introductions and all the file names will be corrupted.
This is how the special characters are changed from the defaults;; this will change the special character from the default of a back-slash to a "hash":
%CODE_START% SCHAR '#' %CODE_END%Likewise, we can change the macro expansion character from the default percent to a "pling" by using this:
%CODE_START% VCHAR '!' %CODE_END%If we refer back to our above example of printing out the system's PATH environment variable, we could make CDU report the correct PATH by altering SCHAR before printing the message. (Note that the alteration of the VCHAR value isn't actually required but it does serve as an example of the effect of changing VCHAR.)
%CODE_START% CDU VCHAR '!' SCHAR '#' SAY !PATH! %CODE_END%As usual, the normal "number grammar" can be used so these would have been acceptable alternative:
%CODE_START% SCHAR 0X23 ;; An alternative to "SCHAR '#'" VCHAR 0X21 ;; An alternative to "VCHAR '!'" %CODE_END% #redef WrdName VERBOSE #redef WrdExamp VERBOSE ON #includ WrdItemSrcThis word increases the amount of "waffle" produced by CDU. This can sometimes be useful when trying to solve disk-related problems.
#redef WrdName VINFO #redef WrdExamp VINFO #includ WrdItemSrcUsing this word is merely a short cut for a more detailed version of the INFO word. It is exactly equivalent to the following:
%CODE_START% DETAIL ON INFO %CODE_END% #redef WrdName VOLUME #redef WrdExamp COPY FILE DRIVEF.IMG TO VOLUME F: #includ WrdItemSrcThe VOLUME word is used to specify the volume stream type. Volume streams are accessed via the standard INT25 and INT26 APIs.
Note that not all disk types are accessible via this interface. For example, ZIP disks are fine but CD-ROMs may not be.
#redef WrdName WRITE #redef WrdExamp WRITE ENABLE #includ WrdItemSrcIn order to prevent embarrassing little "accidents", the writing to disk and volume streams is disabled by default. Enabling the WRITE switch will permit writing to these streams. As far as volume streams go, that's it. (This means that it's very important, when targeting a volume stream, to make sure you don't, for example, use "C:" when you meant to say "A:"...)
However, CDU can detect the difference between floppy and hard disk streams. In order to prevent even more embarrassing accidents, there are separate switches for writing to floppy disks and hard disks. These are FWRITE and HWRITE respectively.
Older versions of CDU only had the WRITE switch and, to provide backwards compatibility, enabling WRITE will allow writing to both sorts of disk. However, with later versions, one can use the word that corresponds to the type of disk you are targeting.
If, for example, you've made a batch file that provides a target floppy drive name to CDU, then it's probably a good idea to enable writing using FWRITE rather than plain old WRITE:
%CODE_START% FWRITE ENABLE COPY FILE FLOPPY.IMG TO DISK %%DRIVE%% %CODE_END%This way, if the user provides the wrong sort of drive name (for example, "HD0"), then total disaster is averted. If a user did do this, imagine what would've happened had you written the script thus:
%CODE_START% WRITE ENABLE COPY FILE FLOPPY.IMG TO DISK %%DRIVE%% %CODE_END%In this case, the COPY could still continue with, no doubt, catastrophic results.
%CODE_START% %CODE_END% ;----------------------------------------------------------------------------- ;