root@stag.UUCP (Computer Abuser) (07/26/87)
Well, here is a very long set of postings that I am putting up for Dale Schumacher. Read his message below and have fun (please remember to send mail to his address rather than mine). This posting is in 6 parts, 2 of documentation (around 25K each) and 4 of binary libraries. Another person here locally has used some of these routines under mwc 2.0 via the drtomw translator. -Todd Burkey Hi folks... As I mentioned in a previous message I posted (or actually had Todd post for me), I've been working on re-writing the standard libraries for use with Alcyon C v4.14. At that time I posted a bunch of string functions that where part of the evolving library. I'm now ready to release the first version of these libraries into the public domain. I will eventually be releasing all the source code for these routines, but I first would like to get some feedback (and bug reports) on the initial release. Therefore, this posting consist of documentation (~50K), an object library, and various header files and such. I've tried to implement a very complete set of Unix compatible and Microsoft C v4.0 compatible functions. I talked recently with David Beckemeyer about adding multi-tasking hooks for RTX, but they will be part of a later release. A little bit of background... I have been using Alcyon C for about a year and a half now. I learned early on to avoid many of the library routines and go directly to the OS calls. My applications have been mostly TOS based and I don't use floating point. I have been in the position of wanting to port code to/from Unix and MS-DOS and was constantly rewriting major sections of the code to adapt normal library calls to OS calls on the ST. I finally got sick of this process and decided that the public domain community could use a very complete set of routines, to which all sources were available, which implemented all these library functions that either didn't work, or weren't included, in the DRI libraries. In the process, there was an opportunity here to avoid certain OS bugs which were invoked by some of the earlier libraries. I've tried to "do it right" in this implementation, but there will certainly be some bugs and some disagreement with certain design decisions I made. That's fine, since the source will be available, people will be free to change what they don't like. This library is basically for TOS applications which do not use floating point. Additions to the library to support floating point (mainly in the printf/scanf functions and the additional fp functions) and GEM/AES/VDI calls will probably appear later. I encourage people who want to implement such libraries, or people who have suggestions (source code would be nice) for improving the existing routines, to contact me. I will gladly collect such proposals and try to maintain a consistent and clean set of upgrades and extensions. I can't prevent people from releasing changes/additions directly, but I would DEFINATELY prefer if the changes were channeled through me. Dale Schumacher 399 Beacon Ave. St. Paul, MN 55104 BBS: (612) 646-3988 [Citadel-86 300/1200/2400, 24hrs.] UUCP: ..ihnp4!meccts!stag!syntel!dal or syntel!dal@stag.UUCP ----- Beginning of DLIBS.DOC ----- _________________________________________________________________________ | | | Replacement standard library functions for Atari ST with Alcyon C v4.14 | | Version 0.11.0, by Dale Schumacher, last modified 07/20/87. | |_________________________________________________________________________| CONSTANTS: TRUE Boolean true (1) FALSE Boolean false (0) ERROR General error value (-1) NULL Null pointer ((void *) 0) MAXFILES Maximum number of open streams (20) MAXINT Maximum signed integer value (32767) MININT Minimum signed integer value (-32768) BUFSIZ Standard buffer size (512) PATHSIZE Maximum size of a pathname (128) EOF End of file indicator (-1) PROCESS CONTROL: void _main(cmdline, cmdlen) char *cmdline; int cmdlen; Parses command line, opens standard files, plus other assorted general setup. Then calls user's main() function. If main() returns, exit() is called with a 0 return value. The following standard streams are initialized by _main(): stdin Standard input, may be redirected stdout Standard output, may be redirected stderr Usually the system console stdprn The standard printer (output only) stdaux The communication port (input/output) The _initargs() function is called to process the command line. The global variables "_argc", "_argv" and "_envp" are used to store the values to be passed to the user's main(). void _initargs(cmdline, cmdlen) char *cmdline; int cmdlen; Process command line and retrieve the environment string. This function is responsible for allocating space to hold the parsed command line arguments, etc. Values to be passed to the user's main() function are stored in the global variables "_argc", "_argv" and "_envp". _main() initiallizes these variables to indicate that no arguments are available. If a program doesn't use command line arguments or the environment string, an _initargs() function, which does nothing, should be defined in the module containing main(). This will result in a smaller executable size and a smaller run-time image. void main(argc, argv, envp) int argc; char *argv[]; char *envp; This function is not actually in the standard libraries, but must be present somewhere in the user's code. The parameters passed to it by _main() are the number of arguments in the command line, a pointer to a list of pointers to arguments, and a pointer to the environment string. The return value from main() is ignored by _main(). If the program wishes to return a status code, it should call exit() directly. void exit(status) int status; Flushes and closes all open streams. Returns <status> value to the operating system. void _exit(status) int status; Exits the program immediately, returning <status> to the OS. void abort() Prints the message "Abnormal program termination" to stderr and calls _exit() with a status code of 3. int getpid() Return an integer value unique for this process. char *getenv(var) register char *var; Search for <var> in the environment. If <var> is found, a pointer to it's value is returned. NULL is returned if <var> is not found. WARNING: The returned pointer points into the environment and must not be modified! int putenv(entry) char *entry; Add <entry> to the environment. <entry> can be any of the following forms: <VARIABLE> <VARIABLE>= <VARIABLE>=<value> The first form removes <VARIABLE> from the environment. getenv() will return NULL if looking for this variable. The second form adds <VARIABLE> to the environment, with a null value. getenv() will return a pointer to a '\0' character if looking for this variable. Many environment handlers don't support such "tag variables", so their use is not recommended. The final form is the most common, and safest to use. <VARIABLE> is installed (or replaced) with the value <value>. It should be noted that the putenv() function itself is not supported in many systems and therefore may not be portable. In addition, care should be taken to prevent overflowing the space allocated for the environment. Returns TRUE for success or FALSE for failure. NO OVERFLOW CHECKING IS DONE. int system(command) char *command; Attempts to pass <command> to the shell program pointed to by the system variable "_shell_p". If a valid shell can't be found there, the "SHELL" environment variable is searched for. If it exists and is not empty, it will be the name of the shell program to execute the given command. If "SHELL" is not valid, the "PATH" variable is searched for. This would specify the paths to search for the program name which is the first token of the <command>. If "PATH" is not valid, the current directory is searched for the given command. The extensions tried (if none is specified) are ".TTP", ".TOS", ".PRG" and ".APP". int exec(program, cmdline, envp) char *program; char *cmdline; char *envp; Calls the OS "Pexec" trap with the parameters specified. Since the OS uses a Pascal-like string for the command line, the <cmdline> parameter, which is a normal C-string, is used to create the actual command line which is passed to the OS trap. Returns the value returned by the program, or -1 for errors. int pexec(program, cmdline, envp) char *program; char *cmdline; char *envp; Operates like exec() except that the "PATH" environment variable, if it is valid, is used to locate the program to be executed. Various extensions are tried, as described for system(). Returns the value returned by the program, or -1 for errors. long gemdos(func[, arg1, ..., argN]) int func; Call operating system trap #1 (GEMDOS) function number <func> with the arguments given. Returned value returned by the trap call. long bios(func[, arg1, ..., argN]) int func; Call operating system trap #13 (BIOS) function number <func> with the arguments given. Returned value returned by the trap call. long xbios(func[, arg1, ..., argN]) int func; Call operating system trap #14 (XBIOS) function number <func> with the arguments given. Returned value returned by the trap call. int setjmp(context) jmp_buf context; [save <context> for longjmp(). MUST include "SETJMP.H" to use.] longjmp(context, rv) jmp_buf context; int rv; [return <rv> to <context> saved by setjmp(). MUST include "SETJMP.H" to use.] int catch(context, func) jmp_buf context; int (*func)(); [execute <func> with saved <context> for throw(). MUST include "SETJMP.H" to use.] void throw(context, func) jmp_buf context; int rv; [return <rv> to <context> saved by catch(). MUST include "SETJMP.H" to use.] MEMORY MANAGEMENT: char *malloc(size) unsigned int size; Allocate at least <size> bytes of memory. A pointer to the requested block is returned, or NULL if there is not enough free memory available. char *calloc(n, size) unsigned int n; unsigned int size; Allocate space for an array of <n> element of <size> bytes each. If the storage can be allocated, it is initialized to all zero. NULL is returned is there is not enough free memory. char *lalloc(size) unsigned long size; Allocate at least <size> bytes of memory. A pointer to the requested block is returned, or NULL if there is not enough free memory available. char *realloc(addr, size) char *addr; unsigned int size; Attempt to change the memory block at <addr> to the new <size>. Making a block smaller will always work, but making it larger may fail if there is not enough free memory. If there is not enough memory, NULL is returned and the block will still reside at <addr>. If realloc() succeeds, a pointer to the (possibly moved) new block will be returned. void free(addr) char *addr; Release the memory block at <addr> back into the free memory pool. If <addr> doesn't point to a block allocated by calloc(), malloc(), lalloc() or realloc(), very bad, unpredictable things will happen. unsigned long msize(addr) char *addr; Return the size, in bytes, of the memory block at <addr>. Note that the size is a long value, since the block may have been allocated by lalloc(). unsigned long memavail() Return the size, in bytes, of the largest block of free memory available for allocation. Note that this value is a long. FILE HANDLING: You may want to include "IO.H" in your program if you use functions in this section, otherwise you may have to declare the return types for some functions. "IO.H" also contains the definitions of many symbolic constants used with these functions. int chdir(pathname) char *pathname; Changes the current working directory to <pathname>. '/' characters in <pathname> are converted to '\'. If a drive letter is specified in <pathname>, the current working directory for that drive is set. Returns 0 for success, or a negative error code. int mkdir(pathname) char *pathname; Creates a new directory called <pathname>. A drive letter may be specified. '/' characters in <pathname> are converted to '\'. Returns 0 for success, or a negative error code. int rmdir(pathname) char *pathname; Removes an existing directory called <pathname>. A drive letter may be specified. '/' characters in <pathname> are converted to '\'. Returns 0 for success, or a negative error code. char *fullpath(full, part) char *full; char *part; <part> is a (possibly) ambiguous file/path specification. A non-ambiguous file/path spec is created which includes a drive letter and all intermediate sub-directories. If the partial specification is not valid, NULL is returned, otherwise a pointer to <full> is returned. If NULL is specified for <full>, an internal buffer is used and a pointer to it is returned. int access(name, amode) char *name; int amode; Return non-zero if a file with the given <name> can be accessed in the given <amode>. Possible <amode> values are: _ACCe file exists _ACCr file can be read _ACCw file can be written _ACCrw file can be read and written char *findfile(afn[, ext]) char *afn; char *ext; Return full file spec for <afn> if found. If <afn> has no extension, extensions from <ext> are tried until a match is found, or the list ends. <ext> is a list of extensions separated by '\0' characters and ending with an additional '\0', ie. "ttp\0tos\0ttp\0" (note that the final null is added by the compiler to any string constant. If <afn> already has an extension, <ext> is not used. If no matching files are found, NULL is returned. The pointer returned when a match is found points to a buffer which is internal to fullpath(). If you want to save the value returned, you must make a copy before the buffer is overwritten by subsequent calls. char *pfindfile(afn[, ext]) char *afn; char *ext; Like findfile() but search all directories listed in the environment variable "PATH", if no match is found in the current directory. If <afn> specifies a drive or directory, "PATH" is not used. int stat(name, statbuf) char *name; STAT *statbuf; Search for file <name> and load <statbuf> with information about that file, if it is found. Return 0 if found, or ERROR (-1) if no file/directory matched <name>. Volume labels are not included in the search. long fsize(name) char *name; Return the size of the file <name> in bytes. Note that this is a long value. Return -1L if the file is not found. int isatty(h) int h; Return non-zero if <h> refers to a character device. Both the device handles (-1..-3) and the standard handles (0..5) are considered character devices by this function. int creat(filename, pmode) char *filename; int pmode; Create a new file with the given <filename>. If a file with the name already exists, it will be truncated to zero bytes. Since the OS doesn't do this properly, the file is actually deleted and then re-created. <pmode> specifies the attributes initially given to the file. Valid <pmode> values are: _CRErw read/write _CREro read only _CREh hidden file _CREs system file _CREv volume label If _CRErw or _CREvol modes are specified, they must be the only mode given. Other modes may be combined with the | operator. int chmod(filename, pmode) char *filename; int pmode; Change the mode attribute of <filename> to <pmode>. Values for <pmode> are the same as for the creat() function. Returns 0 for success, or a negative error code. int open(filename, iomode) char *filename; int iomode; Attempt to open <filename> with the given <iomode>. This is a direct hook into the OS "Fopen" call. A file handle is returned if the open succeeds. A negative error code is returned for errors. Valid <iomode> values are: _OPNr read mode _OPNw write mode _OPNrw read/write mode int close(h) int h; Close file referenced by the file handle <h>. Return 0 for success, or a negative error code. int dup(handle) int handle; Return a second file handle which refers to the same file as the given <handle>. int dup2(handle1, handle2) int handle1; int handle2; Force <handle2> to refer to the same file as <handle1>. Return 0 for success, or a negative error code. Both dup() and dup2() are direct calls to Fdup() and Fforce() GEMDOS calls. Refer to your GEMDOS documentation for further information. int unlink(filename) char *filename; Delete <filename>, if it exists. Return 0 for success, or a negative error code. int rename(oldname, newname) char *oldname; char *newname; Change the name of file <oldname> to <newname>. You may use this function to move files from one directory (pathname) to another, but not from one drive to another. Return 0 for success, or a negative error code. long lseek(h, offset, origin) int h; long offset; int origin; Move file pointer for file <h> to specified location. <origin> specifies the starting point for the <offset> distance. Valid <origin> values are: _LSKbeg from beginning of file (0) _LSKcur from current location (1) _LSKend from end of file (2) The <offset> value is the distance in bytes from the origin. The final file position, or a negative error code, is returned. long tell(h) int h; Return the current file position for the file <h>. FILE *fopen(filename, mode) char *filename; char *mode; Open <filename> as a stream file. This is the normal open way to open a file. The <mode> is a string specifying the mode(s) that are relevent to the file open. Valid <mode> characters are: r read mode w write mode a append mode b binary mode t text (translated) mode At least one of "r", "w" or "a" must be specified. "t" is assumed and indicates that <nl> is translated to <cr><lf> on output and vica-versa on input. If the stream is a character device, the translation is slightly different. The output translation is the same, but on input <cr> and <lf> both become <nl> in all cases. The "b", for binary mode, overides "t" and indicated that characters are not translated during i/o operations. "a" represents append mode and means that the file pointer will initially be placed at the end of the file. "w" mode will create a file if it doesn't exists, or zero an existing file. If "r" is the only mode specified, the file must already exist. A (FILE *) is returned if the open succeeds, or NULL if it fails. FILE *freopen(filename, mode, fp) char *filename; char *mode; FILE *fp; Closes the file associated with <fp> and opens the new file as with fopen(), except that a new FILE structure is not created. The existing FILE structure pointed to by <fp> is re-initialized with the new file information. This is typically used to redirect i/o to standard streams "stdin", "stdout", "stderr", "stdprn", "stdaux". <fp> is returned for success, or NULL for failure. FILE *fdopen(h, mode) int h; char *mode; Associates a stream with the already open file <h>. The <mode> values are the same as for fopen(), but MUST be compatible with the mode in which <h> was open()ed. This functions allows use of a file opened with the low level open()/creat() calls to be used as a buffered/translated stream. A pointer to a FILE struct is returned, or NULL for errors. int fclose(fp) FILE *fp; Close the stream <fp>, flushing the buffer. Returns 0 on success. void setbuf(fp, buf) register FILE *fp; char *buf; If <buf> is NULL, make <fp> unbuffered; else <buf> points to a buffer of BUFSIZ characters to be used as the stream buffer for <fp>. long fseek(fp, offset, origin) FILE *fp; long offset; int origin; Operates like lseek(), except it works on streams. Note that stream file positions may be misleading due to translation of <nl> characters during i/o. ftell() may be used reliably with fseek() to reposition a file to a prior location. void rewind(fp) FILE *fp; Operates like fseek(fp, 0L, _LSKbeg), except it also clears the end-of-file and error flags for <fp>. There is no return value. long ftell(fp) FILE *fp; Operates like tell(), except it works on streams. Note that stream file positions may be misleading due to translation of <nl> characters during i/o. int fileno(fp) Return the file handle associated with the stream <fp>. int feof(fp) Return non-zero if <fp> is at end of file. int ferror(fp) Return non-zero if and error has occurred on <fp>. void clearerr(fp) Clear the error flag on <fp>. INPUT/OUTPUT FUNCTIONS: You may want to include "IO.H" in your program if you use functions in this section, otherwise you may have to declare the return types for some functions. "IO.H" also contains the definitions of many symbolic constants used with these functions. int read(h, data, length) int h; char *data; int length; Read <length> bytes from the file reference by file handle <h>. Data is stored in the buffer pointed to by <data>. The number of bytes actually read is returned, 0 for end of file, or a negative error code. Note that the maximum number of bytes that can be read by this function is MAXINT. long lread(h, data, length) int h; char *data; long length; Same as read(), but uses a long value for number of bytes to read. int write(h, data, length) int h; char *data; int length; Write <length> bytes to the file reference by file handle <h>. Data is written from the buffer pointed to by <data>. The number of bytes actually written is returned, or a negative error code. Note that the maximum number of bytes that can be written by this function is MAXINT. long lwrite(h, data, length) int h; char *data; long length; Same as write(), but uses a long value for number of bytes to write. int fread(data, size, count, fp) char *data; int size; int count; FILE *fp; Read <count> items of <size> characters each from stream <fp>. Data is stored in the buffer pointed to by <data>. The number of full items actually read is returned, or a negative error code. This call DOES NOT translate characters, even if the stream is opened in translate mode. int fwrite(data, size, count, fp) char *data; int size; int count; FILE *fp; Write <count> items of <size> characters each to stream <fp>. Data is read from the buffer pointed to by <data>. The number of full items actually written is returned, or a negative error code. This call DOES NOT translate characters, even if the stream is opened in translate mode. int fgetc(fp) FILE *fp; Get a character from <fp>. Returns the character or EOF. int fungetc(c, fp) char c; FILE *fp; Push the character <c> back to be gotten by the next fgetc() call on <fp>. Only 1 character may be ungotten at a time on each stream. Subsequent calls to fungetc() will write over the currently saved character. int fputc(c, fp) char c; FILE *fp; Put the character <c> to the stream <fp>. int fflush(fp) FILE *fp; Flush the output buffer of the stream <fp>. The buffer is automatically flushed when it is full, the stream is closed, or the program terminates through exit(). This function has no effect if the stream in unbuffered. int getc(fp) FILE *fp; Same as fgetc() but implemented as a macro. int ungetc(c, fp) char c; FILE *fp; Same as fungetc() but implemented as a macro. int putc(c, fp) char c; FILE *fp; Same as fputc() but implemented as a macro. int getw(fp) FILE *fp; Get a 2-byte value from the stream <fp>. The high-order byte is read first. int putw(n, fp) int n; FILE *fp; Put the 2-byte value <n> to the stream <fp>. The high-order byte is written first. int getchar() Same as "fgetc(stdin)". int ungetchar(c) char c; Same as "fungetc(c, stdin)". Note that this name will conflict with any function beginning "ungetch..." due to having only 7 significant characters in Alcyon C v4.14. int putchar(c) char c; Same as "fputc(c, stdin)". cfg_ch(cfg) int cfg; Configure getch()/putch() operation. The following are legal values for <cfg> and may be combined with the | operator: _CIOb Use BIOS level i/o calls _CIOch 8-bit character codes only (cf:getch) _CIOvt Enable VT-52 escape sequence processing The initial configuration value at run time is _CIOch. int getch() Machine dependent console input function. This function normally gets a character from the keyboard by calling the GEMDOS "Cconin" function. If cfg_ch() is given the _CIOb option, input is gotten from the BIOS "Bconin" function instead. The BIOS level functions don't process ^C, ^S or ^Q, while the GEMDOS functions do. The most common use for getch() is when keyboard scan codes are needed to process special function keys. The return value from getch() consists of the scan code in the high-order byte, and the ascii character code in the low-order byte. If cfg_ch() is given the _CIOch option, the return value is always an 8-bit quantity, either the scan code with the 8th bit set, or the ascii code with the 8th bit clear. This is somewhat less informative, since the scan code form is returned only if the ascii value is 0, but is the default configuration value for compatability with Microsoft C. In any case, the global unsigned long variable "_getch" will contain the full character code value returned by the OS. int getche() Same as getch() but calls putch() to echo the character. char putch(c) char c; Machine dependent (typically quite fast) console output function. This function normally puts a character to the console by calling the GEMDOS "Cconout" function. If cfg_ch() is given the _CIOb option, output is sent to the BIOS "Bconout" function instead. The BIOS level functions don't process ^C, ^S or ^Q, while the GEMDOS functions do. At the BIOS level, the _CIOvt option to cfg_ch() allows VT-52 escape code processing on output. The GEMDOS function always does VT-52 emulation. The BIOS function defaults to skipping this overhead, but if VT-52 emulation is desired, it can still be used through the faster BIOS level routine by using the _CIOvt option. Control codes, like '\b' and '\r', are supported even without VT-52 emulation. The return value of this function is simply the character sent. int kbhit() Machine dependent function to detect if input is waiting for the getch() function. Returns non-zero if the console has data ready. char *fgets(data, limit, fp) char *data; int limit; FILE *fp; Get data from <fp> and puts it in the <data> buffer. At most, <limit>-1 characters will be read. Input will also be terminated when a newline is read. <data> will be '\0' terminated and the newline, if read, will be included. A pointer to the start of <data> is returned, or NULL for EOF. void fputs(data, fp) char *data; FILE *fp; Write the characters in <data> to the stream <fp>. A newline WILL NOT be added. char *gets(data) char *data; Get data from stdin and puts it in the <data> buffer. Input is terminated when a newline is read. The newline will be replaced by a '\0' to terminate the string. A backspace character will remove the preceeding character from the buffer, but will not backspace past the start of the buffer. A pointer to the start of <data> is returned, or NULL for EOF. void puts(data) char *data; Write the characters in <data> to stdout. A newline WILL be written after the data. void cputs(data) char *data; Write the characters in <data> directly to the console using the system dependent putch() function. A newline WILL NOT be written after the data. int fprintf(fp, fmt[, arg1, ..., argN]) FILE *fp; char *fmt; Formatted output to the stream <fp>. See the _printf() function for a description of the <fmt> formatting string. int printf(fmt[, arg1, ..., argN]) char *fmt; Formatted output to the stdout stream. See the _printf() function for a description of the <fmt> formatting string. int sprintf(buf, fmt[, arg1, ..., argN]) char *buf; char *fmt; Formatted output to the string <s>. See the _printf() function for a description of the <fmt> formatting string. int cprintf(fmt[, arg1, ..., argN]) char *fmt; Formatted output directly to the console. This functions uses the system dependent putch() for output. See the _printf() function for a description of the <fmt> formatting string. int fscanf(fp, fmt[, arg1, ..., argN]) FILE *fp; char *fmt; Formatted input from the stream <fp>. See the _scanf() function for a description of the <fmt> formatting string. int scanf(fmt[, arg1, ..., argN]) char *fmt; Formatted input from the stdin stream. See the _scanf() function for a description of the <fmt> formatting string. int sscanf(buf, fmt[, arg1, ..., argN]) char *buf; char *fmt; Formatted input from the string <s>. See the _scanf() function for a description of the <fmt> formatting string. ----------------------Cut Here...End of Part 1 of 2--------------------------