The programs contained in this archive and described further down in this text were all written from scratch by Jrgen Hoffmann using BORLAND C++ Version 3.1 during the first weeks of the year 2010. They are licensed under the EUPL V.1.1 and offered to the public free of charge. The english text of this european public licence is included in this archive. Other, equally valid versions, together with some useful explanations for non-lawers are available in all official languages of the european union and can be downloaded from here: http://ec.europa.eu/idabc/eupl. As the programs are free, the author doesn't accept any responsibi- lity beyond what can reasonably be expected from any other kind of gift as well. Even though the programs were thoroughly tested it cannot be excluded, that undiscoverd errors still arise. Should you find such a one, feel free to inform the author about it using the e-mail address shown at the end of this document. ASKECHO (ASK and ECHO) is a program that simply writes its arguments to stdout. As such it resembles the built-in command ECHO. If one or more of these argu- ments begin with a special lead-in character ('+' by default) then this argument will not be written to stdout, rather it will be sent to stderr as a user prompt and the user's response will replace the respective argument in the original text. The correct syntax is: askecho [/N] [/S] [/Q] [ text ... ] + [ text ... ] with /N: no implicit spaces /S: use instead of '+' to mark /Q: use as quoting char, a word following the quoting character will be enclosed in double quotes "..." The behaviour of the program can be modified by three different com- mand line switches. By default, the arguments are separated by one space when send to stdout. By setting the /N switch ASKECHO can be told to append them without any space inbetween. By means of the /S switch it is possible to re-define the lead-in character to some other value if the default "+" is in conflict with some other part of the text. The /Q switch allows to define a character which, as an argument of its own, causes the next following argument to be enclosed in double quotes. Regular double quotes denote a series of words as a single one and are automatically removed. Therefore they must be expressed in some other way, should they appear literally. example: ASKECHO /Qq The answer is q "+Your response please: " Will first prompt the user with the text: "Your response please: " As soon as the response is completed by hitting the key, the text >> The answer is " ... " << will be written to stdout and ' ... ' will be replaced by the user's answer. This is most useful if stdout is re-directed into a file, like this: ASKECHO /N "set RESPONSE=" "+Driver name? " > setvar.bat call setvar This sequence of commands would ask the user to enter a driver name and then store the answer in the environment variable RESPONSE. TIMESTMP (TIMESTaMP) is a program that simply writes its arguments to stdout. As such it resembles the built-in command ECHO. If one or more of these argu- ments begin with a special lead-in character ('+' by default) then this argument will not be copied but interpreted in a special way. Users who are familiar with UNIX, might recognize that this program is inspired by, but by far not identical with, the UNIX "date" com- mand. The primary motivation to write this program was to insert freely configurable timestamps into logfiles. It turned out however, that it can be used in many situations which the standard ECHO can't handle. The correct syntax is: timestmp [/N] [/O] [/S] [ text ... ] + [ text ... ] with /N: no implicit spaces /O: open end (don't append a newline) /S: use instead of '+' to mark and year: 'J','j': '2000' .. '2999' year: 'Y': '00' .. '99' -- 'y': '0' .. '99' month: 'M': '01' .. '12' -- 'm': '1' .. '12' day: 'D': '01' .. '31' -- 'd': '1' .. '31' hour: 'H': '00' .. '23' -- 'h': '0' .. '23' minute: 'I': '00' .. '59' -- 'i': '0' .. '59' second: 'S': '00' .. '59' -- 's': '0' .. '59' 1/100: 'U': '00' .. '99' -- 'u': '0' .. '99' 'q': a single quote (') -- 'Q': a double quote (") 'N': name of the month -- needs set TIMESTMP_M=... 'n': name of day of week -- needs set TIMESTMP_W=... e.g. set TIMESTMP_W=:Sun:Mon:Tue:Wed:Thu:Fri:Sat Each occurrence of one of the characters: "JjYyMmDdHhIiSsUuQqNn" in an argument starting with the lead-in character will be replaced by a number which is related to the current system date or time. Any other characters will by copied unchanged. The precize mapping of characters to data items can be seen in the above table. In many cases an upper case letter means that the number will always be displayed with two digits, while the corresponding lower case will result in a one or two digit number, depending on the value. One exception to this rule is the "J" which alway displays the year with four digits disregarding its case. Another exception is the "q" which, as lower case is replaced by an apostrophe, while the upper case "Q" is turned into a double quote. A special case is the letter "N". As upper case it is replaced by the name of the current month (January, ...) while as lower case it will be transformed into the name of the day of week (Sunday, ...). These names however, unlike numbers, depend very much on the local language and culture. Therefore TIMESTMP allows (and requires) you to define, how they should be displayed. This is achieved by two en- vironment variables: TIMESTMP_M defines an array of names of months (January .. December) while TIMESTMP_W does the same for the day of the week (Sunday .. Saturday). The correct syntax for these two variables is: set TIMESTMP_x= ... Where "x" stands for "M" or "W" and is the limiting character. The colon ":" is a good choice for this, but any other character which doesn't appear within the names can be used as well. This way it is not only possible to use any language (as far as the charac- ter set supports it) but also to freely define the style (full name, abbreviated to three or two characters, upper, lower, mixed case). example: set TIMESTMP_W=:Sun:Mon:Tue:Wed:Thu:Fri:Sat TIMESTMP Today is +n +d.m.y it is +H:I will result in somthing like: Today is Tue 3.5.2009 it is 19:07 If the "N" or "n" characters are not used, then the environment variables don't need to be set. If they are used without prior set- ting of the variables, then roman numbers ("I".."VII".."XII") will be shown instead by default. Apart from its arguments TIMESTMP can take three different command line switches, which modify its behaviour. By default, the argu- ments are separated by one space when send to stdout. By setting the /N switch TIMESTMP can be told to append them without any space inbetween. The /O switch causes TIMESTMP not to append a newline to the end of its output. This is most useful when re-directing the output into a file, as another command can append more text to the same line. By means of the /S switch it is possible to re-define the lead-in character to some other value if the default "+" is in conflict with some other part of the text. RPN (Reverse Polish Notation) is a program to carry out numeric calculations. Although it can be used interactively on the command line, its primary purpose is to add numeric capabilities, such as loop counters to batch procedures. The correct syntax is: rpn [ options ] valid options are: /S make set command for environment variable /E store directly in environment (tricky !!!) /F output format, must be valid "C" format in batch files use "%%" for "%" like /F%%4ld /D tolerate as decimal separator /I ignore inside numbers /R?[num] return code 1 if result compared to [num] is ?: + greater += greater or equal = equal - less than -= less or equal # not equal e.g. /R+5 if [num] is not given, 0 is assumed expression is in reverse polish notation (RPN) e.g. 12 3 + 5 * numbers can be 23 +5 -97 (dec) 0377 (oct) or 0XF9 (hex) operators are + add - sub * mul / div \ mod & and ! or { shl } shr ++ inc : dup $ swap ~ neg _ inv -- dec Expressions must be given in reverse polish notation which might be known from the formerly famous HP-calculators. Numbers can be ex- pressed in decimal, octal or hexadecimal notation and several ope- rations can be performed on them, according to the table above. The internal stack can hold a maximum of eight values. They are put onto the stack in the order they appear in the expression from left to right. Certain operators '++' (increment), '--' (decrement), '~' (change sign) and '_' (negate bitwise) just modify the value on top of the stack. Others '+' (add), '-' (subtract), '*' (multiply), '/' (integer divide), '\' (division remainder/modulo), '&' (bitwise and), '!' (bitwise or), '{' (shift left by n places) and '}' (shift right by n places) modify the next-to-top value on the stack by the value on top of the stack, remove both values from it and replace them by the result, in such a way that there will be one value less on the stack when the operation completed. The operator '$' (swap) simply exchanges the next-to-top value with the topmost one while the operator ':' (dup) will duplicate the value on top of the stack by pushing a second copy of it onto the stack, resulting in a stack that holds one more value afterwards. By default the result, which is simply the number that happens to be on top of the stack when the expression is completely evaluated, is immediately written to stdout but it can also be stored into an environment variable by two different methods. In addition it is possible to test the result against a given value and perform a branch according to the outcome of this test. Various command line switches can modify the behaviour of RPN. The /E defines a variable into which RPN should store the result. As this requires the modification of the environment of RPNs parent process, this may not be possible in all environments, especially not in ones that only emulate (MS-)DOS. Therefore the alternative switch /S exists. It generates a proper set command and writes it to stdout. Re-directing this output into a (secondary) batch file and then calling that batch file from the primary one, will yield the same result as writing directly into the variable, though it is certainly less elegant, but it uses only fully documented features and should work in every environment. In order to understand the meaning of the /D and /I swit- ches, one must know that RPN regards any character, that is neither an operator nor part of a number, as whitespace. As a consequence of that, an expression like 10.908.070,65 would be four different numbers for RPN. The "/I." switch declares the dot as integral part of the number, which RPN should sipmly ignore, while a "/D," tells it to regard the digits after the comma as legal part of the number, though RPN would simply ignore this fractional part, as it stricly calculates with 32 bit integers. Unfortunately the way to express this number is not uniform all over the world. In some countries the same number would be written as 10,908,070.65 or sometimes even as 10'908'070.65. Therefore the two switches allow to tell RPN which convention applies. The /F switch allows to define the output format of the result. By default RPN will just output a simple decimal value. If is just a text, not containing any '%' sign, e.g. "/FThe result is " then RPN will silently append a '%ld' to it and return something like "The result is 1234". If contains a '%' sign, then RPN expects this to be a valid "C"-format string, assumes that the user knows what he/she is doing and neither performs any more checks nor modifies it in any way, but simply uses it to output the number. An additional inconvenience results from the fact that inside batch files, the DOS-shell command.com, interpretes the '%' sign as hint to expand an environment variable. Therefore, when used in such a context, any '%' sign that should be taken literally must be dupli- cated like e.g. /F0X%%08lX. This example would cause RPN to format the result as eight-digit hexadecimal number with a '0X' prefix. As the "C" format conventions already require a literal '%' sign to be expressed as '%%', it would take even four of them, when used in a batch file, like e.g. /F%%ld%%%%. The /R?[num] switch controls the result codes which RPN will return to DOS. By default it will return 0 if all went well and 2 on any error e.g. division by zero. In addition it will write an error message to stderr. If the /R switch is set, then RPN will perform some test on the result (the value that happens to be on the top of the stack when the expression is evaluated completely). If that test evaluates as true than RPN will return a result code of 1 back to DOS and a 0 otherwise. In a batch file this result code can be used to cause a branch by an "IF ERRORLEVEL 1 GOTO..." instruction if the condition is met. The kind of test which is actually perfor- med is determined by the one or two characters imediately following the /F according to the table above. If [num] is given, the result is compared with that number otherwise it compared with zero. example: Try the following batch file under true (MS-)DOS: SET COUNT=0 :LOOP ECHO %COUNT% RPN /ECOUNT /R-10 %COUNT% ++ IF ERRORLEVEL 1 GOTO LOOP If the /E switch doesn't work, try this version instead: ECHO SET COUNT=0 > \temp\setvar.bat :LOOP IF EXIST \temp\setvar.bat CALL \temp\setvar.bat ECHO %COUNT% RPN /SCOUNT /R-10 %COUNT% ++ > \temp\setvar.bat IF ERRORLEVEL 1 GOTO LOOP Version history: Version 1.1 added the ability to resolve environ- ment variables by rpn directly. Most versions of command.com (the default command processor) evaluate environment variables only when used inside batch procedures. As RPN now evaluates these variables itself, expressions like "RPN %num% ++" can now also be used on the command line directly. At least one blank must be found before the leading and after the trailing "%" sign to allow RPN to recognize such a variable. PIPESET (PIPE via stdin and SET environment variable) is a program which, as its name already suggests, can be used to set environment variables. Unlike its built-in cousin SET it does not take its data from the command line rather it reads from stdin. The correct syntax is: | pipeset [ options ] [ target2 ... ] or: pipeset [ options ] [ target2 ... ] < valid options are: /S safe mode (also useful for testing) /L skip lines /L$ skip all but last /M skip matches /M$ last match /F define fixed fields e.g. /F3.5.2 or /F-3.5.2 /C define set of separator characters /W define set of whitespace characters A-Z range \XX hex ^ complement where target is [variablename][=[<*>pattern]] and <*> is = equal { not ( begining ? containing # not equal } not ) ending ! not containing In its most basic form, PIPESET simply reads one line of input and stores it in an environment variable whichs name is given as an ar- gument. It is however also possible to give more than one name. In this case the input line will be broken into pieces and each such piece will be stored in a variable of its own. Should there be more pieces than names, then the last variable will take all remaining ones. If there are less, then some variables will be left unassig- ned. Users who are familiar with the UNIX operating system may re- cognize a certain similarity to the 'read' command of that system. The way how the data is broken into pieces is widely configurable. Furthermore it can be specified, that a line has to fullfill cer- tain criteria to be considered for storing. The first such criterion is the /L command line switch. It de- fines a number of lines that will simply be skipped before anything else is done. In the special case of /L$ every line but the last one will be skipped, in other words only the last line will be pro- cessed. In addition it is possible to require certain fields of the data to fullfill certain criteria. If they are not met, then the whole line is discarted and the next one is checked until a line is found that is acceptable or the end of data is reached. If no line meets the criteria, nothing ist stored. The general form is PIPESET target1 target2 ... targetN where tar- getX in its simplest form is just a name of an environment variable which should take the content of the respective field of the input line. If this name is followed by an equal sign, another qualifying character and a textpattern, than the respective field has to meet a criterion which is defined by the qualifying character and the textpattern. These criteria can be: field has to be equal "=" to the pattern, not equal "#" to the pattern, has to begin "(" or end ")" with pat- tern, must not begin "{" or end "}", has to contain "?" pattern or must not contain "!" it. More than one field may be qualified by such a criterion in which case all of them must meet in order to accept the data. If a target begins with an equal sign, then no name is assigned to the respective field meaning that its data should not be stored but the criterion must be met anyway. If a target consists of only an equal sign, the respective field is to- tally ignored. By default PIPESET will search the input, line by line, until it finds the first line that meets the search criteria. It then stores the data into the targets und terminates. The /M command line switch causes PIPESET to search for more lines that meet the crite- ria. More precisely, it causes PIPESET to ignore the first matches and look for the +1st line that meets the criteria. If only (or even less) lines match, then PIPESET will return no- thing. The special case /M$ causes PIPESET to scan the whole input and to only consider the last matching line. If no matching crite- ria are assigned to any of the targets, then /M operates exactly like /L (just a little bit slower). The way how a line of input is split into fields is configurable as well. By default it is split into "words", series of non-blank cha- racters that are separated from each other by series of white-space characters, where the blank and any charcter whichs ASCII value is below 0X20 are considered as white-space. This default can be overriden by the /W switch, where is a characterstring which defines the set of characters that should be regarded as white-space. Note however, that character values be- low 0X20 are always part of the set of white-space or separator characters, no matter what command line switch has been set. The characters can also be expressed as hexadecimal values in the form \XX. Furthermore whole ranges of characters can be given as X-x. If the '-' is at the beginning or the end of or if the ASCII va- lue of 'X' is not lower than that of 'x', then the '-' is taken as literal minus sign. A '^' at the beginning of denotes as characters NOT belonging to the set, while all the others impli- citly make up the set of white-space or separator characters. An alternative splitting strategy can be specified by the /C switch. Here defines the set of separator characters. Typi- cally it consists of a single character but more are possible. It is used to read data in the CSV-format (character separated value), where each line defines a record in which the individual data items are separated from each other by a dedicated character, often a co- lon ':', a semicolon ';' or a . Unlike the /W switch, the /C regards every occurence of a character from the set of separators as the begining of a new field. So a data string of abc:::def would be seen as two data fields if defined as /W: but as four fields if defined as /C: A third splitting strategy devides the input line into fields of fixed widths. It is defined by the /F[-]x:y:z:... switch. It assig- nes the first x characters to the first target, the next y ones to the second one, the following z to the third one and the rest to the last defined target. Therefore it is not useful to define more numbers than targets, even though it does no harm. The splitting takes place from left to right unless a '-' sign is placed between the /F and the first width. In this case it is carried out from right to left. This means the last z characters are assigned to the last target, the next-to-last y characters to the next-to-last tar- get and so on while the first target takes the remaining rest. By default PIPESET will write its target variables directly into the environment of the parent process. As this may not be possible in all environments, especially not in those that only emulate an (MS-)DOS system the /S switch provides an alternative method. If it is set then PIPESET generates SET commands which can be re-directed into an auxiliary batch file, which can then be called by the pri- mary one to carry out the actual setting of the variables. As this method does not make use of any undocumented features, it should work under any flavor of a DOS system. If not re-directed to a file the /S switch can furthermore serve as testing aid, as it shows, what it would do if it did something. examples: cd | pipeset /S current_path simply writes the output of the 'cd' command, the current path into a variable of name current_path. The /S switch is just set for cla- rity, to let the result be displayed on the screen. Generally it would be omitted. ver | pipeset /S syst=(MS vers Scans the output of the command 'ver' for a line in which the first field begins with the letters 'MS'. If such a line is found, this first field will be stored into the variable 'syst' and the rest of the line into the variable 'vers'. pipeset /S /C=, ==country country codepage driver < \config.sys Reads the file \config.sys breaks each line into pieces delimited by the characters '=' or ',' and searches for a line where the first field equals the string 'country'. If such a line is found this first field is discarted and fields two, three and four are stored into the variables 'country', 'codepage' and 'driver'. dir /S \ | pipeset /S /M$ files ==file(s) = Scans the output of the command "dir /S \" for the last one of all lines in which the second word equals "file(s)", discarting any re- maining words and storing the content of the first word into the environment variable "files". This happens to be the total number of files on the respective drive. Please note, that the precise wording and spelling of the search pattern may have to be adjusted according to the DOS version in use. Version history: The command line switch /M and the search criteria '{' and '}' were only introduced in version 1.1 of PIPESET and were not available in prior versions. TEE (TEE-junction for data streams) is a program that simply copies its stdin to stderr, which is under DOS allways assigned to the terminal. If, and only if, stdout is not also assigned to the terminal, then it will write a second copy to stdout. This way it is possible to route the output of another progam into a file and display it on the screen at the same time. Note furthermore, that this program is similar but not identical to its counterpart known from UNIX. example: dir | tee > dir.lst Shows the directory listing on the screen and writes it into the file dir.lst at the same time. TR (TRanslate characters) is a program which allows to replace certain characters in an input by a replacement. This replacement can be another character or a sequence of characters. Furthermore it is possible to remove cer- tain characters from the input stream. The correct syntax is: tr [ options ] [ [ ... ] ] valid options are: /C (complement) all characters NOT in /D (delete) remove all characters in /S (squeeze) remove consecutive duplicate characters /M (multibyte) replace all characters in by the corresponding , , ... Usually TR is used as part of a pipe. In its standard form it takes two string arguments. The first argument, defines the set of characters that are to be modified, while the second argument, defines the characters by which the corresponding charac- ters from are to be replaced. This implies, that both strings must have the same size. Should be longer than then the excessive characters just have no effect. Should it be shorter, it will be silently extended by duplicating the last character as many times as needed to fill the difference. Characters can optionally be expressed as hexadecimal values in the form \XX and X-x defines a whole range of characters. If the '-' sign is the first or last character of a string or if 'X' doesn't have a lower ASCII value than 'x', then the '-' is taken as literal minus sign. Several command line switches can modify TR's behaviour. If the /C switch is set, then is made up of all those characters that are NOT part of the first command line argument. The /D switch causes TR to remove all characters found in from the in- put stream. In this case doesn't need to be specified. If the /M switch is set, then each character from the input stream found in will be replaced by a sequence of characters in such a way that the first one will be replaced by the whole , the second one by and so on. If there are less strings than there are characters in then the last one is again repeated as many times as needed to fill the difference. Using the /M switch the total length of all strings plus the number of strings (to account for the terminating \0 byte of each string) may not be greater than 255. The /S switch causes all but one of a series of consecutively identical characters to be removed from the output stream, hence after a possible conversion (but before expan- sion into a sequence of characters). examples: echo abcDEFghi | tr A-Z a-z Replaces all upper case characters by their lower case counterpart echo a..o..u. | tr /M \0A\0D ae oe ue "" "" Substitutes the german lower case umlauts by a character sequence and the ASCII codes 0x0D and 0x0A by a visible indicator. SELECT (SELECT an item from a menu) is a program which presents the user a menu from which he/she can pick an item. The result of this choice is stored in an environment variable from where it can be further used or processed in any way. The content of this menu can either be defined by a file of arbi- trary items or it can be a directory in which case it serves to pick a file- or directory name or to traverse the directory tree. The correct syntax is: select [ options ] [path\][dir mask] valid options are: /A[attr] D:directories F:(ordinary) files A:archive H:hidden R:read-only S:system /F get menu content from file /O[B,L,P,R] output: /OB base name /OL long form /OP full path /OR rel.path /C[V,S,K] change dirs /CV virtual root /CK keep on exit /CS "." selects /D append "\" to directory names /T define time-out in seconds /S[var] make set command for environment variable /E[var] store directly in environment (tricky !!!) /H /? print this helptext By default SELECT presents the directory defined by the (optional) path argument and the directory mask in much the same way as the built-in DIR command would do it. One line of this listing is high- lighted in reverse video but this mark can be moved up and down by the /, the / and the keys. By hitting the key, the currently highlighted item is selected and the program will terminate with the result set into a variable. By hitting the key, the program can be left without making a choice. Several command line switches can modify the program's behaviour. The /F switch causes the path/dir-mask argument to be interpreted as a file name (it must not contain any wildcard characters in this case). The content of this file makes up the menu, line by line. If one of the two first lines of this file begins with ".TITLE " then the rest of this line is seen as a headline instead of a menu entry. If it begins with ".DEFAULT " then the rest of the line defines a default which is taken if the user leaves the menu without making a choice by hitting the key or if a time-out defined by /T runs out. This default should be in the same form as the ordinary menu items but it need not be identical to any of them. By the /A switch, which will usually be followed by one or more of the sub-switches A,D,F,H,R or S the directory display can be fur- ther specified. The 'D' sub-switch causes only directories to be shown, while 'F' shows only (ordinary) files. Specifying both toge- ther like this "/ADF" causes directories and files to be shown but this is the default anyway. The 'S' and 'H' allow to include hidden and system files in the display, while 'A' and 'R' have little effect and are only included for compatibility with DIR. The "/C" modifies the treatment of directories. By default, they are treated like files which means, that hitting the key simply selects that item and returns the directory name. If "/C" is set, then hitting the key does not return the directory's name, but rather causes SELECT to change into that directory. Note that it is not possible to get a directory name as result in this case. To overcome this limitation the optional sub-switch 'S' can be used. It causes an additional entry "." to be displayed in each directory. Hitting the key while this entry (which tradi- tionally denotes the current directory) is highlighted doesn't cau- a change to that directory (which would be pointless anyway) rather it causes the name of the current directory to be returned. (Please note that this behaviour differs from the one of version 1.5) The optional sub-switch 'K'(keep) causes SELECT to remain in the currently selected directory upon program termination. By default it will always return to the directory that was current at program start. The also optional sub-switch 'V' defines something like a 'virtual root'. This is either the path argument or, if none was specified, the directory that was current at program start. The effect ot this sub-switch is that the user can freely change into sub-directories of this virtual root but not into its parent direc- tories. All the sub-switches may be combined like "/CKSV" even though combining 'K' and 'S' may not be very useful. The "/O" further specifies the output of SELECT. By default it will return the (short) name of the selected directory item or the first word of the respective line in file mode. The "/OB" switch causes the output to be restricted to the base name that is the part be- fore the dot of the (short) name. In file mode it also truncates the result to the first part should the first word on the line hap- pen to contain a dot. The "/OL" switch causes the longname of the file to be returned, if it is available e.g. under WINDOWS95 or DOSLFN, while in file mode it causes the whole line to be returned. The /OP switch returns the full path, consisting of drive, path the base name and the type extension. The /OR switch causes the relati- ve path, relative to the starting directory, to be returned, if the current directory when terminating SELECT is still the same one or below that starting directory. Otherwise it will return the full path, just as if /OP had been specified. Note that the starting di- rectory is the one that was specified as path argument, it is not necessarily identical to one that was current at program start. If "/CV" is specified too, then it is identical to the virtual root and "/OR" will return the path relative to this virtual root. In file mode "/OP" and "/OR" have no special effect. Please note that the sub-switches of /O ("B","L","P","R") are mutually exclusive. The switch /D causes the program to append a "\" to directory names on output. WARNING: The combination of /OB and /D may lead to un- expected results when selecting a directory which has itself a dot in it's name (this is however a very rare combination). By default SELECT will output the text "SET SELECT=...." to stdout where the dots "...." are replaced by the result. Re-directing this into a file, e.g. \tmp\setvar.bat and then calling that file, will cause the environment variable SELECT to be filled with the selec- ted item. The /S switch allows to assign a different name to that variable while the /E switch causes the variable to be stored di- rectly into the environment of the parent process. This is more elegant but doesn't work in all systems, especially not in those ones that just emulate (MS-)DOS. Optionally the /E switch can also be used to define a different variable name at the same time. If all went well and the user made a choice then SELECT will return an error code of 0. In the case of a severe error, e.g. file not found it will return 2. If the user left SELECT without making a choice by hitting the key or if the time-out defined by the /T switch ran out, then the code 1 will be returned, unless if in filemode a .DEFAULT has been defined in the menu file. In this case the default will be returned with an error code of 0, just as if the user had chosen that alterntive. If the user made no choice, in whatever way, then SELECT doesn't touch the result variable, (which is SELECT by default but can be given any name by the /S or /E switches). So preseting this variable with some value prior to invoking SELECT is a method to establish a default becomimg effec- tive if no choice was made which can be applied in directory mode as well as in file mode. The top most line of the screen gives some information about the kind of selection that can be made while the line on the bottom of the screen gives short usage hints by default. This default can be overriden by two environment variables. The variable SELECT_TOP can be used to define a new text for the top most header line while SELECT_BOT re-defines the footer line. example: select /C *.* Presents the listing of the current directory, allowing to freely change into any other directories ("/C" but not 'V') and returns to the directory that was current at program start (as 'K' is not set either). As result writes the text "SET SELECT=" to stdout. Version history: The /OP command line switch was introduced only in version 1.2 and not available in prior versions. Version 1.3 introduced the /OR command line switch, which was not available in prior versions and included a minor bug fix. Version 1.4 was just a bug fix. Version 1.5 added the possibility to complement the path argument by a drive specification and introduced the "/CS" sub-switch which was not available in prior versions. Version 1.6 modifyed the operation of the "/CS" sub-switch. The /D was introduced only in this version and not available in prior ver- sions. FAM (Find And Modify) is a program that reads text from its stdin channel, line by line, and splits each line into several (up to ten) fields, according to certain rules. Eventually the individual fields are recompiled (af- ter a possible modification) into a new line and written to stdout. So far the default behaviour of the program, which can be modified in various ways. The correct syntax is: | fam [ options ] [ format ] [ > newfile ] or fam [ options ] [ format ] [ > newfile ] < options are: /F define fixed fields e.g. /F3.5.2 or /F-3.5.2 /C define set of separator characters /W define set of whitespace characters A-Z range \XX hex ^ complement /R replace field (0..9,#,*) by string (or /S) /X exchange in field character by /P print non-matching lines unchanged /L only if line # : = equal # not equal /N only if # fields : - less + greater /M only lines where field matches according to 0..9 field n # last field * any field = is equal { not- ( begining with ? containing # is not equal } not- ) ending with ! not containing format can be any text including the following special codes \Fn field n \Tn trim n \N # of fields \F# last field \Pn pad to n \L line # \F* input line \Q quote (") \Xxx hex code \Sn separator n \\ backslash \B conditional break The possibly simplest way to modify the default behaviour is to set the /R command line switch. It causes the content of field (m=0..9) to be replaced by the string before the fields are recompiled to form the output line. More than one such switch, each for a different field, may be specified. If the symbol '#' is specified as field number, than the last field will be changed, no matter what happens to be the number of fields in that line. The symbol '*' has a special meaning which is explained further down in conjunction with pattern matching. The /S (substitute) command line switch takes the same arguments as /R and serves a similar purpose, but is also explained further down in conjunction with pattern mat- ching. The /X switch exchanges all occurences of character in field by character . The field indicator can take the same values as with /R and more than one /X switch can be as- signed to the same field to exchange several characters at a time. The characters and may be either expressed as plain char- acters or in the form \XX with 'XX' being two hexadecimal digits. Another important possibility is to modify the way, how a line is split into pieces (fields). By default, it is split into "words" in a rather intuitive way, where a word simply is a sequence of conse- cutive non-blank characters separated from each other by sequences of so called white-space characters. By default, the space itself as well as all control characters (with ASCII values below 32) are considered as white-space, including carriage-return, line-feed and the tabulator. At most ten such fields (numbered from 0 to 9) are generated. Should a line consist of more than ten "words", then all remaining words will be stored in the last field (number 9). Should a line consist of less then ten "words", then the remaining fields will be empty and the internal field counter will reflect the actu- al number. By means of the /W command line switch one can re-define this set of white-space characters to whatever is appropriate to do the job. However the control characters are always considered as white- space, no matter what is specified by /W. By the /C switch a different kind of rule can be specified. In this case, all members of the string are considered as separa- tors separating the individual fields. This rule which is typically used to read so-called CSV-files (character separated values) dif- fers from the above one in that each occurence of a charcter from the set of separators defines a new field. A line like "ABC:::DEF" with colon being part of the set of separators, would result in two filds ("ABC" and DEF") when split into "words". If the the CSV-rule is in force, then it will be read as four fields ("ABC", two empty fields and "DEF"). Again, the control characters are alway consi- dered as separators and at most ten fields are generated. A third type of rule can be specified by the /F[-]........ command line switch. It simply cuts the line into fields of a fixed size as defined by , , and possibly more numbers, up to a maximum of nine, resulting in nine fields of the specified width plus a tenth one to take the rest. If the optional "-" is specified then the fields are counted from right to left in such a way that the last number specifies the width of the last field, the next-to- last number the width of the next-to-last field and so forth. Field number zero takes the remainig rest at the beginning of the line in that case. Another important way to modify FAM's operation is to re-define the output format. By default each separator and each field (possibly after replacing it by some different text) is output in exactly the the same order as they appeared in the input line. This output for- mat can be overridden by any arbitrary text, optionally enclosed in double quotes, especially if the exact preservation of spaces is important. This text will simply be output for each line read, which may not yet be what the user actually wants, but by inserting certain special codes, all of them beginning with a backslash "\", this text can be become a versatile tool to customize the output in many different ways. A \Fn (n=0..9) will insert the content of field n into the output string at the indicated position. A \F# will do the same with the last field. In both cases the insertion is carried out after a pos- sible replacement and a \F* represents the complete original (unmo- dified) input line. A \Tn (n=0..9,#) is similar to \F as it inserts the content of a field into the output string. However this content will be trimmed (leading and trailing spaces will be removed) prior to actually outputting it. Note that trimming a field doesn't make much sense if the default splitting rule ("split into words") is in effect, as the words will not have any leading or trailing spaces anyway. But if an alternative splitting rule is chosen, then \T may become useful. A \Sn (n=0..9) copies the original separator n into the output string and a \S# does the same with the last separator, this is the one, that separates the last field from the next to last one. If the input is split into "words", then the first separator (\S0) contains the whitespace that was found before the first word, also known as left margin. If the CSV-rule is applied then \S0 is always empty and all other separators are one character long. If the fixed widths rule is in force, than all separators are empty. A \Xhh with "hh" being two hexadecimal digits, will insert an arbi- trary byte into the output stream, a \Q a double quote (") and a \\ writes the backslash itself. A \N will write the number of fields and a \L the current input line number into the output stream. This may be most useful for debugging purposes, when trying to under- stand FAM's operation. A \Pn (n=2..19) pads spaces to the output line assembled so far, until its length is a multiple of . The \B (conditional break) code is possibly the most difficult one to understand. It doesn't output anything at all, but just sets an internal flag. If this flag is set, then, whenever a field (\Fn) is output, it is checked, whether this happens to be the last field in this (input) line. If so, the rest of the output format is discar- ted. The purpose of this code is to allow to suppress the output of fixed text parts which make no sense if the preceeding fields are empty. As the format string is evaluated from left to right and the field checking only takes place after the \B code was found, it is possible to control which part of the output line should be condi- tionally suppressed. If no output format is defined, then the following default is used: "\B\S0\F0\S1\F1\S2\F2\S3\F3\S4\F4\S5\F5\S6\F6\S7\F7\S8\F8\S9\F9" Everything explained so far, applies indiscriminately to each line of the input text, but this can also be modified in such a way that only distinct lines are affected. The /L? switch where '?' can be one of the following characters: '+', '-', '=' or '#', causes FAM to operate only on lines with line numbers greater than, less than, equal to or not equal to . Likewise the /N? switch lets FAM only treat lines where the number of fields, formed accor- ding to one of the above mentioned rules, is greater, less, equal or not equal to . Other lines are simply discarted, at least by default. The most powerful tool to select distinct lines from the input text is the /M switch. Here refers to a field in much the same way as with the /R switch, meaning that '0..9' refers to field number n, '#' to the last field and the special symbol '*' means any field. The second character specifies a match criterion. It can be one of the following symbols: '=', '#', '(', ')', '{', '}', '?' or '!' and means, that the match criterion is fullfilled if the respective field is equal ('='), not equal ('#'), begins with ('('), ends with (')'), does not begin with ('{'), does not end with ('}'), contains ('?') or doesn't contain ('!') the string . The any field criterion('*') is fullfilled if at least one field in the line fullfills it, no matter which one. This can be confusing when used with negative criteria: not equal('#'), does not begin with('{'), does not end with('}') or doesn't contain('!'), as it does _NOT_ mean, that none of the fields may contain, begin, end or be equal to . If the replacement switch is used with the aste- risk like /R*, then the field matched by a corresponding /M* switch will be replaced by , no matter which one it is. If more than one field matches, they will all be replaced. Without a corresponding /M* switch a /R* switch has no effect. The substitute switch (/S) acts very similar to /R with one excep- tion: If it applies to a field to which a positive partial match (contains ('?'), begins with ('(') or ends with (')')) condition is assigned, then only the matching part of that field is replaced in- stead of the entire field. In all other cases and all other aspects it behaves exactly like /R. To better understand the subtle differ- ences between /R and /S it might be helpful to look at this example echo path=C:\;C:\DOS;C:\UTILS; | fam /C=; /M*(C: /S*D: yields the following result: path=D:\;D:\DOS;D:\UTILS; echo path=C:\;C:\DOS;C:\UTILS; | fam /C=; /M*(C: /R*D: doing the same with /R gives: path=D:;D:;D:; instead. It is possible to define more than one /M switch. In this case the following rules apply: Match criteria referring to different fields are AND connected while criteria referring to the same one are OR connected. Thus "/M1=rst /M3(abc /M3)xyz" would find every line where field number 1 is equal to "rst" AND field number 3 either begins with "abc" OR ends in "xyz". If a selection criterion (/L, /N or /M) is in force, then lines not matching that criterion are simply discarted, at least by default. The /P switch can cause FAM to print these non-matching lines as well. They are simply copied from the input without any change. If no selection criterion is specified then /P has no effect. Notes: If more then one switch is specified on the command line, the different switches should be seperated from each other by at least one blank. FAM cannot process lines which are longer than 255 characters. Longer lines are silently truncated to the allowable length and a warning message informs about the truncation. If FAM encounters a line that is even longer than 760 characters, then the operation will be aborted to prevent buffer corruption due to over- flow. examples: fam /L-21 \L \F* < inputfile Prints the first twenty lines of "inputfile", prepending the line number to each of them. fam /F-5 /R1***** < inputfile fam /F-5 /R#***** < inputfile Both versions replace the last five characters of each line of "inputfile" by five asterisks. They differ in the way, how lines which are shorter than five characters, are treated. fam /M*=the /R**** /P < dosutils.txt Replaces each occurence of the word "the" in this text by three as- terisks. This may not be terribly useful, but it is an example of the versatility of this program. Note that the first astrisk in the /R switch refers to the corresponding /M switch, while the remai- ning three ones are the actual replacement text. echo price, excluding tax 12.345,95 | fam /X#., /X#,. Changes the decimal comma and dot notation from german convention to the one used in the united states, but only in the last column, leaving other commas intact ==> price, excluding tax 12,345.95 fam /C=,\\ /M*=c: /M*=C: /R*D: /P < \config.sys" Automatically replaces all references to drive "C:" in the file "config.sys" by references to drive "D:". Note that the backslash in the switch "/C=,\\", defining a CSV-rule with the characters '=', ',' and '\' as separators, has to be duplicated in order to be re- cognized as literal backslash. Using the /S switch, the same result could have been achieved by the following command: fam /C=, /M*(C: /M*(c: /S*D: /P < \config.sys Version history: The command line switches /S and /X, the special format codes \T and \P as well as the search criteria '{' and '}' were only introduced in version 1.1 of FAM and were not available in prior versions. Version 1.2 is a pure bug-fix release to provide for a more robust behaviour when encountering oversized input lines. Version 1.3 was again a pure bug-fix release to correct an error in the processing of /Mx=yyy and /Mx#yyy switches which returned false matches if the field was shorter then the comparison string. PRINTF (PRINT Formatted) does essentially the same as the built-in echo command. However it allows to format the text in various ways and brings the flexibili- ty of the standard "C" libraray function to the command line. The correct syntax is: printf [ [ ... ] ] [ < ] Arguments can be given on the command line and/or they can come via the stdin channel, but command line arguments are evaluated first. The first argument (whether given on the commnd line or via stdin) is the so-called format string which has a special role as it de- termins how many more arguments are expected and how they are in- terpreted. Any argument that contains at least one blank character must be enclosed in double quotes ("...") to be recognized as a single argument, otherwise the quotes are optional. Arguments can also be environment variables like e.g. %num%. When used from the command line, such a reference must be an argument of its own, in other words, the '%' signs must be the first and last character of the respective argument. In a batchfile this is not absolutely ne- cessary. However, due to the interpretation of the '%' sign as va- riable indicator, literal '%' signs must be duplicated in this case. This applies especially to the the format string. The interpretation of the format string follows essentially the rules known from the "C" programming language but with some except- ions caused by the diffenrent context. The format specifiers '%p' and '%n' known from BORLAND-C to denote near and far pointers make no sense on the command line and are not supported. The option to specify the width of an argument by another argument, specified by '*' isn't supported either. Floating point formats '%e','%f','%g', '%E' and '%G' are only supported by some versions of printf. For each format specifyer "%..." one additional argument is expected. If printf encounters one of the '%d','%i','%o','%u','%x' or '%X' specifiers in its format string, it tries to interpret the corres- ponding argument as integer number, which in-turn can be expressed in various ways, e.g. as "123", as "0173" or as "0X7B". If the ar- gument cannot be interpreted as a valid integer, "0" is silently assumed. The output format need not have the same number base (dec, oct or hex) as the argument, so printf can be used to perform num- ber conversions. If printf encounters one of the '%e','%f','%g','%E' or '%G'speci- fiers in the format string, it tries to interpret the corresponding argument as a decimal number, integer or real, which in-turn can be written in various formats. A '%s' specifier just expects any kind of (printable) string as ar- gument. If the first character of the argument for a '%c' specifier is a digit ('0'..'9') then this argument is read as integer number and the character corresponding to the respective ASCII code (modu- lo 256) is printed. Otherwise the argument is regarded as a string of which only the first character will be printed. The data size specifiers 'h','l','L','F' and 'N' are tolerated but have no effect. In the format string (and only there) most of the usual escape cha- racter sequences are recognized. Only "\'" is not supported, it is not necessary - just use a literal aposthrophe instead and the quote character '\"' cannot be used, as it is interpreted by the shell to denote strings - use \q instead. The additional code '\e' issues an ASCII escape character (value 27) and the codes '\l' and '\m' have a special meaning which is described further down. Printf can operate in two different modes. By default, it just in- terprets the format string and expects for each format specifyer ('%...') a corresponding additional argument. If there are no more arguments, but stdin is assigned to something other than the key- board, then more arguments are read from there. Otherwise missing arguments are replaced by the string "(NULL)". If there are more arguments than format specifyers, the excessive arguments are just ignored. Printf behaves differently if the format string contains the code '\l' (for: loop). In this case, if the interpretation of the format string, which is carried out strictly from left to right, reaches the code '\m' (for: more) or the end of the format string (if '\m' is not specified) then printf starts over at the character follow- ing the '\l' code until the list of arguments is exhausted. At that point the part following the '\m' code will be interpreted. This part should not contain any more format specifyers, but constant text is allowed. If '\m' is not specified then printf will simply termiate. At most one '\l' and one '\m' should appear in the format string and '\m' (if present) should be placed to the right of '\l'. examples: printf "%s %d %02X %d %02X\n" abc 123 123 0x7b 0X7B This will print the string "abc", followed by four times the number 123 represented in various formats. echo abc def ... xyz | printf "result=\q\l%s,\m\q\n" The built-in command echo is used to produce a stream of four strings which is fed into a pipe. Printf itself has a single argu- ment, the format string. As it expects more arguments, it continues to read from stdin. First it will print 'result="', followed by the first string 'abc' and a comma. When reaching the '\m' it will re- turn to the character following the '\l', that is the '%'. As soon as the last string 'xyz' is printed, it will continue at the cha- racter following the '\m' thereby skipping the last trailing comma and print a trailing quote, followed by a newline. The result will look like this: result="abc,def,...,xyz" Printf comes in two flawors: printf.com is the compact version which doesn't support floting point formats while printf.exe allows to use the full range of formats, including '%e','%f','%g','%E' and '%G' but at the expense of being more than twice as large. This is the only difference and both versions are generated from the same source code by means of conditional compilation. DUMPENV (DUMP the ENVironment) is a tiny utility which simply writes the current environment to stdout in much the same way as the built-in command SET (without ar- guments) would do it. However it gives more details and also shows the environment of the parent process. As such it is not terribly useful for everyday life, but it can be handy in debugging if one of the other programs, that attempt to store data directly into the environment doesn't work as espected. GENERR / CGENERR (GENerate an ERRor) Are two little utilities which take one numeric argument in the range of 0 .. 255. They terminate immediately returning this number as error code. Their only purpose is to test the "IF ERRORLEVEL n" command of batchfiles. CGENERR was written in "C" and is a little bit more verbose while GENERR is a pure assembler program. example: generr 3 INVOKE (INVOKE a program) Is a program that takes the name of another program as first argu- ment and possibly (up to 19) more arguments. It then spawns that program as a child process, passing to it all additional arguments. Upon termination of the child process it displays the error code returned by that program. As many flawors of (MS-)DOS do not allow to directly show the value of the returned error code, this may be a useful aid in testing and verifying these error codes. The correct syntax is: invoke [ options ] [ arguments for program ] valid options are: /D discard stderr /P propagate result /Q quiet operation /R re-direct stderr into stdout /H /? print this helptext INVOKE itself returns zero as error code unless called with the /P switch. In this case it propagates the error code returned by its child back to its own parent. The /Q switch suppresses the display of the error (return) code, which may be useful in conjunction with the /D and /R switches. Unlike UNIX, (MS-)DOS does not allow to re-direct stderr, at least not out of the box. The /R switch re-directs the stderr channel of the invoked child program to stdout. By itself this does not lead to any visible effect. If however stdout is in-turn re-directed, e.g. to a file, then both, stderr and stdout will go to that file. The /D switch just discards the child's stderr channel (actually it just re-directs it to NUL). Note that INVOKE adds another level to the parent-child-grandchild process chain. Therefore programs which try to set environment var- iables may not work as expected. example: invoke select *.* Version history: The command line switches /D, /R and /Q, were only introduced in version 1.1 and not available in prior versions. SCRDUMP (SCReen DUMP) This program writes a portion of the screen to stdout if stdout is re-directed to a file (or another program). It's main pupose is to serve as logging feature in batch files like e.g. AUTOEXEC.BAT. The output of programs like network drivers that might otherwise simply scroll off the screen can be captured and written to a log file for later inspection. The correct syntax is: usage: scrdump - invisibly mark screen line or: scrdump [ options ] > - dump screen between marked line and cursor line to file valid options are: /H /? print this helptext /A (all) dump whole screen /C compensate for prompt /B print before begin of screen output /E print after end of screen output The program operates in one of two modes, depending on the way how it is invoked. If invoked without stdout being re-directed (no ">" or ">>" or "|") then it simply writes an invisible mark to the cur- rent line on the screen. If invoked WITH re-direction in effect (scrdump > file) it will search the mark and write the screen lines between (but not including) the marked line and the line the cursor is on when the program starts to stdout which in-turn will go to a file. If the mark cannot be found, either because it was scrolled off the screen or because no mark was written before, the top line of the screen will be taken instead. The operation of the program can be further modified by some com- mand line switches. The swithes /B (begin) and/or /E (end) write an extra line of text before or after the screen content. If the out- put of several programs is appended to the same logging file, this feature can be used to separate individual sections. If is only one character long and is not alphanumeric like "/B=" then it is automatically expanded to a string of 60 repetitions of that character. This way a horizontal ruler can be written very easily. Other text is just written literally. If the text contains any blanks then the entire switch must be enclosed in quotation marks like this: "/B--- packed driver ---". Even though the program is most useful in batch files it can also be used directly from the command line. In this case however there is a slight inconvenience as in interactive mode the command shell writes a prompt to the screen and echoes the command entered via the keyboard. The command line switch /C compensates for this in order to prevent this prompt from being written to the output. When used in batch files it is not required. If the command line switch /A is set, then all 25 lines (of a standard 25*80 character screen) are written to the file, regardless of marks or the cursor position. example: scrdump ne1000 0x60 5 0x300 scrdump > net\ne1000.log This sequence which could be part of an AUTOEXEC.BAT file would write a mark to the screen, then load the packet driver and eventu- ally write the messages from the driver to the file net\ne1000.log. Only the messages from the driver will be written to the file any other text that happens to be on the screen is ignored and it makes no difference whether the driver itself writes it's messages via stdout, stderr or directly to the screen. Jrgen Hoffmann (2010) j_hoff@hrz1.hrz.tu-darmstadt.de