Path: senator-bedfellow.mit.edu!dreaderd!not-for-mail
Message-ID: <msdos-programmer-faq/part3_1084010824@rtfm.mit.edu>
Supersedes: <msdos-programmer-faq/part3_1081511793@rtfm.mit.edu>
Expires: 11 Jun 2004 10:07:04 GMT
References: <msdos-programmer-faq/part1_1084010824@rtfm.mit.edu>
X-Last-Updated: 2003/08/14
From: jeffrey@carlyle.org (Jeffrey Carlyle)
Sender: jeffrey@carlyle.org (Jeffrey Carlyle)
Reply-To: jeffrey@carlyle.org (Jeffrey Carlyle)
Approved: news-answers-request@MIT.edu
Organization: JeffC.org
Subject: comp.os.msdos.programmer FAQ part 3/5
Newsgroups: comp.os.msdos.programmer,alt.msdos.programmer,comp.answers,alt.answers,news.answers
Followup-To: poster
Summary: Frequently asked questions from DOS programmers with tested answers.
Originator: faqserv@penguin-lust.MIT.EDU
Date: 08 May 2004 10:08:03 GMT
Lines: 942
NNTP-Posting-Host: penguin-lust.mit.edu
X-Trace: 1084010883 senator-bedfellow.mit.edu 574 18.181.0.29
Xref: senator-bedfellow.mit.edu comp.os.msdos.programmer:127444 alt.msdos.programmer:54822 comp.answers:57100 alt.answers:72787 news.answers:270991

Archive-name: msdos-programmer-faq/part3
Comp-os-msdos-programmer-archive-name: dos-faq-pt3.txt
Posting-frequency: 28 days
Last-modified: 14 Aug 2003

comp.os.msdos.programmer FAQ Version 2003.08.14

This is the Frequently Asked Questions list for the newsgroup
comp.os.msdos.programmer.

COPYRIGHT

Copyright 2003 by Jeffrey Carlyle. All rights reserved. This article is
not in the public domain, but it may be redistributed so long as this
notice, the acknowledgments, and the information on obtaining the latest
copy of this list are retained and no fee is charged. The code fragments
may be used freely; credit to the FAQ would be polite. This FAQ is not to
be included in any static: archive (e.g. CD-ROM or book); however, a
pointer to the FAQ may be included. See <Q:01.14> [Where can I get the
latest copy of this FAQ list?] for a link to the latest version of the
FAQ.)

This is part 3 of 5 parts.

TABLE OF CONTENTS

PART 1: 
Section 1.  General FAQ and Newsgroup Information
  <Q:01.01> - Is MS-DOS Dead?
  <Q:01.02> - What is this article for?
  <Q:01.03> - Who has contributed to this article?
  <Q:01.04> - How can I search this article for a particular topic?
  <Q:01.05> - Are the answers guaranteed to be correct and complete?
  <Q:01.06> - What is comp.os.msdos.programmer about?
  <Q:01.07> - Is comp.os.msdos.programmer just for C programmers?
  <Q:01.08> - What is comp.sys.ibm.pc.programmer?
  <Q:01.09> - Is comp.os.msdos.programmer available as a mailing list?
  <Q:01.10> - What's this netiquette?
  <Q:01.11> - How can I learn more about Usenet?
  <Q:01.12> - What other technical newsgroups should I know about?
  <Q:01.13> - Where are FAQ lists archived?
  <Q:01.14> - Where can I get the latest copy of this FAQ list?

Section 2.  General Reference
  <Q:02.01> - Are there any good on-line references for PC hardware
              components?
  <Q:02.02> - Are there any good on-line references for PC interrupts?
  <Q:02.03> - What and where is Ralf Brown's interrupt list?
  <Q:02.04> - Where can I find lex, yacc, and language grammars?
  <Q:02.05> - What's the best book to learn programming?
  <Q:02.06> - Why won't my code work?
  <Q:02.07> - Are there any good sources of example code?
  <Q:02.08> - What and where is SNIPPETS?
  <Q:02.09> - Is the source code MS-DOS available?
  <Q:02.10> - What are my alternatives for MS-DOS compatible OSes?
  <Q:02.11> - What and where is FreeDOS?
  <Q:02.12> - Where can I find out about batch files?

PART 2: 
Section 3.  Compile and link
  <Q:03.01> - What the heck is DGROUP > 64K?
  <Q:03.02> - How do I fix 'automatic data segment exceeds 64K' or 'stack
              plus data exceed 64K'?
  <Q:03.03> - Will Borland C code and Microsoft C code link together?
  <Q:03.04> - Why did my program bomb at run time with 'floating point
              formats not linked' or 'floating point not loaded'?
  <Q:03.05> - How can I change the stack size in Borland's C compilers?
  <Q:03.06> - What's the format of an .OBJ file?
  <Q:03.07> - What's the format of an .EXE header?
  <Q:03.08> - What's the difference between .COM and .EXE formats?
  <Q:03.09> - How do I create a .COM file?
  <Q:03.10> - Where is EXE2BIN located?
  <Q:03.11> - What does this message mean: 'A20 already enabled so test
              is meaning less?'

Section 4.  Keyboard
  <Q:04.01> - How can I read a character without echoing it to the
              screen, and without waiting for the user to press the Enter
              key?
  <Q:04.02> - How can I find out whether a character has been typed,
              without waiting for one?
  <Q:04.03> - How can I disable Ctrl-C/Ctrl-Break and/or Ctrl-Alt-Del?
  <Q:04.04> - How can I disable the print screen function?
  <Q:04.05> - How can my program turn NumLock (CapsLock, ScrollLock) on
              or off?
  <Q:04.06> - How can I speed up the keyboard's auto-repeat?
  <Q:04.07> - What is the SysRq key for?
  <Q:04.08> - How can my program tell what kind of keyboard is on the
              system?
  <Q:04.09> - How can I tell if input, output, or stderr has been
              redirected?
  <Q:04.10> - How can I increase the size of the keyboard buffer?
  <Q:04.11> - How can I stuff characters into the keyboard buffer?

PART 3: (this part)
Section 5.  Disks and files
  <Q:05.01> - What drive was the PC booted from?
  <Q:05.02> - How can I boot from drive B:?
  <Q:05.03> - Which real and virtual disk drives are valid?
  <Q:05.04> - How can I make my single floppy drive both a: and b:?
  <Q:05.05> - How can I disable access to a drive?
  <Q:05.06> - How can a batch file test existence of a directory?
  <Q:05.07> - Why won't my C program open a file with a path?
  <Q:05.08> - How can I redirect printer output to a file?
  <Q:05.09> - How can I redirect the output of a batch file?
  <Q:05.10> - How can I redirect stderr?
  <Q:05.11> - How can my program open more files than DOS's limit of 20?
  <Q:05.12> - How can I read, create, change, or delete the volume label?
  <Q:05.13> - How can I get the disk serial number?
  <Q:05.14> - What's the format of .OBJ, .EXE., .COM files?
  <Q:05.15> - How can I flush the software disk cache?
  <Q:05.16> - How can I see if a drive is a RAM drive?
  <Q:05.17> - How can I determine a hard drive's manufacturer?
  <Q:05.18> - Where can I find information about the ATA/ATAPI
              specification?
  <Q:05.19> - How can I copy files to or from filenames containing date
              information?

Section 6.  Serial ports (COM ports)
  <Q:06.01> - How do I set my machine up to use COM3 and COM4?
  <Q:06.02> - How do I find the I/O address of a COM port?
  <Q:06.03> - But aren't the COM ports always at I/O addresses 3F8, 2F8,
              3E8, and 2E8?
  <Q:06.04> - How do I configure a COM port and use it to transmit data?

PART 4: 
Section 7.  Other hardware questions and problems
  <Q:07.01> - Which 80x86 CPU is running my program?
  <Q:07.02> - How can a C program send control codes to my printer?
  <Q:07.03> - How can I redirect printer output?
  <Q:07.04> - Which video adapter is installed?
  <Q:07.05> - How do I switch to 43- or 50-line mode?
  <Q:07.06> - How can I find the Microsoft mouse position and button
              status?
  <Q:07.07> - How can I access a specific address in the PC's memory?
  <Q:07.08> - How can I read or write my PC's CMOS memory?
  <Q:07.09> - How can I access memory beyond 640K?
  <Q:07.10> - How can I use the protected mode?
  <Q:07.11> - How can I tell if my program is running on a PS/2-style
              machine.
  <Q:07.12> - Is there a 80x87 math unit installed?
  <Q:07.13> - How can I power off the computer from a batch file?

Section 8.  Other software questions and problems
  <Q:08.01> - How can a program reboot my PC?
  <Q:08.02> - How can I time events with finer resolution than the system
              clock's 55 ms (about 18 ticks a second)?
  <Q:08.03> - How can I find the error level of the previous program?
  <Q:08.04> - How can a program set DOS environment variables?
  <Q:08.05> - How can I change the switch character to - from /?
  <Q:08.06> - How can I write a TSR (terminate-stay-resident utility)?
  <Q:08.07> - Why does my interrupt function behave strangely?
  <Q:08.08> - How can I write a device driver?
  <Q:08.09> - What can I use to manage versions of software?
  <Q:08.10> - What's this 'null pointer assignment' after my C program
              executes?
  <Q:08.11> - How can a batch file tell whether it's being run in a DOS
              box under Windows?
  <Q:08.12> - How can my program tell if it's running under Windows?
  <Q:08.13> - How can a program tell whether ANSI.SYS is installed?
  <Q:08.14> - How do I copyright software that I write?
  <Q:08.15> - How can I place date and time information into environment
              variables?

PART 5: 
Section 9.  Downloading
  <Q:09.01> - What are SimTel and Garbo?
  <Q:09.02> - Can I get archives on CD-ROM?
  <Q:09.03> - Where do I find program <mumble>?

Section 10.  Vendors and products
  <Q:10.01> - How can I contact Borland?
  <Q:10.02> - How can I contact Microsoft?
  <Q:10.03> - What is the current version of DJGPP?
  <Q:10.04> - What and where is DJGPP?
  <Q:10.05> - Are there any good shareware/freeware compilers?
  <Q:10.06> - Where is QBASIC?
  <Q:10.07> - What is a vendor's web site address?

------------------------------

Subject: Section 5. Disks and files
Date: 5 Feb 2002 22:03:03 -0400

 Information about accessing disks and files from MS-DOS.

------------------------------

Subject: <Q:05.01> - What drive was the PC booted from?
Date: 5 Feb 2002 22:03:03 -0400

 Under DOS 4.0 or later, use INT 21 AX=3305. DL is returned with an
 integer indicating the boot drive (1=A:, etc.).

------------------------------

Subject: <Q:05.02> - How can I boot from drive B:?
Date: 8 Feb 2002 19:52:06 -0400

 Downloadable shareware: <http://www.simtel.net/pub/pd/44102.html>
 <ftp://garbo.uwasa.fi/pc/bootutil/boot_b.zip>

 The included documentation says it works by writing a new boot sector on
 a disk in your a: drive that redirects the boot to your B: drive. (A
 similar utility is bboot.zip in the same directory at Garbo only.)

 If that doesn't work, you can always interchange your A: and B: drives
 by switching ribbon cables and changing the setup in your BIOS. From an
 article posted 27 Jan 1993 on another newsgroup:

 [begin quotation]
   Take  the  "ribbon" connector, as you call it, and  switch
   them.  To double-check, start at the end of the cable that
   connects to the motherboard or floppy controller.   Follow
   the  cable until you get to the first connector.   Connect
   this to the drive you want to be B:.
  
   After this, there should be a few lines on the cable  that
   get flipped left to right.  (On most cables, they just cut
   the lines and physically reverse them.  It should be quite
   obvious from looking at the cable.)  Anyway, the connector
   after  the pins get flipped right to left is the connector
   for your a: drive.
 [end quotation]

------------------------------

Subject: <Q:05.03> - Which real and virtual disk drives are valid?
Date: 5 Feb 2002 22:03:03 -0400

 Use INT 21 AH=29 (parse filename). Point DS:SI at a null- terminated
 ASCII string that contains the drive letter and a colon, point ES:DI at
 a 37-byte dummy FCB buffer, and call INT 21 AX=2900. On return, AL is FF
 if the drive is invalid, something else if the drive is valid. RAM disks
 and SUBSTed drives are considered valid.

 You can detect whether the drive is ASSIGNed by using INT 2F AX=0601. To
 check whether the drive is SUBSTed, use INT 21 AX=4409; or use INT 21
 AH=52 to test for both JOIN and SUBST. See Ralf Brown's interrupt list:
 <Q:02.03> [What and where is Ralf Brown's interrupt list?].

 Unfortunately, the b: drive is considered valid even on a
 single-diskette system. You can check that special case by interrogating
 the BIOS equipment byte at 0040:0010. Bits 7- 6 contain the one less
 than the number of diskette drives, so if those bits are zero you know
 that b: is an invalid drive even though function 29 says it's valid.

 Following is some code originally posted by Doug Dougherty to test valid
 drives (treating SUBSTed and JOINed drives as valid), with my fix for
 the b: special case, tested in Borland C++ 4.5 (in the large model):

   #include <dos.h>
   #include <stdio.h>
   
   void drvlist(void)
   {
     char s[3] = "A:", fcb_buff[37];
     int valid;

     for( ;  *s<='Z';  (*s)++)
     {
       _SI = (unsigned) s;
       _DI = (unsigned) fcb_buff;
       _ES = _DS;
       _AX = 0x2900;

       geninterrupt(0x21);
       valid = _AL != 0xFF;

       if (*s == 'B'  &&  valid)
       {
         char far *equipbyte = (char far *)0x00400010UL;
         valid = (*equipbyte & (3 << 6)) != 0;
       }

       printf("Drive '%s' is %sa valid drive.\n", s, valid ? "" : "not ");
     }
   }

 This code was translated to MSC 7.0 and tested it in small model:

   #include <dos.h>
   #include <stdio.h>

   void drvlist(void)
   {
     char s[3] = "A:", fcb_buff[37], *buff=fcb_buff;
     int valid;

     for (   ;  *s<='Z';  (*s)++)
     {
       __asm mov si,s      __asm mov di,buff
       __asm mov ax,ds     __asm mov es,ax
       __asm mov ax,0x2900 __asm int 21h
       __asm xor ah,ah     __asm mov valid,ax

       valid = (valid != 0xFF);

       if (*s == 'B'  &&  valid)
       {
         char far *equipbyte = (char far *)0x00400010UL;
         valid = (*equipbyte & (3 << 6)) != 0;
       }

       printf("Drive '%s' is %sa valid drive.\n", s, valid ? "" : "not");
     }
   }

------------------------------

Subject: <Q:05.04> - How can I make my single floppy drive both a: and
        b:?
Date: 5 Feb 2002 22:03:03 -0400

 Under any DOS since DOS 2.0, you can put the following command into your
 AUTOEXEC.BAT file:

 assign b=a

 Then, when you type "dir b:" you'll no longer get the annoying prompt to
 insert diskette B (and the even more annoying prompt to insert A the
 next time you type "dir a:").

 You may be wondering why anybody would want to do this. Suppose you use
 two different machines, maybe one at home and one at work. One of them
 has only a 3.5" diskette drive; the other machine has two drives, and b:
 is the 3.5" one. You're bound to type "dir b:" on the first one, and get
 the nuisance message:

 Insert diskette for drive B: and press any key when ready.

 But if you assign drive b: to point to a:, you avoid this problem.

 Caution: there are a few commands, such as DISKCOPY, that will not work
 right on ASSIGNed or SUBSTed drives. See the DOS manual for the full
 list. Before typing one of those commands, be sure to turn off the
 mapping by typing "assign" without arguments.

 The DOS 5.0 manual says that ASSIGN is obsolete, and recommends the
 equivalent form of SUBST: "subst b: a:\". Unfortunately, if this command
 is executed when a: doesn't hold a diskette, the command fails. ASSIGN
 doesn't have this problem, so under DOS 5.0 you should disregard that
 particular bit of advice in the manual.

------------------------------

Subject: <Q:05.05> - How can I disable access to a drive?
Date: 8 Feb 2002 19:53:23 -0400

 Reader Eric DeVolder writes that he has made available a program to do
 this. I haven't tried it, but it's downloadable from
 <http://www.simtel.net/pub/pd/44403.html>

 Reader Igor Karp reports that MS-DOS version 5.0 and greater provides
 two interrupts to do this.

   --------D-215F07-----------------------------
   INT 21 - DOS 5+ - ENABLE DRIVE
      AX = 5F07h
      DL = drive number (0=A:)
   Return: CF clear if successful
      CF set on error
      AX = error code (0Fh) (see #0885 at AH=59h)
   Notes:   simply  sets the "valid" bit in the  drive's  CDS
   this function is not supported by Novell DOS 7
   See Also: AH=52h,AX=5F08h"DOS"

   --------D-215F08-----------------------------
   INT 21 - DOS 5+ - DISABLE DRIVE
      AX = 5F08h
      DL = drive number (0=A:)
   Return: CF clear if successful
      CF set on error
      AX = error code (0Fh) (see #0885 at AH=59h)
   Notes:   simply clears the "valid" bit in the drive's  CDS
   this function is not supported by Novell DOS 7

------------------------------

Subject: <Q:05.06> - How can a batch file test existence of a directory?
Date: 8 Feb 2002 19:54:04 -0400

 The standard way, which in fact is documented in the DOS manual, is:

 if exist d:\path\nul goto found

 Unfortunately, this is not entirely reliable. I found it failed in
 Pathworks (a/k/a PCSA, DEC's network that connects PCs and VAXes), or on
 a MARS box that uses an OEM version of MS-DOS 5.0. Readers have reported
 that it gave the wrong answer on Novell networks, on DR-DOS, and in a
 DOS window under OS/2. By "failed" I mean that it "found" a directory
 that didn't exist, or failed to find one that did exist, or both. (It
 has been reported that IBM fixed the OS/2 bug in version 2.11 of OS/2.)
 As a legacy from earlier versions of DOS it always succeeds if the path
 is DEV.

 There appears to be no foolproof way to use pure batch commands to test
 for existence of a directory. The real solution is to write a program,
 which returns a value that your batch program can then test with an "if
 errorlevel". Reader Duncan Murdoch kindly posted the following Turbo
 Pascal version:

   program existdir;
   { Confirms  the  existence of a directory  given  on  the
     command  line.  Returns errorlevel 2 on error,  1  if  not
     found, 0 if found. }
  
   uses dos;
  
   var
     s : searchrec;
  
   begin
     if paramcount <> 1 then
       begin
         writeln('Syntax:  EXISTDIR directory');
         halt(2);
       end
     else
       begin
         findfirst(paramstr(1),Directory,S);
         while (Doserror = 0) and ((Directory and S.Attr) =  0) do
           findnext(S);
  
        if Doserror <> 0 then
          begin
            Writeln('Directory not found.');
            halt(1);
          end
        else
          begin
            Writeln('Directory found.');
            halt(0);
          end;
       end;
   end.

 Timo Salmi also has a Turbo Pascal version in his Turbo Pascal FAQ,
 which is downloadable as <ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip>

------------------------------

Subject: <Q:05.07> - Why won't my C program open a file with a path?
Date: 5 Feb 2002 22:03:03 -0400

 You've probably got something like the following code:

   char *filename = "c:\foo\bar\mumble.dat";
   FILE *fptr;
   /*.*/
   fptr = fopen(filename, "r");

 The problem is that \f is a form feed, \b is a backspace, and \m is m.
 Whenever you want a backslash in a string constant in C, you must use
 two backslashes:

 char *filename = "c:\\foo\\bar\\mumble.dat";

 This is a feature of every C compiler, because Dennis Ritchie designed C
 this way. It's a problem only on MS-DOS systems, because only DOS (and
 Atari ST/TT running TOS) uses the backslash in directory paths. But even
 in DOS this backslash convention applies _only_ to string constants in
 your source code. For file and keyboard input at run time, \ is just a
 normal character, so users running your program would type in file specs
 the same way as in DOS commands, with single \ characters.

 Another possibility is to code all paths in source programs with /
 rather than \ characters:

 char *filename = "c:/foo/bar/mumble.dat";

 Ralf Brown writes, "All versions of the DOS kernel accept either forward
 or backslashes as directory separators. I tend to use this form more
 frequently than backslashes since it is easier to type and read." This
 applies to DOS function calls (and therefore to calls to the file
 library of every programming language), but not to DOS commands.

------------------------------

Subject: <Q:05.08> - How can I redirect printer output to a file?
Date: 8 Feb 2002 19:55:31 -0400

 Recommended: PRN2FILE from PC Magazine, downloadable as:
 <http://www.simtel.net/pub/pd/49066.html>

 PRN2FILE contains ASM source code. PC Magazine has given copies away as
 part of its utilities disks, so you may already have a copy.

 The directories mentioned above have lots of other utilities to redirect
 printer output.

------------------------------

Subject: <Q:05.09> - How can I redirect the output of a batch file?
Date: 7 Feb 2002 14:48:46 -0400

 Assuming the batch file is called batch.bat, to send its output (stdout)
 to another file, just invoke COMMAND.COM as a secondary command
 processor:

 command /c batch parameters_if_any >outfile

 Timo Salmi's notes on this and other batch tricks are downloadable from:
 <ftp://garbo.uwasa.fi/pc/link/tsbat.zip>

 A reader of comp.os.msdos.programmer has created a utility that can
 capture batch file output. It can be found at:
 <http://www.simtel.net/pub/dl/11141.shtml>

------------------------------

Subject: <Q:05.10> - How can I redirect stderr?
Date: 8 Feb 2002 19:58:21 -0400

 Use freopen(..., stderr) and then execute the desired command via
 system(). There are downloadable versions of programs to do this.

 This file includes TP4 source and an executable:
 <http://www.simtel.net/pub/pd/50430.html>

 A C example is downloadable as:
 <http://www.simtel.net/pub/pd/41772.html>

 I compiled it with MSC 7.0, and it works fine with one exception:
 Contrary to the included comments, redirected output starts writing at
 the beginning of the output file rather than appending. That is easily
 solved by adding "fseek(stderr, 0L, SEEK_END);" after the freopen() call
 for stderr.

 A reader comp.os.msdos.programer has created a utilitiy that can capture
 console output. It can be found at:
 <http://www.simtel.net/pub/dl/11141.shtml>

------------------------------

Subject: <Q:05.11> - How can my program open more files than DOS's limit
        of 20?
Date: 5 Feb 2002 22:03:03 -0400

 This is a summary of an article Ralf Brown posted on 8 August 1992, with
 some additions from a Microsoft tech note and information from Chin
 Huang.)

 DOS imposes some limits. Once you overcome those, which is pretty easy,
 you may have to take additional measures to overcome the limitations
 built into your compiler's run- time library.

 1) Limitations imposed by DOS:

 There are separate limits on files and file handles. For example, DOS
 opens three files but five file handles: CON (stdin, stdout, and
 stderr), AUX (stdaux), and PRN (stdprn).

 The limit in FILES= in CONFIG.SYS is a system-wide limit on files opened
 by all programs (including the three that DOS opens and any opened by
 TSRs); each process has a limit of 20 handles (including the five that
 DOS opens). Example: CONFIG.SYS has FILES=40. Then program #1 will be
 able to open 15 file handles. Assuming that the program actually does
 open 15 handles pointing to 15 different files, other programs could
 still open a total of 22 files (40-3-15 = 22), though no one program
 could open more than 15 file handles. If you're running DOS 3.3 or
 later, you can increase the per-process limit of 20 file handles by a
 call to INT 21 AH=67, Set Handle Count. Your program is still limited by
 the system-wide limit on open files, so you may also need to increase
 the FILES= value in your CONFIG.SYS file (and reboot). The run-time
 library that you're using may have a fixed-size table of file handles,
 so you may also need to get source code for the module that contains the
 table, increase the table size, and recompile it.

 2) Limitations in Microsoft C run-time library:

 In Microsoft C the run-time library limits you to 20 file handles. To
 change this, you must be aware of two limits:

 File handles used with _open(), _read(), etc.: Edit _NFILE_ in
 CRT0DAT.ASM.

 Stream files used with fopen(), fread(), etc.: Edit _NFILE_ in _FILE.C
 for DOS or FILE.ASM for Windows/QuickWin. This must not exceed the value
 of _NFILE_ in CRT0DAT.ASM. (QuickWin uses the constant _WFILE_ in
 CRT0DAT.ASM and WFILE.ASM for the maximum number of child text windows.)

 After changing the limits, recompile using CSTARTUP.BAT. Microsoft
 recommends that you first read README.TXT in the same directory.

 3) Limitations in Borland C++ run-time library:

 (Reader Chin Huang provided this information on 12 Sep 1993.) To
 increase the open file limit for a program you compile with Borland C++
 3.1, edit the file _NFILE.H in the include directory and change the
 _NFILE_ value. Compile and link the modules FILES.C and FILES2.C from
 the lib directory into your program.

------------------------------

Subject: <Q:05.12> - How can I read, create, change, or delete the volume
        label?
Date: 5 Feb 2002 22:03:03 -0400

 In DOS 5.0 (and possibly in 4.0 as well), there are actually two volume
 labels: the LABEL command reports only the first but changes both of
 them.

 * The traditional volume label is an entry with "volume label" attribute
   in the root directory of the disk. The DIR, VOL, and LABEL commands
   report this volume label, and LABEL sets it.

 * There is a second volume label, which may be different, in the boot
   record along with the serial number. In DOS 4.0 and later, INT 21
   AH=69 gets or sets the boot record's serial number and volume label
   together; see <Q:05.13> [How can I get the disk serial number?] DIR
   and VOL ignore this volume label; the LABEL command doesn't report it
   but does set it.

 The rest of this answer assumes that by "volume label" you mean the
 traditional one, the one that DIR and VOL display. Though it's a
 directory entry in the root directory, you can't change it using the
 newer DOS file-access functions (INT 21 AH=3C, 41, 43); instead, use the
 old FCB-oriented directory functions. Specifically, you need to allocate
 a 64-byte buffer and a 41- byte extended FCB (file control block). Call
 INT 21 AH=1A to find out whether there is a volume label. If there is,
 AL returns 0 and you can change the label using DOS function 17 or
 delete it using DOS function 13. If there's no volume label, function 1A
 will return FF and you can create a label via function 16. Important
 points to notice are that ? wildcards are allowed but * are not; the
 volume label must be space filled not null terminated.

 The following MSC 7.0 code worked for me in DOS 5.0; the functions it
 uses have been around since DOS 2.0. The function parameter is 0 for the
 current disk, 1 for a:, 2 for b:, etc. It doesn't matter what your
 current directory is; these functions always search the root directory
 for volume labels. (I didn't try to change the volume label of any
 networked drives.)

   // Requires DOS.H, STDIO.H, STRING.H

   void vollabel(unsigned char drivenum)
   {
     static  unsigned  char  extfcb[41],  dta[64],  status,  *newlabel;
     int chars_got = 0;

     #define DOS(buff,func) __asm { __asm mov dx,offset buff  \
       __asm mov ax,seg buff  __asm push ds  __asm mov ds,ax  \
       __asm  mov  ah,func   __asm int  21h   __asm  pop  ds  \
       __asm mov status,al }

     #define getlabel(buff,prompt) newlabel = buff;  \
       memset(newlabel,' ',11);  printf(prompt);   \
       scanf("%11[^\n]%n", newlabel, &chars_got);  \
       if (chars_got < 11) newlabel[chars_got] = ' ';

     // Set up the 64-byte transfer area used by function 1A.
     DOS(dta, 1Ah)
  
     //  Set  up  an extended FCB and search for the  volume label.
     memset(extfcb, 0, sizeof extfcb);
     extfcb[0] = 0xFF;           // denotes extended FCB
     extfcb[6] = 8;              // volume-label attribute  bit
     extfcb[7] = drivenum;       // 1=A,2=B,...; 0=current drive
  
     memset(&extfcb[8], '?', 11);// wildcard *.*
     DOS(extfcb,11h)
     if(status == 0)
     {                           // DTA has volume  label's FCB
       printf("volume label is %11.11s\n", &dta[8]);
       getlabel(&dta[0x18], "new label (\"delete\" to delete): ");
      
       if(chars_got==0)
         printf("label not changed\n");
       else if (strncmp(newlabel,"delete  ",11) == 0)
       {
         DOS(dta,13h)
         printf(status ? "label failed\n":"label deleted\n");
       }
       else
       {                  // user wants to change label
         DOS(dta,17h)
         printf(status ? "label failed\n" : "label changed\n");
       }
     }
     else
     {                      // no volume label was found
       printf("disk has no volume label.\n");
       getlabel(&extfcb[8], "new label (<Enter>  for  none): ");

       if (chars_got > 0)
       {
         DOS(extfcb,16h)
         printf(status ? "label failed\n" : "label created\n");
       }
     }
   } // end function vollabel

------------------------------

Subject: <Q:05.13> - How can I get the disk serial number?
Date: 5 Feb 2002 22:03:03 -0400

 If the disk was formatted by DOS 4.0 or later, use INT 21: AX=6900 gets
 the serial number; AX=6901 sets it. (The disk serial number doesn't
 exist if the disk was formatted with an earlier version of DOS, or with
 some third-party formatters.) See Ralf Brown's interrupt list (<Q:02.03>
 [What and where is Ralf Brown's interrupt list?]), or PC Magazine July
 1992 (xi:13) page 496, for details.

 INT 21 AH=69 also gets and sets the volume label in the boot record,
 which is not necessarily the same as "the" volume label displayed by the
 DIR, VOL, and LABEL commands. For that volume label, see <Q:05.12> [How
 can I read, create, change, or delete the volume label?]

------------------------------

Subject: <Q:05.14> - What's the format of .OBJ, .EXE., .COM files?
Date: 5 Feb 2002 22:03:03 -0400

 Please see <Q:03.06> [What's the format of an .OBJ file?]; <Q:03.07>
 [What's the format of an .EXE header?]; and <Q:03.08> [What's the
 difference between .COM and .EXE formats?]

------------------------------

Subject: <Q:05.15> - How can I flush the software disk cache?
Date: 5 Feb 2002 22:03:03 -0400

 Please see <Q:08.01> [How can a program reboot my PC?] (Trust me.)

------------------------------

Subject: <Q:05.16> - How can I see if a drive is a RAM drive?
Date: 5 Feb 2002 22:03:03 -0400

 Use INT 21 AX=4409h. See Ralph Brown's interrupt list (<Q:02.03> [What
 and where is Ralf Brown's interrupt list?]) for more information.

------------------------------

Subject: <Q:05.17> - How can I determine a hard drive's manufacturer?
Date: 5 Feb 2002 22:03:03 -0400

 Information about the hard drive's manufacturer is retrieved by using
 the ATA and ATAPI specifications. Please see "<Q:05.18> [Where can I
 find information about the ATA/ATAPI specification?]

------------------------------

Subject: <Q:05.18> - Where can I find information about the ATA/ATAPI
        specification?
Date: 5 Feb 2002 22:03:03 -0400

 The AT Attachment (ATA) standard is maintained by T13, a Technical
 Committee for the National Committee on Information Technology Standards
 which as accredited by ANSI. Their web site can be found at
 <http://www.t13.org>. At that web site the ATA and ATAPI specifications
 are availible in PDF form.

------------------------------

Subject: <Q:05.19> - How can I copy files to or from filenames containing
        date information?
Date: 7 Feb 2002 14:26:15 -0400

 You can use the NOWMINUS program. This program creates environment
 variables containing date and time information. See <Q:08.15> [How can I
 place date and time information into environment variables?] for more
 information.

 Here is an example of using NOWMINUS to rename the files thisweek.* to
 {lastweeksdate}.*:

        NOWMINUS d7 z7 f1 j0 vLASTWEEK
        ren thisweek.* %LASTWEEK%.*
        set LASTWEEK=

------------------------------

Subject: Section 6. Serial ports (COM ports)
Date: 5 Feb 2002 22:03:03 -0400

 This section provides information about how to access the serial ports.
 In the future I will be working on adding information about using MS-DOS
 for networking and internet access.

------------------------------

Subject: <Q:06.01> - How do I set my machine up to use COM3 and COM4?
Date: 5 Feb 2002 22:03:03 -0400

 Unless your machine is fairly old, it's probably already set up. After
 installing the board that contains the extra COM port(s), check the I/O
 addresses in word 0040:0004 or 0040:0006. (In DEBUG, type "D 40:4 L4"
 and remember that every word is displayed low byte first, so if you see
 "03 56" the word is 5603.) If those addresses are nonzero, your PC is
 ready to use the ports and you don't need the rest of this answer.

 If the I/O address words in the 0040 segment are zero after you've
 installed the I/O board, you need some code to store these values into
 the BIOS data segment:

   0040:0004  word  I/O address of COM3
   0040:0006  word  I/O address of COM4
   0040:0011   byte  (bits  3-1):  number  of  serial   ports installed

 The documentation with your I/O board should tell you the port
 addresses. When you know the proper port addresses, you can add code to
 your program to store them and the number of serial ports into the BIOS
 data area before you open communications. Or you can use DEBUG to create
 a little program to include in your AUTOEXEC.BAT file, using this
 script:

   n  SET_ADDR.COM     <--- or a different name  ending in .COM
   a 100
   mov  AX,0040
   mov  DS,AX
   mov  wo [0004],aaaa <--- replace aaaa with COM3 address or 0
   mov  wo [0006],ffff <--- replace ffff with COM4 address or 0
   and  by [0011],f1
   or    by [0011],8   <--- use number of serial ports times 2
   mov  AH,0
   int  21
                         <--- this line must be blank
   rCX
   1f
   rBX
   0
   w
   q

------------------------------

Subject: <Q:06.02> - How do I find the I/O address of a COM port?
Date: 8 Feb 2002 20:00:09 -0400

 Look in the four words beginning at 0040:0000 for COM1 through COM4.
 (The DEBUG command "D 40:0 L8" will do this. Remember that words are
 stored and displayed low byte first, so a word value of 03F8 will be
 displayed as F8 03.) If the value is zero, that COM port is not
 installed (or you've got an old BIOS; see <Q:06.01> [How do I set my
 machine up to use COM3 and COM4?]). If the value is nonzero, it is the
 I/O address of the transmit/receive register for the COM port.

 Each COM port occupies eight consecutive I/O addresses (though many
 chips use only the first seven).

 Here's some C code to find the I/O address:

   unsigned ptSel(unsigned comport)
   {
     unsigned io_addr;
  
     if (comport >= 1  &&  comport <= 4)
     {
       unsigned far *com_addr = (unsigned far *)0x00400000UL;
       io_addr = com_addr[comport-1];
     }
     else
       io_addr = 0;
  
     return io_addr;
   }

 You might also want to explore Port Finder, downloadable as:
 <http://www.simtel.net/pub/pd/47138.html>

 I haven't tried it myself, but a posted article reviewed it very
 favorably and said it also lets you swap ports around.

------------------------------

Subject: <Q:06.03> - But aren't the COM ports always at I/O addresses
        3F8, 2F8, 3E8, and 2E8?
Date: 5 Feb 2002 22:03:03 -0400

 The first two are usually right (though not always); the last two are
 different on many machines.

------------------------------

Subject: <Q:06.04> - How do I configure a COM port and use it to transmit
        data?
Date: 8 Feb 2002 20:03:52 -0400

 Do you want actual code, or do you want books that explain what's going
 on?

 1) Source code

 First, check your compiler's run-time library. Many compilers offer
 functions similar to Microsoft C's _bios_serialcom() or Borland's
 bioscom(), which may meet your needs.

 Second, check for downloadable resources at SimTel and Garbo. At SimTel,
 <http://www.simtel.net/pub/pd/41750.html> (March 1993) is described as
 "Asynchronous communications library for C"; Garbo has a whole
 <ftp://garbo.uwasa.fi/pc/comm> directory. Also, an extended example is
 in Borland's TechFax TI445, downloadable as part of:
 <http://www.simtel.net/pub/pd/50843.html>
 <ftp://garbo.uwasa.fi/pc/c-lang/bchelp10.zip>

 Though written by Borland, much of it is applicable to other forms of C,
 and it should give you ideas for other programming languages.

 Third, SNIPPETS (see <Q:02.08> [What and where is SNIPPETS?]) contains a
 sample interrupt-driven serial communications library.

 2) Reference books

 Highly recommended: Joe Campbell's {C Programmer's Guide to Serial
 Communications}, ISBN 0-672-22584-0. He gives complete details on how
 serial ports work, along with complete programs for doing polled or
 interrupt-driver I/O. The book is quite thick, and none of it looks like
 filler.

 If Campbell's book is overkill for you, you'll find a good short
 description of serial I/O in {DOS 5: A Developer's Guide}, ISBN
 1-55851-177-6, by Al Williams.

 Finally, a reader has recommended {Serial Communications Programming in
 C/C++} by Mark Goodwin (ISBN 1-55828-198-3), with source code in the
 book and on disk. Topics include the basics, various methods of serial
 communications on the PC (with consideration of high-speed modems), ANSI
 screen interface, file transfer protocols (Xmodem and Ymodem), etc.
 There is code in C, and that code is extended into a C++ class for those
 who use C++. There are also subroutines in Assembly.

 3) Downloadable information files

 A "Serial Port FAQ" is occasionally posted to this newsgroup, and is
 downloadable as multiple files:

 <ftp://ftp.phil.uni-sb.de/pub/people/chris/>

 This directory contains a series of files beginning with Serial_Port.

------------------------------

Subject: Conclusion

This is the end of part 3 of 5 parts.

This text is copyright 2003 by Jeffrey Carlyle. All rights reserved.
Please see the top of this article for additional copyright information.