The following is HIPO (Hierarchy, Inputs, Processing, Outputs)
information for all the functions in this project.

  copy.c:
    main():
      Hierarchy: the top-level function in the project.
      Inputs: command line arguments, user responses to prompts.
      Processing: parses the command line, checks for errors,
                  calls the appropriate functions for copying/appending.
      Outputs: return-code of 0 for success, 1 for failure.

    copyhlp():
      Hierarchy: called by main().
      Inputs: n/a.
      Processing: displays the help screen.
      Outputs: n/a.

    nextspec():
      Hierarchy: called by main().
      Inputs: pointer to a source string, possibly containing '+'
              separators.
      Processing: scans to the first '+', replaces it with '\0'.
      Outputs: pointer to the rest of the string (after the '+').
    main_exit():
      Hierarchy: called by all functions which need to exit, eg,
                 upon finding an error.
      Inputs: value for return-code.
      Processing: restores values that need to be reset, prints
                  appropriate messages, exits.
      Outputs: return-code.
    do_one_file():
      Hierarchy: called by main().
      Inputs: pass #, various global variables having info about
              the source and destination specs.
      Processing: in the first pass, does error checking; in the
                  second pass, calls copy1() with appropriate arguments to
                  actually copy or append 1 file.
      Outputs: n/a.

  dirfns.c:
    fullpath():
      Hierarchy: called by functions which need to expand an
                 abbreviated path.
      Inputs: pointer to abbreviated path.
      Processing: allocates a string to hold the result; inserts
                  missing information (eg, the current drive letter if none
                  appears) and expands abbreviations (eg, ".."); terminates
                  the result with "*.*" if appropriate.
      Outputs: pointer to new string containing the full path.
    getcurdir1():
      Hierarchy: called by update_dwd().
      Inputs: pointer to a drive letter.
      Processing: allocates a string to hold the result; calls the
                  getcurdir() library function to obtain the current
                  directory for the drive.
      Outputs: pointer to new string containing the directory path.
    update_dwd():
      Hierarchy: called by fullpath().
      Inputs: pointer to a drive letter, global variable dwd.
      Processing: uses getcurdir1() to update the drive-working-
                  directory (dwd) so that it contains the correct info for
                  the indicated drive letter.
      Outputs: dwd and dwd_parent_exists are updated.
    is_dir():
      Hierarchy: called by fullpath().
      Inputs: pointer to a filename string.
      Processing: uses the findfirst() library function to obtain
                  the file's attributes.
      Outputs: boolean TRUE if the file has the directory attribute.
    fnsplit2():
      Hierarchy: called by main().
      Inputs: pointer to a full path string.
      Processing: uses the fnsplit() library function to split the
                  path string in half.
      Outputs: the flags from fnsplit() as the return value; a
               pointer to a new string containing the drive-directory half;
               a pointer to another new string containing the filename-
               extension half.
    newname():
      Hierarchy: called by do_one_file().
      Inputs: pointer to a filename; pointer to a pattern
              containing wildcards.
      Processing: allocates a new string for the result; transforms
                  the input string into the new string implied by the pattern.
                  For example, input "abc.txt", pattern "*.doc", result is
                  "abc.doc".
      Outputs: pointer to the new string.
    file_exists():
      Hierarchy: called by do_one_file().
      Inputs: pointer to a filename.
      Processing: uses the findfirst() library function to determine 
                  if the file exists.
      Outputs: TRUE if it exists; FALSE otherwise.

  strfns.c:
    test_heap_err():
      Hierarchy: called by functions that call malloc().
      Inputs: pointer.
      Processing: tests if pointer is NULL; if so, prints an error
                  message and exits.
      Outputs: n/a.
    strcat3():
      Hierarchy: a general-purpose string-concatenation function.
      Inputs: pointers to three strings.
      Processing: allocates a new string for the result, which
                  consists of the concatenation of the three input strings.
      Outputs: pointer to the new string.
    strdup1():
      Hierarchy: a general-purpose string-duplication function.
      Inputs: pointer to a string.
      Processing: allocates a new string for the result, which
                  consists of a copy of the input string.
      Outputs: pointer to the new string.
    str_toupper():
      Hierarchy: a general-purpose string-modification function.
      Inputs: pointer to a string.
      Processing: modifies the string by applying the toupper()
                  library function to each character in it.
      Outputs: pointer to the string which was modified.
    starts_with_plus():
      Hierarchy: called by main() when parsing the command line.
      Inputs: pointer to a string.
      Processing: tests the first character in the string.
      Outputs: TRUE if the string begins with '+'; else FALSE.
    ends_with_plus():
      Hierarchy: called by main() when parsing the command line.
      Inputs: pointer to a string.
      Processing: tests the last character in the string.
      Outputs: TRUE if the string ends with '+'; else FALSE.

  copysubs.c
    copy1():
      Hierarchy: called by do_one_file().
      Inputs: pointers to source and destination file names,
              switches to specify binary/ascii, copy/append, and
              zero/retain the high-order bits.
      Processing: copies one file.
      Outputs: n/a.