TABLE OF CONTENTS

net.lib/autoinit
net.lib/autoinit_timer.device
net.lib/autoinit_usergroup.library
net.lib/charRead
net.lib/chmod
net.lib/chown
net.lib/dup
net.lib/dup2
net.lib/fstat
net.lib/gettimeofday
net.lib/herror
net.lib/init_inet_daemon
net.lib/lineRead
net.lib/lstat
net.lib/perror
net.lib/popen
net.lib/PrintNetFault
net.lib/PrintUserFault
net.lib/rcmd
net.lib/serveraccept
net.lib/set_socket_stdio
net.lib/sleep
net.lib/SPrintf
net.lib/stat
net.lib/strerror
net.lib/syslog
net.lib/usleep
net.lib/utime
netd.lib/dosio_init
net.lib/autoinit                                             net.lib/autoinit

   NAME
       autoinit - SAS C Autoinitialization Functions

   SYNOPSIS
       LONG _STI_200_openSockets(void)

       void _STD_200_closeSockets(void)

   FUNCTION
       These functions open and close the bsdsocket.library at the startup
       and exit of the program, respectively.  For a program to use these
       functions, it must be linked with netlib:net.lib (or some variant).
       These functions are linked in only if the program references the
       global symbol "SocketBase".

       If the library can be opened, the _STI_200_openSockets() calls
       bsdsocket.library function SocketBaseTags() to tell the library the
       address and the size of the errno variable of the calling program,
       the program name (to be used in syslog() messages) and the address
       of the h_error variable (in which the name resolver errors are
       returned).

   NOTES
       _STI_200_openSockets() also checks that the system version is at
       least 37. It also puts up a requester if the bsdsocket.library is
       not found or is of wrong version.

       The autoinitialization and autotermination functions are features
       specific to the SAS C6.  However, these functions can be used with
       other (ANSI) C compilers, too. Example follows:

       /* at start of main() */

       atexit(_STD_200_closeSockets);
       if (_STI_200_openSockets() != 0)
          exit(20);

   BUGS
       The same autoinitialization won't work for both SAS C 6.3 and SAS C
       6.50 or latter.  Only way to terminate an initialization function is
       by exit() call with SAS C 6.3 binary.  If an autoinitialization
       function is terminated by exit() call with SAS C 6.50 binary, the
       autotermination functions won't be called.  Due this braindamage
       these compilers require separate net.lib libraries.

   SEE ALSO
       bsdsocket.library/SocketBaseTags(),
       SAS/C 6 User's Guide p. 145 for details of autoinitialization and
       autotermination functions.

net.lib/autoinit_timer.device                   net.lib/autoinit_timer.device

   NAME
       timerinit - SAS C Autoinitialization Functions for timer.device

   SYNOPSIS
       #include <time.h>
   
       int daylight;
       long timezone;
       char *tzname[2];

       void tzset(void);

       #include <sys/time.h>

       struct Device *TimerBase;

       LONG _STI_200_openTimer(void);
       void _STD_200_closeTimer(void);
       
   FUNCTION
       These functions open and close the timer.device at the startup and
       exit of the program, respectively. For a program to use these
       functions, it must be linked with netlib:net.lib.

       The opened device base is stored in the TimerBase global variable.

       If the device can be opened, the _STIopenTimer() sets up the time zone
       information, which is used by the gettimeofday() function and the time
       conversion routines of the C-library.

   NOTES
       The time zone information is got from the environment variable named
       TZ. The format for this variable is:

           zzznnnddd

       where zzz is three letter identifier for the time zone (for example
       GMT), and the nnn is hours west from Greenwich on range [-23,24]
       (negative values are to east).  The last field is the abbreviation for
       the local daylight saving time zone (which is not interpreted by this
       version).

       If the TZ environment variable cannot be found, Greenwich Mean Time
       (GMT) is used instead.

       The autoinitialization and autotermination functions are features
       specific to the SAS C6.  However, these functions can be used with
       other (ANSI) C compilers, too.  Example follows:

       /* at start of main() */

       atexit(_STD_200_closeTimer);
       _STI_200_openTimer();

       The tzset() does nothing. All the necessary initialization is done at
       the autoinit function.

   BUGS
       TZ "hours west from GMT" should be interpreted as float.

       The same autoinitialization won't work for both SAS C 6.3 and SAS C
       6.50 or latter.  Only way to terminate an initialization function is
       by exit() call with SAS C 6.3 binary.  If an autoinitialization
       function is terminated by exit() call with SAS C 6.50 binary, the
       autotermination functions won't be called.  Due this braindamage
       these compilers require separate net.lib libraries.

   SEE ALSO
       net.lib/gettimeofday(),
       SAS/C 6 User's Guide p. 145 for details of autoinitialization and
       autotermination functions.
net.lib/autoinit_usergroup.library         net.lib/autoinit_usergroup.library

   NAME
       autoinit usergroup.library - SAS C Autoinitialization Functions

   SYNOPSIS
       error = _STI_200_openUserGroup()

       LONG _STI_200_openUserGroup(void)

       _STD_200_closeUserGroup()

       void _STD_200_closeUserGroup(void)

   FUNCTION
       These functions open and close the usergroup.library at the startup
       and exit of the program, respectively.  For a program to use these
       functions, it must be linked with netlib:usr.lib.

   NOTES
       _STI_200_openUserGroup() also checks that the system version is at
       least 37.  It puts up a requester if the usergroup.library is not
       found or is too old version.

       The autoinitialization and autotermination functions are features
       specific to the SAS C6.  However, these functions can be used with
       other (ANSI) C compilers, too.  Example follows:

       /* at start of main() */

       atexit(_STD_200_closeUserGroup);
       if (_STI_200_openUserGroup() != 0)
          exit(20);

   BUGS 
       The same autoinitialization won't work for both SAS C 6.3 and SAS C
       6.50 or latter.  Only way to terminate an initialization function is
       by exit() call with SAS C 6.3 binary.  If an autoinitialization
       function is terminated by exit() call with SAS C 6.50 binary, the
       autotermination functions won't be called.  Due this braindamage
       these compilers require separate net.lib libraries.

   SEE ALSO
       SAS/C 6 User's Guide p. 145 for details of autoinitialization and
       autotermination functions.

net.lib/charRead                                             net.lib/charRead

   NAME
       charRead -- read characters from socket one by one.

   SYNOPSIS
       initCharRead(rc, fd)

       void initCharRead(struct CharRead *, int);


       character = charRead(rc)

       int charRead(struct CharRead *);


   DESCRIPTION
       charRead is a macro package which return characters one by one 
       from given socket input stream. The socket where data is to be read
       is set by calling initCharRead(): rc is the pointer to charread
       structure previously allocated. fd is the (socket) descriptor where
       reading is to be done.

       charRead() returns the next character from input stream or one of
       the following:

       RC_DO_SELECT    (-3)    - read input buffer is returned. Do select
                                 before next call if you don't want charread
                                 to block.

       RC_EOF          (-2)    - end-of-file condition has occurred.

       RC_ERROR        (-1)    - there has been an error while filling new
                                 charread buffer. Check the value of Errno()

   NOTE
       Always use variable of type int to store return value from charRead()
       since the numeric value of characters returned may vary between
       0 -255 (or even greater). As you may know, -3 equals 253 if of type
       unsigned char.

   EXAMPLE
       /*
        * This piece of code shows how to use charread with select()
        */
       #include <sys/types.h>
       #include <sys/socket.h>
       #include <charread.h>

       main_loop(int sock)
       {
         struct CharRead rc;
         fd_set readfds;
         int c;

         initCharRead(&rc, sock);

         FD_ZERO(&readfds);

         while(1) {
           FD_SET(sock, &readfds);     

           if (select(sock + 1. &readfds, NULL, NULL, NULL)) < 0) {
             perror("select");
             break;
           }
           if (FD_ISSET(sock, &readfds)) {
             while((c = charRead(&rc)) >= 0)
               handle_next_input_character(c);
             if (c == RC_EOF)
               break;
             if (c == RC_ERROR) {
               perror("charRead");
               break;
             }
           }
         }
       }

    PORTABILITY
       The source file charread.h should be able to be used in 
       UNIX programs as is.

    SEE ALSO
       lineRead(), bsdsocket.library/recv()
net.lib/chmod                                                   net.lib/chmod

   NAME
       chmod, fchmod - change mode of file

   SYNOPSIS
       #include <sys/stat.h>

       int chmod(const char *path, mode_t mode);

       int fchmod(int fd, mode_t mode);

   DESCRIPTION
       The function chmod() sets the file permission bits of the file
       specified by the pathname path to mode. Fchmod() sets the permission
       bits of the specified file descriptor fd. Chmod() verifies that the
       process owner (user) either owns the file specified by path (or fd),
       or is the super-user.  A mode is created from or'd permission bit
       masks defined in <sys/stat.h>:

             #define S_IRWXU 0000700    /* RWX mask for owner */
             #define S_IRUSR 0000400    /* R for owner */
             #define S_IWUSR 0000200    /* W for owner */
             #define S_IXUSR 0000100    /* X for owner */

             #define S_IRWXG 0000070    /* RWX mask for group */
             #define S_IRGRP 0000040    /* R for group */
             #define S_IWGRP 0000020    /* W for group */
             #define S_IXGRP 0000010    /* X for group */

             #define S_IRWXO 0000007    /* RWX mask for other */
             #define S_IROTH 0000004    /* R for other */
             #define S_IWOTH 0000002    /* W for other */
             #define S_IXOTH 0000001    /* X for other */

             #define S_ISUID 0004000    /* set user id on execution */
             #define S_ISGID 0002000    /* set group id on execution */
             #define S_ISVTX 0001000    /* save swapped text even after use *
/

       The ISVTX (the sticky bit) indicates to the system which executable
       files are shareable (pure).

       Writing or changing the owner of a file turns off the set-user-id
       and set-group-id bits unless the user is the super-user.  This makes
       the system somewhat more secure by protecting set-user-id
       (set-group-id) files from remaining set-user-id (set-group-id) if
       they are modified.

   RETURN VALUES
       Upon successful completion, a value of 0 is returned.  Otherwise, a
       value of -1 is returned and errno is set to indicate the error.

   ERRORS
       Chmod() will fail and the file mode will be unchanged if:

       [ENOTDIR]     A component of the path prefix is not a directory.

       [ENAMETOOLONG]
                     A component of a pathname exceeded 255 characters, or
                     an entire path name exceeded 1023 characters.

       [ENOENT]      The named file does not exist.

       [EACCES]      Search permission is denied for a component of the
                     path prefix.

       [EPERM]       The effective user ID does not match the owner of the
                     file and the effective user ID is not the super-user.

       [EROFS]       The named file resides on a read-only file system.

       [EFAULT]      Path points outside the process's allocated address
                     space.

       [EIO]         An I/O error occurred while reading from or writing to
                     the file system.

       Fchmod() will fail if:

       [EBADF]       The descriptor is not valid.

       [EINVAL]      Fd refers to a socket, not to a file.

       [EROFS]       The file resides on a read-only file system.

       [EIO]         An I/O error occurred while reading from or writing to
                     the file system.

   NOTES
       This call is provided for Unix compatibility.  It does not know all
       Amiga protection bits (Delete, Archive, Script).  The archive and
       script bits are cleared, Delete set according the Write bit.

   SEE ALSO
       open(),  chown(),  stat()

net.lib/chown                                                   net.lib/chown

   NAME
       chown - change owner and group of a file

   SYNOPSIS
       #include <unistd.h>

       success = chown(path, owner, group)

       int chown(const char *, uid_t, gid_t);

   DESCRIPTION
       The owner ID and group ID of the file named by path or referenced by
       fd is changed as specified by the arguments owner and group.  The
       owner of a file may change the group to a group of which he or she is
       a member, but the change owner capability is restricted to the
       super-user.

       Chown() clears the set-user-id and set-group-id bits on the file to
       prevent accidental or mischievious creation of set-user-id and
       set-group-id programs.

       One of the owner or group id's may be left unchanged by specifying it
       as -1.

       If the final component of path is a symbolic link, the ownership and
       group of the symbolic link is changed, not the ownership and group of
       the file or directory to which it points.

   RETURN VALUES
       Zero is returned if the operation was successful; -1 is returned if an
       error occurs, with a more specific error code being placed in the
       global variable errno.

   ERRORS
       Chown() will fail and the file will be unchanged if:

       [ENOTDIR]     A component of the path prefix is not a directory.

       [EINVAL]      The pathname contains a character with the high-order
                     bit set.

       [ENAMETOOLONG]
                     A component of a pathname exceeded 80 characters, or an
                     entire path name exceeded 1023 characters.

       [ENOENT]      The named file does not exist.

       [EACCES]      Search permission is denied for a component of the path
                     prefix.

       [ELOOP]       Too many symbolic links were encountered in translating
                     the pathname.

       [EPERM]       The effective user ID is not the super-user.

       [EROFS]       The named file resides on a read-only file system.

       [EFAULT]      Path points outside the process's allocated address
                     space.

       [EIO]         An I/O error occurred while reading from or writing to
                     the file system.

   SEE ALSO
       chmod(2)

net.lib/dup                                                       net.lib/dup

   NAME
       dup, dup2 - duplicate an existing file descriptor

   SYNOPSIS
       #include <unistd.h>

       int dup(int oldd)

       int dup2(int oldd, int newd)

   FUNCTION
       Dup() duplicates an existing object descriptor and returns its value
       to the calling program (newd = dup(oldd)). The argument oldd is a
       small nonnegative integer index in the program's descriptor table.
       The value must be less than the size of the table, which is returned
       by getdtablesize().  The new descriptor returned by the call is the
       lowest numbered descriptor currently not in use by the program.

       The object referenced by the descriptor does not distinguish between
       oldd and newd in any way.  Thus if newd and oldd are duplicate
       references to an open file, read() and write() calls all move a single
       pointer into the file, and append mode, non-blocking I/O and
       asynchronous I/O options are shared between the references.  If a
       separate pointer into the file is desired, a different object
       reference to the file must be obtained by issuing an additional open()
       call.  The close-on-exec flag on the new file descriptor is unset.

       In dup2(), the value of the new descriptor newd is specified.  If this
       descriptor is already in use, the descriptor is first deallocated as
       if a close() call had been done first.

   RETURN VALUES
       The value -1 is returned if an error occurs in either call.  The
       external variable errno indicates the cause of the error.

   BUGS
       The current UFB implementation for SAS C allows only sockets to be
       duplicated.

   ERRORS
       Dup() and dup2() fail if:

       [EBADF]       Oldd or newd is not a valid active descriptor

       [EMFILE]      Too many descriptors are active.

   SEE ALSO
       accept(),  open(),  close(),  socket(),  getdtablesize()

   STANDARDS
       Dup() and dup2() are expected to conform to IEEE Std 1003.1-1988
       (``POSIX'').

   COPYRIGHT
       This manual page is copyright © 1980, 1991 Regents of the
       University of California.  All rights reserved.

net.lib/dup2                                                     net.lib/dup2
   SEE ALSO
       dup()
net.lib/fstat                                                   net.lib/fstat

   SEE ALSO
       stat()

net.lib/gettimeofday                                     net.lib/gettimeofday

   NAME   
       gettimeofday - get date and time 

   SYNOPSIS
       #include <sys/time.h>

       error = gettimeofday(tp, tzp)

       int gettimeofday(struct timeval *, struct timezone *)

   FUNCTION
       The system's notion of the current Greenwich time and the
       current time zone is obtained with the gettimeofday() call.
       The time is expressed in seconds and microseconds since
       midnight (0 hour), January 1, 1970.  The resolution of the
       system clock is hardware dependent. If tzp is zero, the time
       zone information will not be returned. Also, if your system
       software is unable to provide time zone information, the
       structure pointed by tzp will be filled with zeroes.
  
   PORTABILITY
       UNIX

   INPUTS
       The structures pointed to by tp and tzp are defined in
       <sys/time.h> as:
  
            struct timeval {
                 long tv_sec;      /* seconds since Jan. 1, 1970 */
                 long tv_usec;     /* and microseconds */
            };
  
            struct timezone {
                 int  tz_minuteswest;   /* of Greenwich */
                 int  tz_dsttime;  /* type of dst correction to apply */
            };
  
       The timezone structure indicates the local time zone (meas-
       ured in minutes of time westward from Greenwich), and a flag
       that, if nonzero, indicates that Daylight Saving time
       applies locally during the appropriate part of the year.

   RESULT
       Returns 0 when successful and -1 with specific error code in 
       errno in case of an error. No error codes are specified,
       however.
       
   NOTES
       gettimeofday() uses GetSysTime() function of the timer.device,
       which is new to V36 of the device.

       Time zone information is taken from the locale.library, if it
       is available (it is included in all Amiga systems from 2.1 and
       up). Otherwise the environment variable "TZ" is consulted. If
       it fails, the time zone is initialized to the GMT.

       Global variable TimerBase _must_ be initialized before
       gettimeofday() is called. This is normally done automatically
       by the autoinit module (timerinit.c) included in the net.lib.

   SEE ALSO
       timer.device/GetSysTime()
net.lib/herror                                                 net.lib/herror

   NAME
       herror - print name resolver error message to stderr.

   SYNOPSIS
       #include <clib/netlib_protos.h>

       herror(banner)
       void herror(const char *)

   FUNCTION
       The herror() function finds the error message corresponding to the
       current value of host error using the SocketBaseTags() and writes
       it, followed by a newline, to the stderr. If the argument string
       is non-NULL it is used as a prefix to the message string and
       separated from it by a colon and space (`: '). If the argument is
       NULL only the error message string is printed.

   NOTES
       The herror() function requires the stdio functions to be linked.

   SEE ALSO
       <netinclude:netdb.h>, SocketBaseTagList(), perror()

net.lib/init_inet_daemon                             net.lib/init_inet_daemon

   NAME
       init_inet_daemon - obtain socket accepted by the inetd

   SYNOPSIS
       int init_inet_daemon(void);

   FUNCTION
       Obtain the server socket accepted by the inetd, the Internet
       super-server.

   RETURN VALUES
       socket descriptor if successful, -1 with specific error code
       on errno otherwise.

   ERRORS
       ENXIO     - The process was not started by the inetd.

   NOTES
       If the process was started by the inetd, but the ObtainSocket()
       call fails, then this function exit()s with some specific exit
       code, so that inetd can clean up the unobtained socket.

       Use the net.lib function set_socket_stdio() to redirect stdio,
       stdout and stderr to the returned socket, if necessary.

   SEE ALSO
       serveraccept(), set_socket_stdio(), bsdsocket/ObtainSocket(),
       netutil/inetd
net.lib/lineRead                                             net.lib/lineRead

   NAME
       lineRead -- read newline terminated strings from socket

   SYNOPSIS
       initLineRead(rl, fd, lftype, bufsize)

       void initLineRead(struct LineRead *, int, int, int);


       length = lineRead(rl)

       int lineread(struct LineRead *);


   FUNCTION
       lineRead() reads newline terminated strings from given descriptor
       very efficiently. All the options needed are set by calling
       initLineRead(): rl is the pointer to lineread structure previously
       allocated. fd is the (socket) descriptor where reading is to be
       done. lftype can have following 3 values:

           RL_LFNOTREQ - Newline terminated strings are returned unless
                         there is no newlines left in currently buffered
                         input. In this case remaining buffer is returned.

           RL_LFREQLF  - If there is no newlines left in currently buffered
                         input the remaining input data is copied at the
                         start of buffer. Caller is informed that next
                         call will fill the buffer (and it may block).
                         Lines are always returned with newline at the end
                         unless the string is longer than whole buffer.

           RL_LFREQNUL  - Like LF_REQLF, but remaining newline is removed.
                         Note here that lenght is one longer that actual
                         string length since line that has only one
                         newline at the end would return length as 0
                         which indigate string incomplete condition.

       bufsize is used to tell lineread how big the receive buffer is.
       always put RL_BUFSIZE here since that value is used to determine
       the memory allocated for the buffer. This option is given to you
       so you may decide to use different buffer size than the default
       1024.

       lineRead() returns the newline terminated string in rl_line field
       of lineread structure. Return values of lineRead() are:

            1 - RL_BUFSIZE     - normal length of returned string.

            0                  - If zero is returned just after select(),
                                 end-of-file condition has occurred.
                                 Otherwise string is not completed yet.
                                 Make sure you call select() (or use non-
                                 blocking IO) if you don't want next call
                                 to block.

           -1                  - if rl_Line field of lineread structure
                                 is NULL, it indicates error condition.
                                 If rl_Line points to start of string
                                 buffer, input string has been longer
                                 than buffer. In this case rl_Line points
                                 to zero terminated string of length
                                 RL_BUFSIZE.

       You may modify the zero terminated string returned by lineRead() in
       any way, but memory around the string is private lineread memory.

   EXAMPLE
       /*
        * The following code shows how to use lineread with select()
        */
       #ifdef USE_LOW_MEMORY_BUFFER
       #define RL_BUFSIZE 256
       #endif

       #include <sys/types.h>
       #ifdef AMIGA
       #include <bsdsocket.h>
       #endif
       #include <lineread.h>

       #define NULL 0

       ...

       main_loop(int sock)
       {
         struct LineRead * rl;
         int length;
         fd_set reafdfs;

         if (rl = (struct LineRead *)AllocMem(sizeof (*rl), 0)) {

           initLineRead(rl, sock, LF_REQLF, RL_BUFSIZE);

           FD_ZERO(&readfds);

           while(1) {
             FD_SET(sock, &readfds);

             if (select(sock + 1, &readfds, NULL, NULL, NULL)) < 0) {
               perror("select");
               break;
             }
             if (FD_ISSET(sock, &readfds))
               if ((length = lineRead(rl)) == 0) /* EOF */
                 break;
               do {
                 if (length > 0)
                   write(1, rl->rl_Line, length); /* stdout. write() for */
                                                  /* speed demonstration */
                 else { /* length == -1 */
                   if (rl->rl_Line == NULL); {
                     perror("lineRead");
                     break;
                   }
                   else {
                     fprintf(stderr, "lineread input buffer overflow!\n");
                     write(1, rl->rl_Line, RL_BUFSIZE);
                     write(1, "\n", 1);
                   }
                 }
               } while ((length = lineRead(rl)) != 0); /* 0 -> do select() */
           }
         FreeMem(rl, sizeof (*rl);
         }
         else
           fprintf("AllocMem: Out Of memory\n");
       }

    PORTABILITY
       The source modules lineread.c and lineread.h should compile
       in UNIX machines as is.

    SEE ALSO
       charRead(), bsdsocket.library/recv()

net.lib/lstat                                                   net.lib/lstat

   SEE ALSO
       stat()

net.lib/perror                                                 net.lib/perror

   NAME
       perror - socket error messages

   SYNOPSIS
       extern int errno;

       #include <stdio.h>

       perror(banner)
       void perror(const char *)

   FUNCTION
       The perror() function finds the error message corresponding to the
       current value of the global variable errno and writes it, followed
       by a newline, to the stderr. If the argument string is non-NULL it
       is preappended to the message string and separated from it by a
       colon and space (`: '). If string is NULL only the error message
       string is printed.

   NOTES
       The perror() function requires the stdio functions to be linked.

   SEE ALSO
       strerror(), PrintNetFault(), <netinclude:sys/errno.h>

net.lib/popen                                                   net.lib/popen
   NAME
       popen, pclose - initiate I/O to/from a process

   SYNOPSIS
       #include <stdio.h>

       FILE *popen(command, type)
       char *command, *type;

       pclose(stream)
       FILE *stream;

   DESCRIPTION
       The arguments to popen are pointers to null-terminated
       strings containing respectively a command line and an
       I/O mode, either "r" for reading or "w" for writing.  It
       creates a pipe between the calling process and the command
       to be executed.  The value returned is a stream pointer that
       can be used (as appropriate) to write to the standard input
       of the command or read from its standard output.

       A stream opened by popen **MUST** be closed by pclose, which
       waits for the associated process to terminate and returns
       the exit status of the command.

       Because stdio files are shared, a type "r" command may be
       used as an input filter, and a type "w" as an output filter.

   DIAGNOSTICS
       Popen returns a null pointer if files or processes cannot be
       created.

       Pclose returns -1 if stream is not associated with a
       `popened' command.

   AUTHOR
       Original version by Rick Schaeffer <ricks@isc-br.isc-br.com>
/

include <stdio.h>
include <stdlib.h>
include <string.h>
include <stdarg.h>

include <exec/types.h>
include <exec/memory.h>
include <dos/dos.h>
include <dos/dosextens.h>
include <dos/record.h>
include <dos/dostags.h>

include <proto/exec.h>
include <proto/dos.h>
include <clib/alib_protos.h>

include <errno.h>

define NOTDEF

xtern char *mktemp(char *);

truct POmsg {
   struct Message  POm;
   int     rc;
   char        *cmd;
   struct Library  *DOSBase;
   };


truct pstruct {
   FILE    *fptr;
   struct POmsg    childmsg;
   };

define MAXPIPES    6
tatic struct pstruct poarray[MAXPIPES];

tatic int childprocess(void);

ILE *popen(const char *cmd, const char *mode)

   static char tempname[] = "pipe:pXXX.XXX";
   char        *pname,redir[20];
   short       i;
   int         pmode;
   struct pstruct  *poptr;
   BPTR            pfd;
   struct Process  *child;
   struct CommandLineInterface *cli;
   BPTR Binfh, Boutfh;
   ULONG closeinp, closeoutp;
   ULONG stacksize;
   struct Process *thistask;

   /* First, get pointers to our process and cli structs */
   thistask = (struct Process *) FindTask(NULL);
   cli = Cli();
   poptr = NULL;

   /* now find an open pipe (we currently only allow 6 simultaneously
      open pipes) */
   for (i=0; i<MAXPIPES; i++) {
       if (poarray[i].fptr == NULL) {
           poptr = &poarray[i];
           break;
           }
       }
   if (poptr == NULL) {
       fprintf(stderr,"popen: Unable to find an open pipe\n");
       errno = EMFILE;
       return(NULL);
       }
   if (strcmp(mode,"r") == 0)
       pmode = MODE_NEWFILE;
   else if (strcmp(mode,"w") == 0)
       pmode = MODE_OLDFILE;
   else {
       fprintf(stderr,"popen: Mode must be 'r' or 'w'\n");
       errno = EINVAL;
       return(NULL);
       }

   /* Try to make a guaranteed unique file name for the pipe */
   strcpy(redir,tempname);
   redir[5] = 'a' + i;

   pname = mktemp(redir);            /* set up a pipe: file name */

   /* Now get the child's stack and priority set up */
   if (cli)
       stacksize = cli->cli_DefaultStack << 2;
   else
       stacksize = thistask->pr_StackSize;

   /* Open the side of the pipe for the child */
   pfd = Open(pname,pmode);
   if (pfd == 0) {
       errno = __io2errno(_OSERR = IoErr());
       fprintf(stderr,"popen: Unable to open pipe file\n");
       return(NULL);
       }

   /* set up the tags for the new process */
   if (pmode == MODE_NEWFILE) {
       Binfh     = (Tag) Input();
       Boutfh    = (Tag) pfd;
       closeinp  = FALSE;
       closeoutp = TRUE;
       }
   else {
       Binfh     = (Tag) pfd;
       Boutfh    = (Tag) Output();
       closeinp  = TRUE;
       closeoutp = FALSE;
       }

   /* create the command.  since the "System" function runs through
      the default shell, we need to tell it not to fail so that we
      ALWAYS get back the exit status.  This wouldn't be necessary
      if the CLI created by the System function inherited the parent's
      FAILAT level
   */
   poptr->childmsg.cmd = malloc(strlen(cmd) + 15);
   strcpy(poptr->childmsg.cmd,"failat 9999\n");
   strcat(poptr->childmsg.cmd,cmd);

   /* Create a port that we can get the child's exit status through */
   poptr->childmsg.POm.mn_ReplyPort = CreateMsgPort();
   poptr->childmsg.POm.mn_Node.ln_Type = NT_MESSAGE;
   poptr->childmsg.POm.mn_Node.ln_Pri = 0;
   if (poptr->childmsg.POm.mn_ReplyPort == 0) {
       fprintf(stderr,"popen: Couldn't create message port\n");
       errno = ENOMEM;
       return(NULL);
       }

   /* Now we can start the new process.  NOTE: this is actually going
      to create a process consisting ONLY of the function "childprocess"
      which can be seen below.  childprocess() then runs the command
      passed in the startup message.
   */
   child = CreateNewProcTags(
       NP_Entry,   (Tag) childprocess,
       NP_Input,   Binfh,
       NP_Output,  Boutfh,
       NP_CloseInput,  closeinp,
       NP_CloseOutput, closeoutp,
       NP_StackSize,   stacksize,
       NP_Cli,     TRUE,
       TAG_DONE
       );

   poptr->childmsg.DOSBase = (struct Library *)DOSBase;

   /* now pass the child the startup message */
   PutMsg(&child->pr_MsgPort,(struct Message *) &poptr->childmsg);

   /* Now open our side of the pipe */
   poptr->fptr = fopen(pname,mode);
   if (poptr->fptr == NULL) {
       fprintf(stderr,"popen: Unable to open pipe file %s\n",pname);
       DeleteMsgPort(poptr->childmsg.POm.mn_ReplyPort);
       return(NULL);
       }
   return(poptr->fptr);


ILE *popenl(const char *arg0, ...)

   va_list ap;
   char argbuf[512], *mode;

   strcpy(argbuf, arg0);
   va_start(ap, arg0);
   while(1)
   {
       char *s = va_arg(ap, char *);

       if(s == NULL)
       {
       strcat(argbuf, "\n");
       break;
       } /* if */

       strcat(argbuf, " ");

       if(strchr(s, ' '))
       {
       strcat(argbuf, "\"");
       strcat(argbuf, s);
       strcat(argbuf, "\"");
       }
       else
       {
       strcat(argbuf, s);
       } /* if */
   }
   mode = va_arg(ap, char *);
   va_end(ap);

   return(popen(argbuf, mode));

 /* popenl */

nt pclose(FILE *fptr)

   short       i;

   /* Figure out which pipe we used for this file */
   for (i=0; i<MAXPIPES; i++)
       if (poarray[i].fptr == fptr)
           break;
   if (i >= MAXPIPES) {
       fprintf(stderr,"popen: DISASTER...couldn't find file pointer in pclose
\n");
       exit(1);
       }

   /* close the file */
   fclose(fptr);

   /* now wait for the exit status */
   WaitPort(poarray[i].childmsg.POm.mn_ReplyPort);
   poarray[i].fptr = NULL;

   /* clean things up */
   DeletePort(poarray[i].childmsg.POm.mn_ReplyPort);
   free(poarray[i].childmsg.cmd);
   return(poarray[i].childmsg.rc);


* SAS/C autoinitialization for cleanup! */
oid __stdargs _STD_4000_popen(void)

   short i;

   /* Close all the open pipes! */
   for(i=0; i<MAXPIPES; i++)
   {
       if(poarray[i].fptr)
       {
           pclose(poarray[i].fptr);
       } /* if */
   } /* for */

 /* _STD_4000_popen */

ifdef NOTDEF

har *mktemp(char * template)

   register char *cp;
   register unsigned long val;

   cp = template;
   cp += strlen(cp);
   for (val = (unsigned long) FindTask(0L) ; ; )
       if (*--cp == 'X') {
           *cp = val%10 + '0';
           val /= 10;
       } else if (*cp != '.')
           break;

   if (*++cp != 0) {
       *cp = 'A';
       while (access(template, 0) == 0) {
           if (*cp == 'Z') {
               *template = 0;
               break;
           }
           ++*cp;
       }
   } else {
       if (access(template, 0) == 0)
           *template = 0;
   }
   return template;


endif

* WATCH OUT! This only works without __saveds because of the special
  SAS/C 6.1 tricks I use! Check the output with omd! */
tatic int __interrupt childprocess(void)

   struct ExecBase *SysBase = *((struct ExecBase **)4);
   struct Library *DOSBase;
   struct Process  *me;
   struct POmsg    *startupmsg;
   int             i = RETURN_FAIL;

   /* find our process structure */
   me = (struct Process *) FindTask(NULL);

   /* Wait for the parent to kick us off */
   WaitPort(&me->pr_MsgPort);

   /* Get the command to execute */
   startupmsg = (struct POmsg *) GetMsg(&me->pr_MsgPort);

   DOSBase = startupmsg->DOSBase;

   if(DOSBase)
   {
       /* Now run the command.  stdin and stdout are already set up */
       i = SystemTags(startupmsg->cmd,
              SYS_UserShell, 1,
              TAG_DONE);
   } /* if */

   if(i > 0)
   {
       /* UNIX compatibility ... */
       i <<= 8;
   } /* if */

   startupmsg->rc = i;
   /* pass the exit code back to the parent */
   ReplyMsg((struct Message *) startupmsg);
   return(0);

net.lib/PrintNetFault                                   net.lib/PrintNetFault

   NAME
       PrintNetFault - socket error messages

   SYNOPSIS
       PrintNetFault(code, banner)
       void PrintNetFault(LONG, const UBYTE *)

   FUNCTION
       The PrintNetFault() function finds the error message corresponding
       to the code and writes it, followed by a newline, to the standard
       error or Output() filehandle. If the argument string is non-NULL it
       is preappended to the message string and separated from it by a
       colon and space (`: '). If string is NULL only the error message
       string is printed.

   NOTES
       The PrintNetFault() function uses the DOS IO functions.

   SEE ALSO
       strerror(), perror(), <netinclude:sys/errno.h>

net.lib/PrintUserFault                                 net.lib/PrintUserFault

   NAME
       PrintUserFault - socket error messages

   SYNOPSIS
       PrintUserFault(code, banner)
       void PrintUserFault(LONG, const UBYTE *)

   FUNCTION
       The PrintUserFault() function finds the error message corresponding to
       the code and writes it, followed by a newline, to the standard error
       or Output() filehandle. If the argument string is non-NULL it is
       preappended to the message string and separated from it by a colon and
       space (`: '). If string is NULL only the error message string is
       printed.

   NOTES
       The PrintUserFault() function used the DOS io functions.  It is
       recommended to use PrintUserFault() when the standard C IO functions
       are not otherwise in use.

   SEE ALSO
       strerror(), perror(), <netinclude:sys/errno.h>

net.lib/rcmd                                                     net.lib/rcmd

   NAME
       rcmd, rresvport - routines for returning a stream to a remote command

   SYNOPSIS
       #include <clib/socket_protos.h>

       int rcmd(char **ahost, int inport, const char *locuser, 
                const char *remuser, const char *cmd, int *fd2p);

       int rresvport(int *port);

   FUNCTION
       The rcmd() function is used by the super-user to execute a command on
       a remote machine using an authentication scheme based on reserved port
       numbers.  The rresvport() function returns a descriptor to a socket
       with an address in the privileged port space.  Both functions are
       present in the same file and are used by the rsh command (among
       others).

       The rcmd() function looks up the host *ahost using gethostbyname(),
       returning -1 if the host does not exist.  Otherwise *ahost is set to
       the standard name of the host and a connection is established to a
       server residing at the well-known Internet port inport.

       If the connection succeeds, a socket in the Internet domain of type
       SOCK_STREAM is returned to the caller, and given to the remote command
       as stdin and stdout. If fd2p is non-zero, then an auxiliary channel to
       a control process will be set up, and a descriptor for it will be
       placed in *fd2p. The control process will return diagnostic output
       from the command (unit 2) on this channel, and will also accept bytes
       on this channel as being UNIX signal numbers, to be forwarded to the
       process group of the command.  If fd2p is 0, then the stderr (unit 2
       of the remote command) will be made the same as the stdout and no
       provision is made for sending arbitrary signals to the remote process,
       although you may be able to get its attention by using out-of-band
       data.

       The protocol is described in detail in netutil/rshd.

       The rresvport() function is used to obtain a socket with a privileged
       address bound to it.  This socket is suitable for use by rcmd() and
       several other functions.  Privileged Internet ports are those in the
       range 0 to 1023.  Only the super-user is allowed to bind an address of
       this sort to a socket.

   DIAGNOSTICS
       The rcmd() function returns a valid socket descriptor on success.  It
       returns -1 on error and prints a diagnostic message on the standard
       error.

       The rresvport() function returns a valid, bound socket descriptor on
       success.  It returns -1 on error with the global value errno set
       according to the reason for failure.  The error code EAGAIN is
       overloaded to mean `All network ports in use.'

   SEE ALSO
       netutil/rlogin,  netutil/rsh,  rexec(),  netutil/rexecd,
       netutil/rlogind, netutil/rshd

net.lib/serveraccept                                     net.lib/serveraccept

   NAME
       serveraccept - Accept a server connection on named port

   SYNOPSIS
       socket = serveraccept(name, peer);

       long serveraccept(char *, struct sockaddr_in *);

   DESCRIPTION
       The serveraccept() library call binds a socket to the named Internet
       TCP port. Then it listens the socket and accepts the connection to
       the port. The peer's socket address is returned in sockaddr pointed
       by sockaddr argument.

       The port name is resolved by getservbyname() call. A numeric value
       for port name is also accepted.
 
       This module is meant for daemon developing.

   INPUTS
       name   - port name or numeric string.
       peer   - pointer to struct sockaddr_in

   RESULT
       socket - positive socket id for success or -1 for failure.

       peer   - sockaddr_in structure containing peer's internet address.
                Note that on error, the structure containing peer address
                is not necessarily updated.

   SEE ALSO
       bsdsocket/accept, bsdsocket/getservbyname

net.lib/set_socket_stdio                             net.lib/set_socket_stdio

   NAME
       set_socket_stdio - redirect stdio to/from a socket

   SYNOPSIS
       int set_socket_stdio(int sock);

   FUNCTION
       Redirect stdio (stdin, stdout and stderr) to/from socket 'sock'.
       This is done by dup2()'ing 'sock' to the level 1 files underneath
       the stdin, stdout and stderr.

       The original 'sock' reference is closed on successful return, so
       the socket descriptor given as argument should not be used after
       this function returns (successfully).

   RETURN VALUES
       0 if successful, -1 on error. Global variable 'errno' contains
       the specific error code set by the failing function.

   NOTES
       This module pulls in the link library stdio modules.

   SEE ALSO
       dup2()
net.lib/sleep                                                   net.lib/sleep

   NAME
       sleep - suspend process execution for the specified time

   SYNOPSIS
       void sleep(unsigned int seconds);

   FUNCTION
       Process execution is suspended for number of seconds specified in 
       'seconds'. The sleep will be aborted if any of the break signals
       specified for the process is received (only CTRL-C by default).

   PORTABILITY
       UNIX

   INPUTS
       'seconds' - number of seconds to sleep.

   RESULT
       Does not return a value.

   NOTES
       The sleep is implemented as a single select() call with all other
       than time out argument as NULL.

   SEE ALSO
       bsdsocket.library/select()

net.lib/SPrintf                                               net.lib/SPrintf

   NAME        
       SPrintf -- formatted print to a buffer

   SYNOPSIS
       len = SPrintf(Buffer, FormatString, Arguments...)
       len = VSPrintf(Buffer, FormatString, ap)

       ULONG SPrintf(STRPTR, const char *, ...)
       ULONG VSPrintf(STRPTR, const char *,  va_list)

   FUNCTION
       Prints to a simple buffer or to a CSource buffer. These functions
       are similar to C-library sprintf() with RawDoFmt() formatting.

   INPUTS
       Buffer - Pointer to buffer.
       FormatString - This is a printf()-style format string as defined
           in exec.library/RawDoFmt().
       Arguments - as in printf() .

       Result - Pointer to CSource structure.

   RESULT
       Number of characters printed.

   EXAMPLE
       SPrintf(mybuf, "line=%ld, val=%lx\n", 
               __LINE__, very.interesting->value);

   BUGS
       Function SPrintf() assumes that no print is longer than 1024 chars.
       It does not check for buffer owerflow (there no way to check, the
       definition of sprintf misses it).

       SPrintf strings are truncated to maximum of 1024 chars (including
       final NUL)

   SEE ALSO
       exec.library/RawDoFmt()

net.lib/stat                                                     net.lib/stat

   NAME
       stat, lstat, fstat - get file status

   SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>

       success = stat(path, buf)

       int stat(const char *, struct stat *);

       success =  lstat(path, buf);

       int lstat(const char *, struct stat *);

       success = fstat(fd, buf);

       int fstat(int, struct stat *);

   DESCRIPTION
       The stat() function obtains information about the file pointed to by
       path. Read, write or execute permission of the named file is not
       required, but all directories listed in the path name leading to the
       file must be seachable.

       Lstat() is like stat() except in the case where the named file is a
       symbolic link, in which case lstat() returns information about the
       link, while stat() returns information about the file the link
       references.

       The fstat() obtains the same information about an open file known by
       the file descriptor fd, such as would be obtained by an open call.

       Buf is a pointer to a stat() structure as defined by <sys/stat.h>
       (shown below) and into which information is placed concerning the
       file.

          struct  stat
          {
            dev_t   st_dev;         /* unique device id */ 
            ino_t   st_ino;         /* inode of file (key block) */ 
            mode_t  st_mode;        /* Unix style mode */ 
            ushort  st_nlink;       /* number of links (unimplemented) */ 
            uid_t   st_uid;         /* owner's user ID */ 
            gid_t   st_gid;         /* owner's group ID */ 
            dev_t   st_rdev;        /* special file ID (unimplemented) */ 
            off_t   st_size;        /* file size */ 
            time_t  st_atime;       /* Time of last access */ 
            time_t  st_mtime;       /* Last modification time */ 
            time_t  st_ctime;       /* Last file status change time */ 
            long    st_blksize;     /* Size of disk block */ 
            long    st_blocks;      /* Size in blocks */ 
            long    st_dosmode;     /* DOS protection bits */ 
            short   st_type;        /* DOS file type */ 
            char   *st_comment;     /* DOS file comment */ 
          };

       The time-related fields of struct stat have same contents, time when
       file data last modified.

       The status information word st_mode has bits as follows:

         #define S_ISUID  0004000    /* set user id on execution */ 
         #define S_ISGID  0002000    /* set group id on execution */ 
         #define S_ISVTX  0001000    /* save swapped text even after use */ 
         #define S_IRUSR  0000400    /* read permission for owner */ 
         #define S_IWUSR  0000200    /* write permission for owner */ 
         #define S_IXUSR  0000100    /* execute permission for owner */ 
         #define S_IRGRP  0000040    /* read permission for group */ 
         #define S_IWGRP  0000020    /* write permission for group */ 
         #define S_IXGRP  0000010    /* execute permission for group */ 
         #define S_IROTH  0000004    /* read permission for other */ 
         #define S_IWOTH  0000002    /* write permission for other */ 
         #define S_IXOTH  0000001    /* execute permission for other */ 
         #define S_IFCHR  0020000    /* character special */ 
         #define S_IFDIR  0040000    /* directory */ 
         #define S_IFBLK  0060000    /* block special */ 
         #define S_IFREG  0100000    /* regular */ 
         #define S_IFLNK  0120000    /* symbolic link */ 
         #define S_IFSOCK 0140000    /* socket */ 
         #define S_IFIFO  0010000    /* named pipe (fifo) */ 

       For a list of access modes, see <sys/stat.h>, access(2) and chmod(2).

   RETURN VALUES
       Upon successful completion a value of 0 is returned.  Otherwise, a
       value of -1 is returned and errno is set to indicate the error.

   ERRORS
       The functions stat() and lstat() will fail if:

       [ENOTDIR]       A component of the path prefix is not a directory.

       [ENAMETOOLONG]  A component of a pathname exceeded 255 characters,
                       or an entire path name exceeded 1023 characters.

       [ENOENT]        The named file does not exist.

       [ELOOP]         Too many symbolic links were encountered in
                       translating the pathname.

       [EACCES]        Search permission is denied for a component of the
                       path prefix.

       [EFAULT]        Buf or name points to an invalid address.

       [EIO]           An I/O error occurred while reading from or writing
                       to the file system.

       The function fstat() will fail if:

       [EBADF]   fd is not a valid open file descriptor.

       [EFAULT]  Buf points to an invalid address.

       [EIO]     An I/O error occurred while reading from or writing to the
                 file system.

   SEE ALSO
       chmod(),  chown()

   BUGS 
       Applying fstat to a socket returns a zero'd buffer.

net.lib/strerror                                             net.lib/strerror

   NAME
       strerror -- return the text for given error number

   SYNOPSIS
       string = strerror(error);

       char * strerror(int);

   FUNCTION
       This function returns pointer to the (English) string describing the
       error code given as argument. The error strings are defined for the
       error codes defined in <sys/errno.h>.

   NOTES
       The string pointed to by the return value should not be modified by
       the program, but may be overwritten by a subsequent call to this
       function.

   BUGS
       The strerror() prototype should be 
       const char *strerror(unsigned int); 
       However, the SAS C includes define it differently.

   SEE ALSO
       <netinclude:sys/errno.h>, perror(), PrintNetFault()
net.lib/syslog                                                 net.lib/syslog

   NAME   
       openlog(), closelog(), setlogmask() -- syslog utility functions

   SYNOPSIS
       #include <syslog.h>
       
       openlog(ident, logopt, facility);

       void openlog(const char *, int, int);

       closelog();

       void closelog(void);

       oldmask = setlogmask(maskpri);
       
       int setlogmask(int);
       
   FUNCTION
       openlog() can be called to initialize the log file, if special
       processing is needed.  ident is a string that precedes every
       message.  logopt is a mask of bits, logically OR'ed together,
       indicating logging options.  The values for logopt are:
       
            LOG_PID             Log the process ID with each message;
                                useful for identifying instantiations
                                of daemons.

            LOG_CONS            Force writing messages to the console
                                if unable to send it to syslogd.
                                This option is safe to use in daemon
                                processes that have no controlling
                                terminal because syslog() forks
                                before opening the console.

            LOG_NDELAY          Open the connection to syslogd
                                immediately.  Normally, the open is
                                delayed until the first message is
                                logged.  This is useful for programs
                                that need to manage the order in
                                which file descriptors are allocated.

            LOG_NOWAIT          Do not wait for children forked to
                                log messages on the console. Obsolete
                                in AmiTCP/IP, since AmiTCP/IP does
                                not fork.

       facility encodes a default facility to be assigned to all
       messages written subsequently by syslog() with no explicit
       facility encoded. The facility codes are:

            LOG_KERN            Messages generated by the kernel.
                                These cannot be generated by any user
                                processes.

            LOG_USER            Messages generated by random user
                                processes.  This is the default
                                facility identifier if none is
                                specified.

            LOG_MAIL            The mail system.

            LOG_DAEMON          System daemons, such as inetd, ftpd,
                                etc.

            LOG_AUTH            The authorization system: login, su,
                                getty, etc.

            LOG_LPR             The line printer spooling system: lp,
                                lpsched, etc.

            LOG_LOCAL0          Reserved for local use. Similarly for
                                LOG_LOCAL1 through LOG_LOCAL7.


       closelog() closes the log file.

       setlogmask() sets the log priority mask to maskpri and returns
       the previous mask.  Calls to syslog() with a priority not set
       in maskpri are rejected.  The mask for an individual priority
       pri is calculated by the macro LOG_MASK(pri); the mask for all
       priorities up to and including toppri is given by the macro
       LOG_UPTO(toppri).  By default, all priorities are logged.

   EXAMPLES
       who logs a message regarding some sort of unexpected and
       serious error:

           syslog(LOG_ALERT, "who: internal error 23");

       ftpd uses openlog() to arrange to log its process ID, to log
       to the console if necessary, and to log in the name of the
       daemon facility:

           openlog("ftpd", LOG_PID|LOG_CONS, LOG_DAEMON);

       Arrange to log messages only at levels LOG_ERR and lower:

           setlogmask(LOG_UPTO(LOG_ERR));

       Typical usage of syslog() to log a connection:

           syslog(LOG_INFO, "Connection from host %d", CallingHost);

       If the facility has not been set with openlog(), it defaults
       to LOG_USER.

       Explicitly set the facility for this message:

           syslog(LOG_INFO|LOG_LOCAL2, "foobar error: %m");
       
   NOTES
       openlog() does not copy and store the ident string internally;
       it stores only the character pointer.  Therefore it is the
       responsibility of the programmer to make sure that the ident
       argument points to the correct string while syslog() is being
       called. 

   BUGS
       Most of the logopt and facility codes are currently being
       ignored by AmiTCP/IP, but they should be used for future
       compatibility.

       The autoinit module of the net.lib tells the program name 
       to the AmiTCP/IP at program startup, so use of the openlog()
       for that purpose only is not necessary.

   AUTHOR
       syslog() was developed by the University of California,
       Berkeley.

   SEE ALSO
       bsdsocket.library/syslog(), bsdsocket.library/SocketBaseTagList()
net.lib/usleep                                                 net.lib/usleep

   NAME
       usleep - suspend process execution for the specified time

   SYNOPSIS
       void usleep(unsigned int microseconds);

   FUNCTION
       Process execution is suspended for number of microseconds
       specified in 'microseconds'. The sleep will be aborted if any
       of the break signals specified for the process is received
       (only CTRL-C by default).

   PORTABILITY
       UNIX

   INPUTS
       'microseconds' - number of microseconds to sleep.

   RESULT
       Does not return a value.

   NOTES
       The sleep is implemented as a single select() call with all other
       than time out argument as NULL.

   SEE ALSO
       bsdsocket.library/select()

net.lib/utime                                                   net.lib/utime

   NAME
       utime - set file access and modification times

   SYNOPSIS
       #include <utime.h>

       int error = utime(const char *name, const struct utimbuf *times)

   FUNCTION
       The access and modification times for the file 'name' are modified
       according to the 'times'. If 'times' is NULL, the times are set to
       systems current time.

   PORTABILITY
       UNIX

   INPUTS
       'name'  - the name of the file to be affected.

       'times' - pointer to a structure containing the time values,
                 defined in <utime.h> as:

                     struct utimbuf {
                         time_t actime;        /* Access time */
                         time_t modtime;        /* Modification time */
                     };

                 Both times are in units of seconds since Jan. 1, 1970,
                 Greenwich Mean Time.

                 If the 'times' is given as the NULL pointer, the current
                 time is used.

   RESULT
       Returns 0 when successful and -1 with specific error code in errno in
       case of an error.

   NOTES
       Since AmigaDOS files have only one time stamp, both access and
       modification times cannot be supported. Since the AmigaDOS file date
       is the modification time, only the 'modtime' field of the 'times' is
       used.

       The conversion from 1.1.1970 based GMT to 1.1.1978 based local time is
       done with external long __local_to_GMT, which is defined and
       initialized by the timerinit.c module included in the net.lib.

   SEE ALSO
       dos.library/DateStamp(), dos.library/SetFileDate(), net.lib/timerinit

netd.lib/dosio_init                                       netd.lib/dosio_init

   NAME
       dosio_init - (std) io macros to dos.library V37 or newer

   SYNOPSIS
       long _STI_500_dosio_init(void)

   FUNCTION
       This function initializes the file table used by the stdio
       look-a-like macros defined in <netinclude:stdio.h>.

       These macros are taken in to use by defining the symbol
       `USE_DOSIO' before including any include files.  When this is
       done, the normal stdio prototypes are replaced with macros,
       which call the corresponding dos.library functions.  The
       netd.lib provides the initialization function mentioned above
       and the functions VSPrintf(), SPrintf(), VCSPrintf() and
       CSPrintf(), which are not found from the dos.library.

       The stdio macros provided are suitable for stdin, stdout and
       stderr usage. No file opening function (fopen()) is provided,
       so the use is quite limited.

       The netd.lib version of the net.lib is compiled with this
       USE_DOSIO, so you will want to use that instead of the
       net.lib to make your executable smaller if your own program
       does not use stdio of the C runtime library.

   NOTES
       The stdio macros rely on dos.library 37 or newer being present.

       The autoinitialization and autotermination functions are features
       specific to the SAS C6.  However, these functions can be used with
       other (ANSI) C compilers, too. Example follows:

       /* at start of main() */

       if (_STI_500_dosio_init() != 0)
          exit(20);

   BUGS
       The same autoinitialization won't work for both SAS C 6.3 and SAS C
       6.50 or latter.  Only way to terminate an initialization function is
       by exit() call with SAS C 6.3 binary.  If an autoinitialization
       function is terminated by exit() call with SAS C 6.50 binary, the
       autotermination functions won't be called.  Due this braindamage
       the libraries must be separately compiled for each compiler version.

   SEE ALSO


