BDS C User's Guide Addenda
                      v1.45 Edition --  December, 1981

                                 Leor Zolman
                                 BD Software
                               33 Lothrop st.
                       Brighton, Massachussetts 02135


Here are the bug fixes and extensions for BDS C version 1.45.

Note: If you are running under MP/M II, be sure to see item 10 below!




0.   Expressions of the form

            !(expr || expr)
       or   !(expr && expr)

    may  not  have  worked  correctly  when  a  VALUE  was  required  for  the
    expression; i.e., when used in some way other than in a flow control test.
    For example,

            x = !(a || b);

    might have failed, but

            if (!(a || b)) return 7;

    would have worked, since the expression was used for flow control.


1.   Declarations  of  pointer-to-function  variables for functions returning a
    CHARACTER value caused only one byte of  storage  to  be  reserved for the
    pointer, instead of two bytes (all pointers-to-functions require two bytes
    of storage, by virtue of being pointers). For example, in the sequence:

            char c1, (*ptrfn)(), c2;
            ...
            ptrfn = &getc;

    the  assignment  to  `ptrfn' would have incorrectly overwritten  the  `c2'
    character variable, since  only  one  byte would have been reserved on the
    stack for the `ptrfn' variable while the  assignment  operation would have
    assumed there were two bytes reserved.


2.   A  bug  in  the  ternary  operator evaluator (?: expressions)  caused  the
    high-order  byte of a 16-bit  result  to  be  incorrectly  zeroed  in  the
    following situation: given a ternary expression of the form

            e1 ? e2 : e3

    where `e2' evaluated to a 16-bit value (int, unsigned or pointer) and `e3'
    evaluated to a character value (type char only), the entire expression was
    treated as having type char...so if `e1' was true and `e2' was bigger than
    255, then the  value of the expression ended up as only the low-order byte
    of the value of `e2'. For version 1.45, whenever `e2' and `e3' do not BOTH
    evaluate to character  values  the  type  of  the  overall  expression  is
    guaranteed not to be char.


3.   A  sequence  of  two `!' (logical `not') operators in a row did not always
    produce the correct result in an expression. For example,

            x = !!n;                /* convert n to a logical (0 or 1) value */

    might have produced the wrong result (0 instead of 1, or vice-versa).


4.   A  stack-handling  bug   in  CC2  caused  problems  at  run  time  when  a
    sufficiently complex sub-expression appeared in any but the final position
    of an expression involving  the  comma  operator  (",").  For example, the
    following statement would not have worked correctly:

            for (i = 0; i < 10; x += y, i++) ...



5.   CC1  has not been recognizing illegal octal character constants  as  such;
    digits such as `8' and `9' within an octal constant will now draw an error
    in cases  where  they  would have been ignored before. Also, certain other
    forms of illegal constants (aside from character constants) are now better
    diagnosed than before.


6.   I  found  one more case where  an  internal  table  overflow  during  code
    generation  was  not  detected,  causing the final command file to bomb as
    soon as it was executed (either by  crashing  the  machine  or immediately
    re-booting.)  This  occurred when a single large function containing  many
    string constants was compiled. All fixed now.


7.   An  extension  to the linker:  CLINK  now  recognizes  "DEFF3.CRL"  as  an
    automatic library file, similar to DEFF.CRL and DEFF2.CRL. Note that there
    is NO DEFF3.CRL  file  included  with  the BDS C package; this feature has
    been added to allow you to fit more custom  functions  into  your  library
    than  just  what  fits in DEFF.CRL and DEFF2.CRL (which are getting rather
    full.)

    Also, CLINK will now search ALL default library files (DEFF.CRL, DEFF2.CRL
    and  DEFF3.CRL  [if  it  exists])  when  a  carriage-return  is  typed  in
    interactive mode.  Previously,  only  the  file  DEFF.CRL  was searched in
    response to carriage-return.


8.   It  has been brought to my attention that the ^Q-CR sequence  required  by
    CLINK  in  interactive  mode  (to abort the linkage in progress) cannot be
    typed in under MP/M systems, since  ^Q is used to detach a process. If you
    are running MP/M, then just type control-C  instead  of  ^Q-CR;  this will
    also  work  for  CP/M systems...the only difference is that when ^Q-CR  is
    used, then any currently  active "submit file" processing is automatically
    aborted by CLINK before returning  to  command  level, as a convenience (I
    assume that if you abort the linkage, you don't want to continue with your
    submit file...). Under MP/M, you'll have to type characters quickly at the
    keyboard (after ^C-ing CLINK) to abort any pending  submit  file activity.


9.   A slight bug in CLIB.COM (The C Library manager program) made  it  hard to
    exit  CLIB  from  within  a  submit  file  (assuming XSUB is in use).  The
    problem was that CLIB requires a confirmation  character, `y', to be typed
    after  the  `quit'  command is given.  CLIB was getting  the  confirmation
    character by doing a single direct BDOS console input call, which required
    the user to manually  type  in  the  letter before any pending submit file
    processing could continue. This has been  fixed  by  having  CLIB  get  an
    entire  line  of  input  (using BDOS call 10) when seeking a confirmation;
    now the `y' may be inserted  into  submit  files.  Note  that  the  `quit'
    command  and  the  `y' confirmation must be placed on separate consecutive
    lines in the submit  file. If not using a submit file, the only difference
    is that now a carriage-return is required after typing the `y'.

    Another minor problem  with  CLIB: function names longer than 8 characters
    were not being truncated when  entered  for  operations  such as renaming,
    resulting  in  too-long  CRL  file  directory entries. All names  are  now
    properly limited to 8 characters.


10.  A problem with file I/O under MP/M Version  II  has  come up: The run-time
    package routine "vclose", called by the library function  "close" whenever
    a  file  needs to be closed, has been optimizing for files open  only  for
    reading by  NOT  actually performing a "close" operation through the BDOS.
    This worked fine under  CP/M,  because  CP/M  didn't care whether or not a
    file that has had no changes made to it was ever  closed;  MP/M II, on the
    other  hand, DOES seem to want such files to be explicitly closed...so  by
    running  many  programs  that  didn't  close  their Read-only files, BDS C
    programs eventually caused MP/M to not allow any  more files to be opened.

    This  problem  has  been  fixed by adding a conditional  assembly  symbol,
    called "MPM2", to the CCC.ASM  source  file. If you are running under MP/M
    II, you should set the "MPM2" equate to  true  (1) and reassemble CCC.ASM,
    yielding  a new C.CCC after loading and renaming  (you  should  only  need
    ASM.COM for this, although MAC.COM works also). The change does NOT affect
    the size of  C.CCC,  so  the libraries do not have to be reassembled as is
    usually the case when the  run-time  package  is  customized.  The  change
    simply causes a single conditional jump to be turned into three nop's,  so
    that  ALL  files  are  always  closed,  instead  of only the ones open for
    writing.  My apologies to MP/M users who may have had  confusing  troubles
    because of this bug.


11.  A bug was found in the `_scn' library function (affecting `scanf'): when a
    lone carriage-return  (newline)  was  typed  in  response to a "%s" format
    conversion, the format conversion was totally ignored.    This  caused the
    target  string to remain unchanged from its previous contents, instead  of
    correctly having a null string (consisting of a single zero byte) assigned
    to it.


12.  A bug was  found  in  the  `_spr'  library  function  (affecting `printf',
    `sprintf', and `fprintf'): The default field width value  was 1, causing a
    null string to be printed as a single space when the standard  "%s" format
    conversion was used. For example, the statement:

            printf("Here is a null string: \"%s\"\n","");

    would have produced the output:

            Here is a null string: " "

    instead of:

            Here is a null string: ""

    The default field width value has been changed to 0, so null strings  will
    now  print  correctly.  An explicit field width may always be given in any
    format conversion, of course.


13.  When the library function  "sprintf"  (formatted  output  directly  into a
    memory buffer) is used, a null byte is appended onto the end of the output
    text.  I'm  not  absolutely  sure  whether  or  not  this  is  a "desired"
    characteristic;  at  least one user has complained about it, but it  turns
    out that "sprintf" on  the  large-scale  Unix system I have access to does
    the same thing and I can think of applications  where the trailing null is
    useful. So, the null stays in.


14.  In  several  library functions, as well as at one point  in  the  run-time
    package, calls  were  made to BDOS function number 11 (interrogate console
    status) followed by an  "ani  1"  instruction  to  test bit 0 of the value
    returned by BDOS. I've been told that on some systems,  testing  bit  0 is
    not  sufficient  since  sometimes values other than 0 and 1 (or 0 and 255)
    are returned. SO, all such  sequences  have  been changed to do an "ora a"
    instead  of  an  "ani  1",  so  that  a return value  of  exactly  00h  is
    interpreted as "no character ready" and  any other value is interpreted as
    "yes,  there  is  a  character  ready". The library  functions  that  were
    modified this way are: `kbhit', `putchar',  `srand1', `nrand', `sleep' and
    `pause'.  The sequence to clear console status  in  the  run-time  package
    (CCC.ASM),  near the label "init:", has likewise been changed (but a "nop"
    instruction was  added  to  keep  all  addresses  consistent  with earlier
    versions of the run-time package.)


15.  When  customizing  the  run-time  package (CCC.ASM) with the "cpm"  symbol
    equated  to zero, several symbols (named  "SETNM"  and  "SETNM3",  at  the
    routine labeled  "PATCHNM") were undefined;  this has been fixed by adding
    some conditional assembly directives to insure that the labels in question
    are not referenced  under  non-"cpm" implementations, while the total code
    size remains constant so that  the  addresses  of  later  run-time package
    utility subroutines stay exactly the same for all implementations.


16.  A  problem  with  the "bdos" library function has come up that  is  rather
    tricky, since it is  system-dependent: A program that runs correctly under
    a normal Digital Research CP/M system might NOT run under MP/M or SDOS (or
    who knows how many other  systems)  if  the  "bdos"  function  is  used. A
    typical symptom of this problem is that upon character output, a character
    on  the  keyboard needs to be hit once in order to make each character  of
    output appear.

    To understand  the  problem,  we must first understand exactly how the CPU
    registers are supposed to be set  after  an  operating  system  BDOS call.
    Normal  CP/M  behavior  (which  the  C  library function "bdos" had always
    assumed) is for registers A and L to contain  the  low-order  byte  of the
    return value, and for registers B and H to contain the high order byte  of
    a  return  value (which is zero if the return value is only one byte). The
    CP/M interface guide explicitly states that "A == L and B == H upon return
    in all cases",  and  I  figured  that  just in case CP/M 1.4 or some other
    system didn't put the values in H and L  from B and A, I'd have the "bdos"
    function copy register A into register L and copy register B into register
    H, to make SURE the value is in HL (where  the return value must always be
    placed by a C library function.)

    Not  all systems actually FOLLOW this convention.  Under  MP/M,  H  and  L
    always  contain the correct value but B does not! So when B is copied into
    H, the wrong  value  results.  So,  the way to make "bdos" work under both
    CP/M 2.2 and MP/M was to discontinue  copying  B  and  A into H and L, and
    just assume the value will always be correctly left in HL  by  the system.
    This  was  done  for  v1.45, so at least CP/M and MP/M are taken care  of,
    but...

    Under SDOS (and perhaps  other  systems), register A is sometimes the ONLY
    register to contain a meaningful  return  value.  For example, upon return
    from a function 11 call (interrogate console  status),  the  B,  H  and  L
    registers  were all found to contain garbage.  So if no copying is done in
    this case, the  return  value  never  gets  from  A to L and the result is
    wrong;  but if B is copied into H along with A getting  copied into L, the
    result is still wrong because B contains garbage.  Evidently  the only way
    to get function 11 to work right under SDOS is to have the "bdos" function
    copy  register A into L and ZERO OUT the H register before returning...but
    then many  other  system  calls  which  return  values  in H wouldn't work
    anymore.  And  that  is the problem: You can please SOME systems  ALL  the
    time, but not ALL systems  all  the  time  with  only  one standard "bdos"
    function!

    The way I left "bdos" for version 1.45 was so that it works  with CP/M and
    MP/M (i.e., no register copying is done at all...HL is assumed  to contain
    the  correct  value).  You  might  want to make a note in the User's Guide
    library section (page 30) to the effect  that  A  and  B  are now ignored.
    This,  of  course,  won't  work in all cases under SDOS and perhaps  other
    systems...in those cases, you  need  to  either use the "call" and "calla"
    functions  to  perform the BDOS call, or create  your  own  assembly-coded
    version(s) of the  "bdos" function (with MAC.COM, CMAC.LIB and BDS.LIB) to
    perform the correct  register manipulation sequences for your system. Note
    that it may take more  than one such function to cover all possible return
    value register configurations.


17.  The "creat" library function  had been creating new files and opening them
    for writing ONLY; this caused some confusion, so `creat' has been modified
    to open files for both reading  AND  writing  following  creation.  PLEASE
    MAKE  A  NOTE  OF  THIS  UNDER  THE `CREAT' ENTRY IN THE STANDARD  LIBRARY
    SECTION OF THE BDS C USER'S GUIDE.


18.  The "execv" function has been changed  to  return  ERROR  (-1)  on  error,
    instead  of forcing an error message ("Broken pipe") to be printed to  the
    standard error  device.  The  reason  I originally had it printing "Broken
    Pipe" was because I was too lazy to figure  out how to fix the stack after
    passing all the arguments; following some justified  bitching  from  Scott
    Layson  I  went  in  there  and  fixed it so it does something reasonable.
    PLEASE MAKE A NOTE OF THIS UNDER THE `EXECV' ENTRY IN THE STANDARD LIBRARY
    SECTION OF THE B
DS C USER'S GUIDE.


19.  The DIO (directed I/O and pipes) package  contained  an  obscure bug: if a
    pipe operation was aborted before completion, leaving a "TEMPIN.$$$"  file
    in  the  directory,  then the next pipe operation performed had gotten its
    own output mixed up with  the output of the aborted pipe....the old output
    was used as input to the new  next  command,  and the new output was lost.
    The new DIO.C has been fixed. (Note: DIO.C has  also been slightly changed
    to  properly  interact  with  the  new  version  of  the  "execv"  library
    function.)


20.  Another  change has been made to the DIO package: the "getchar"  function,
    when used  without  input redirection to read characters directly from the
    console, had not allowed for line editing in previous versions. I.e., each
    character was obtained  by a direct BDOS call and none of the special line
    editing characters (delete,  ^R,  ^U,  etc.)  were recognized. For version
    1.45, an optional line buffer mechanism has been  added to the DIO package
    so lines of console input can be fetched at one time  by  using  the "read
    console  buffer"  BDOS  call  and  all editing characters now function  as
    expected.  Operation of the package  using buffered console input is still
    the  same  as  before,  except  for one thing:  to  enter  an  end-of-file
    character (control-Z), it is now  necessary to also type a carriage-return
    after the control-Z.

    To  enable console input buffering when  using  the  DIO  library,  it  is
    necessary to un-comment a line in the DIO.H file and re-compile DIO.C. See
    the comments in DIO.C for more information.


21.  The special  case handler for the code generator has been improved to more
    efficiently handle  relational  binary operations where exactly one of the
    operands  is  a constant. The operators  affected  are:  "<",  ">",  "<=",
    ">=","=="  and  "!=",  for  both  signed  and  unsigned  data  types.  The
    improvement is mainly  in  the  speed  of  execution  of such comparisons;
    statements such as:

            if (i < 1234) ...

    execute much faster. This results in speedier execution  of  programs such
    as the Seive of Eratosthenes benchmark in the September '81 issue of BYTE:
    the  current  version of BDS C, using the -e and -o compiler options  with
    variables made  external,  does  it  in  15.2  seconds (see SIEVE.C on the
    distribution disk.)

    Also, multiplication by a constant that is a low  power of 2 (2,4,8,16) is
    now  done  by  DAD  H sequences instead of calls to the  run-time  package
    multiply routine [so  that  expressions  such as (i * 8) and (i << 3) each
    compile to the same code].


22.  Two new functions have been added to the standard library:

       int setjmp(buffer)
       char buffer[JBUFSIZE];

       longjmp(buffer,val)
       char buffer[JBUFSIZE];

    When "setjump" is called, the current processor  state  is  saved  in  the
    JBUFSIZE-byte  buffer  area  whose  address  is  passed  as  the  argument
    ("JBUFSIZE"  is  defined  in  BDSCIO.H),  and a value of zero is returned.
    Whenever a subsequent "longjump" call is performed  (from  ANYWHERE in the
    current  function  or  any  lower-level  function)  with  the same  buffer
    argument,  the  CPU  state  is  restored  to that which it was during  the
    "setjmp" call, and the program behaves as if  control  were just returning
    from  the  "setjmp" function, except that the return value  this  time  is
    "val" as passed  to "longjmp".  A typical use of setjmp/longjmp is to exit
    up through several  levels  of  function  nesting without having to return
    through  EACH  level  in sequence, to make sure  that  a  particular  exit
    routine (e.g., the directed  I/O "dioflush" function) is always performed.
    It is a nifty facility that should  have  been  available long ago.  THESE
    FUNCTIONS ARE NOT DOCUMENTED IN THE BDS C USER'S  GUIDE;    PLEASE  MAKE A
    NOTE OF THEM IN THE STANDARD LIBRARY SECTION OF THE GUIDE.


23.  A  new  linker  for  BDS C called "L2" (a substitute for CLINK.COM) is now
    available from the BDS  C  User's  Group.  L2, written by Scott Layson (of
    Mark of the Unicorn) in BDS C, has several interesting features:

         1.   L2 can link programs that are up to  about 8K larger than CLINK:
              if there isn't enough room in memory to  hold the entire program
              while building an image in memory, L2 performs  a disk-buffering
              second pass.  This means that the resulting COM files  can be as
              large as the entire available TPA on the target machine.

         2.   The number of functions per program is no longer limited to 255.

         3.   While  CLINK  uses jump tables at the beginning of functions  to
              resolve references to other functions, L2 totally eliminates the
              jump tables and  instead  generates  direct external calls. This
              shortens programs by anywhere from 3%  to  10%,  and also speeds
              them up a little.

         4.   Since L2 is written in C, you can customize it yourself.

    The L2 package comes with source code, a special overlay generator program
    and documentation. It is available to BDSCUG members for the  nominal cost
    of media and shipping (currently $8). See the next note for information on
    joining the BDSCUG.


24.  The  BDS C User's Group membership forms should now be included  with  the
    BDS C package...this makes life easier for everyone, since it is no longer
    necessary  to  write to the Group first just to ask for forms before being
    able to order library  disks. BDS C User's Group members receive the Group
    newsletter approximately  6  times  per year, and are entitled to compiler
    updates and library disks for low prices (typically $8 per disk).