summaryrefslogtreecommitdiffstats
path: root/share/doc
diff options
context:
space:
mode:
authorgrog <grog@FreeBSD.org>2002-05-19 06:11:50 +0000
committergrog <grog@FreeBSD.org>2002-05-19 06:11:50 +0000
commit2d717c6f9fef0e6fda4e55557f91a024e131d99e (patch)
tree80e9a5cb42879768b1004d8e85813a58aca2fb9d /share/doc
parent559398948817b63678ed666fe48329ec9dd78db7 (diff)
downloadFreeBSD-src-2d717c6f9fef0e6fda4e55557f91a024e131d99e.zip
FreeBSD-src-2d717c6f9fef0e6fda4e55557f91a024e131d99e.tar.gz
Initial checkin: 4.4BSD version. These files need to be updated with
current license information and adapted to the FreeBSD build environment before they will build. Approved by: David Taylor <davidt@caldera.com>
Diffstat (limited to 'share/doc')
-rw-r--r--share/doc/psd/04.uprog/Makefile11
-rw-r--r--share/doc/psd/04.uprog/p.mac39
-rw-r--r--share/doc/psd/04.uprog/p049
-rw-r--r--share/doc/psd/04.uprog/p155
-rw-r--r--share/doc/psd/04.uprog/p2242
-rw-r--r--share/doc/psd/04.uprog/p3436
-rw-r--r--share/doc/psd/04.uprog/p4567
-rw-r--r--share/doc/psd/04.uprog/p5544
-rw-r--r--share/doc/psd/04.uprog/p6328
-rw-r--r--share/doc/psd/04.uprog/p829
-rw-r--r--share/doc/psd/04.uprog/p9647
11 files changed, 2947 insertions, 0 deletions
diff --git a/share/doc/psd/04.uprog/Makefile b/share/doc/psd/04.uprog/Makefile
new file mode 100644
index 0000000..c8b6abc
--- /dev/null
+++ b/share/doc/psd/04.uprog/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+# $FreeBSD$
+
+DIR= psd/04.uprog
+SRCS= p.mac p0 p1 p2 p3 p4 p5 p6 p8 p9
+MACROS= -ms
+
+paper.ps: ${SRCS}
+ ${ROFF} ${MAC} ${SRCS} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/share/doc/psd/04.uprog/p.mac b/share/doc/psd/04.uprog/p.mac
new file mode 100644
index 0000000..32d9030
--- /dev/null
+++ b/share/doc/psd/04.uprog/p.mac
@@ -0,0 +1,39 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p.mac 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.de UC
+\&\\$3\s-1\\$1\\s0\&\\$2
+..
+.de IT
+\&\\$3\fI\\$1\fR\^\&\\$2
+..
+.de UL
+\%\&\\$3\f(CW\s-1\\$1\s0\fR\&\\$2
+..
+.de P1
+.DS I .5i
+.nf
+.ft CW
+.ps \\n(PS-1
+.vs \\n(VS-1
+..
+.de P2
+.ps \\n(PS
+.vs \\n(VS
+.ft R
+.DE
+..
+.hy 14 \"2=not last lines; 4= no -xx; 8=no xx-
+.am SH
+.ft R
+..
+.am NH
+.ft R
+..
+.am TL
+.ft R
+..
diff --git a/share/doc/psd/04.uprog/p0 b/share/doc/psd/04.uprog/p0
new file mode 100644
index 0000000..4a59311
--- /dev/null
+++ b/share/doc/psd/04.uprog/p0
@@ -0,0 +1,49 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p0 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.if n .ls 1
+.\" .TM 78-1273-9 39199 39199-11
+.\" .ND October 2, 1978
+.\" .old TM 75-1273-11 October 22, 1975
+.OH 'UNIX Programming \(em Second Edition''PSD:4-%'
+.EH 'PSD:4-%''UNIX Programming \(em Second Edition'
+.TL
+UNIX Programming \(em Second Edition
+.AU "MH 2C-518" 6021
+Brian W. Kernighan
+.AU "MH 2C-517" 3770
+Dennis M. Ritchie
+.AI
+AT&T Bell Laboratories
+Murray Hill, NJ 07974
+.AB
+.PP
+This paper is an introduction to programming on
+the
+.UX
+system.
+The emphasis is on how to write programs that interface
+to the operating system,
+either directly or through the standard I/O library.
+The topics discussed include
+.IP " \(bu"
+handling command arguments
+.IP " \(bu"
+rudimentary I/O; the standard input and output
+.IP " \(bu"
+the standard I/O library; file system access
+.IP " \(bu"
+low-level I/O: open, read, write, close, seek
+.IP " \(bu"
+processes: exec, fork, pipes
+.IP " \(bu"
+signals \(em interrupts, etc.
+.PP
+There is also an appendix which describes
+the standard I/O library in detail.
+.AE
+.\" .CS 17 0 17 0 0 4
diff --git a/share/doc/psd/04.uprog/p1 b/share/doc/psd/04.uprog/p1
new file mode 100644
index 0000000..32efd31
--- /dev/null
+++ b/share/doc/psd/04.uprog/p1
@@ -0,0 +1,55 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p1 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.if n .ls 2
+.if t .tr |\(or
+.NH
+INTRODUCTION
+.PP
+This paper describes how to write
+programs
+that interface with the
+.UC UNIX
+operating system in a non-trivial way.
+This includes programs that use files by name,
+that use pipes,
+that invoke other commands as they run,
+or that attempt to catch interrupts and other signals
+during execution.
+.PP
+The document collects material which is scattered
+throughout several sections of
+.I
+The
+.UC UNIX
+Programmer's Manual
+.R
+[1]
+for Version 7
+.UC UNIX .
+There is no attempt to be complete;
+only generally useful material is dealt with.
+It is assumed that you will be programming in C,
+so you must be able to read the language
+roughly up to the level of
+.I
+The C Programming Language
+.R
+[2].
+Some of the material in sections 2 through 4
+is based on
+topics covered more carefully there.
+You should also be familiar with
+.UC UNIX
+itself
+at least
+to the level of
+.I
+.UC UNIX
+for Beginners
+.R
+[3].
diff --git a/share/doc/psd/04.uprog/p2 b/share/doc/psd/04.uprog/p2
new file mode 100644
index 0000000..8f4ff04
--- /dev/null
+++ b/share/doc/psd/04.uprog/p2
@@ -0,0 +1,242 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p2 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.NH
+BASICS
+.NH 2
+Program Arguments
+.PP
+When a C program is run as a command,
+the arguments on the command line are made available
+to the
+function
+.UL main
+as an argument count
+.UL argc
+and an array
+.UL argv
+of
+pointers to
+character strings
+that contain
+the arguments.
+By convention,
+.UL argv[0]
+is the command name itself,
+so
+.UL argc
+is always greater than 0.
+.PP
+The following program illustrates the mechanism:
+it simply echoes its arguments
+back to the terminal.
+(This is essentially the
+.UL echo
+command.)
+.P1
+main(argc, argv) /* echo arguments */
+int argc;
+char *argv[];
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ printf("%s%c", argv[i], (i<argc-1) ? ' ' : '\en');
+}
+.P2
+.UL argv
+is a pointer to an array
+whose individual elements are pointers to arrays of characters;
+each is terminated by
+.UL \e0 ,
+so they can be treated as strings.
+The program starts by printing
+.UL argv[1]
+and loops until it has printed them all.
+.PP
+The argument count and the arguments
+are parameters to
+.UL main .
+If you want to keep them around so other
+routines can get at them, you must
+copy them to external variables.
+.NH 2
+The ``Standard Input'' and ``Standard Output''
+.PP
+The simplest input mechanism is to read the ``standard input,''
+which is generally the user's terminal.
+The function
+.UL getchar
+returns the next input character each time it is called.
+A file may be substituted for the terminal by
+using the
+.UL <
+convention:
+if
+.UL prog
+uses
+.UL getchar ,
+then
+the command line
+.P1
+prog <file
+.P2
+causes
+.UL prog
+to read
+.UL file
+instead of the terminal.
+.UL prog
+itself need know nothing about where its input
+is coming from.
+This is also true if the input comes from another program via
+the
+.U
+pipe mechanism:
+.P1
+otherprog | prog
+.P2
+provides the standard input for
+.UL prog
+from the standard output of
+.UL otherprog.
+.PP
+.UL getchar
+returns the value
+.UL EOF
+when it encounters the end of file
+(or an error)
+on whatever you are reading.
+The value of
+.UL EOF
+is normally defined to be
+.UL -1 ,
+but it is unwise to take any advantage
+of that knowledge.
+As will become clear shortly,
+this value is automatically defined for you when
+you compile a program,
+and need not be of any concern.
+.PP
+Similarly,
+.UL putchar(c)
+puts the character
+.UL c
+on the ``standard output,''
+which is also by default the terminal.
+The output can be captured on a file
+by using
+.UL > :
+if
+.UL prog
+uses
+.UL putchar ,
+.P1
+prog >outfile
+.P2
+writes the standard output on
+.UL outfile
+instead of the terminal.
+.UL outfile
+is created if it doesn't exist;
+if it already exists, its previous contents are overwritten.
+And a pipe can be used:
+.P1
+prog | otherprog
+.P2
+puts the standard output of
+.UL prog
+into the standard input of
+.UL otherprog.
+.PP
+The function
+.UL printf ,
+which formats output in various ways,
+uses
+the same mechanism as
+.UL putchar
+does,
+so calls to
+.UL printf
+and
+.UL putchar
+may be intermixed in any order;
+the output will appear in the order of the calls.
+.PP
+Similarly, the function
+.UL scanf
+provides for formatted input conversion;
+it will read the standard input and break it
+up into strings, numbers, etc.,
+as desired.
+.UL scanf
+uses the same mechanism as
+.UL getchar ,
+so calls to them may also be intermixed.
+.PP
+Many programs
+read only one input and write one output;
+for such programs I/O
+with
+.UL getchar ,
+.UL putchar ,
+.UL scanf ,
+and
+.UL printf
+may be entirely adequate,
+and it is almost always enough to get started.
+This is particularly true if
+the
+.UC UNIX
+pipe facility is used to connect the output of
+one program to the input of the next.
+For example, the following program
+strips out all ascii control characters
+from its input
+(except for newline and tab).
+.P1
+#include <stdio.h>
+
+main() /* ccstrip: strip non-graphic characters */
+{
+ int c;
+ while ((c = getchar()) != EOF)
+ if ((c >= ' ' && c < 0177) || c == '\et' || c == '\en')
+ putchar(c);
+ exit(0);
+}
+.P2
+The line
+.P1
+#include <stdio.h>
+.P2
+should appear at the beginning of each source file.
+It causes the C compiler to read a file
+.IT /usr/include/stdio.h ) (
+of
+standard routines and symbols
+that includes the definition of
+.UL EOF .
+.PP
+If it is necessary to treat multiple files,
+you can use
+.UL cat
+to collect the files for you:
+.P1
+cat file1 file2 ... | ccstrip >output
+.P2
+and thus avoid learning how to access files from a program.
+By the way,
+the call to
+.UL exit
+at the end is not necessary to make the program work
+properly,
+but it assures that any caller
+of the program will see a normal termination status
+(conventionally 0)
+from the program when it completes.
+Section 6 discusses status returns in more detail.
diff --git a/share/doc/psd/04.uprog/p3 b/share/doc/psd/04.uprog/p3
new file mode 100644
index 0000000..9e258bb
--- /dev/null
+++ b/share/doc/psd/04.uprog/p3
@@ -0,0 +1,436 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p3 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.NH
+THE STANDARD I/O LIBRARY
+.PP
+The ``Standard I/O Library''
+is a collection of routines
+intended to provide
+efficient
+and portable
+I/O services
+for most C programs.
+The standard I/O library is available on each system that supports C,
+so programs that confine
+their system interactions
+to its facilities
+can be transported from one system to another essentially without change.
+.PP
+In this section, we will discuss the basics of the standard I/O library.
+The appendix contains a more complete description of its capabilities.
+.NH 2
+File Access
+.PP
+The programs written so far have all
+read the standard input and written the standard output,
+which we have assumed are magically pre-defined.
+The next step
+is to write a program that accesses
+a file that is
+.ul
+not
+already connected to the program.
+One simple example is
+.IT wc ,
+which counts the lines, words and characters
+in a set of files.
+For instance, the command
+.P1
+wc x.c y.c
+.P2
+prints the number of lines, words and characters
+in
+.UL x.c
+and
+.UL y.c
+and the totals.
+.PP
+The question is how to arrange for the named files
+to be read \(em
+that is, how to connect the file system names
+to the I/O statements which actually read the data.
+.PP
+The rules are simple.
+Before it can be read or written
+a file has to be
+.ul
+opened
+by the standard library function
+.UL fopen .
+.UL fopen
+takes an external name
+(like
+.UL x.c
+or
+.UL y.c ),
+does some housekeeping and negotiation with the operating system,
+and returns an internal name
+which must be used in subsequent
+reads or writes of the file.
+.PP
+This internal name is actually a pointer,
+called a
+.IT file
+.IT pointer ,
+to a structure
+which contains information about the file,
+such as the location of a buffer,
+the current character position in the buffer,
+whether the file is being read or written,
+and the like.
+Users don't need to know the details,
+because part of the standard I/O definitions
+obtained by including
+.UL stdio.h
+is a structure definition called
+.UL FILE .
+The only declaration needed for a file pointer
+is exemplified by
+.P1
+FILE *fp, *fopen();
+.P2
+This says that
+.UL fp
+is a pointer to a
+.UL FILE ,
+and
+.UL fopen
+returns a pointer to
+a
+.UL FILE .
+.UL FILE \& (
+is a type name, like
+.UL int ,
+not a structure tag.
+.PP
+The actual call to
+.UL fopen
+in a program
+is
+.P1
+fp = fopen(name, mode);
+.P2
+The first argument of
+.UL fopen
+is the
+name
+of the file,
+as a character string.
+The second argument is the
+mode,
+also as a character string,
+which indicates how you intend to
+use the file.
+The only allowable modes are
+read
+.UL \&"r" ), (
+write
+.UL \&"w" ), (
+or append
+.UL \&"a" ). (
+.PP
+If a file that you open for writing or appending does not exist,
+it is created
+(if possible).
+Opening an existing file for writing causes the old contents
+to be discarded.
+Trying to read a file that does not exist
+is an error,
+and there may be other causes of error
+as well
+(like trying to read a file
+when you don't have permission).
+If there is any error,
+.UL fopen
+will return the null pointer
+value
+.UL NULL
+(which is defined as zero in
+.UL stdio.h ).
+.PP
+The next thing needed is a way to read or write the file
+once it is open.
+There are several possibilities,
+of which
+.UL getc
+and
+.UL putc
+are the simplest.
+.UL getc
+returns the next character from a file;
+it needs the file pointer to tell it what file.
+Thus
+.P1
+c = getc(fp)
+.P2
+places in
+.UL c
+the next character from the file referred to by
+.UL fp ;
+it returns
+.UL EOF
+when it reaches end of file.
+.UL putc
+is the inverse of
+.UL getc :
+.P1
+putc(c, fp)
+.P2
+puts the character
+.UL c
+on the file
+.UL fp
+and returns
+.UL c .
+.UL getc
+and
+.UL putc
+return
+.UL EOF
+on error.
+.PP
+When a program is started, three files are opened automatically,
+and file pointers are provided for them.
+These files are the standard input,
+the standard output,
+and the standard error output;
+the corresponding file pointers are
+called
+.UL stdin ,
+.UL stdout ,
+and
+.UL stderr .
+Normally these are all connected to the terminal,
+but
+may be redirected to files or pipes as described in
+Section 2.2.
+.UL stdin ,
+.UL stdout
+and
+.UL stderr
+are pre-defined in the I/O library
+as the standard input, output and error files;
+they may be used anywhere an object of type
+.UL FILE\ *
+can be.
+They are
+constants, however,
+.ul
+not
+variables,
+so don't try to assign to them.
+.PP
+With some of the preliminaries out of the way,
+we can now write
+.IT wc .
+The basic design
+is one that has been found
+convenient for many programs:
+if there are command-line arguments, they are processed in order.
+If there are no arguments, the standard input
+is processed.
+This way the program can be used stand-alone
+or as part of a larger process.
+.P1
+#include <stdio.h>
+
+main(argc, argv) /* wc: count lines, words, chars */
+int argc;
+char *argv[];
+{
+ int c, i, inword;
+ FILE *fp, *fopen();
+ long linect, wordct, charct;
+ long tlinect = 0, twordct = 0, tcharct = 0;
+
+ i = 1;
+ fp = stdin;
+ do {
+ if (argc > 1 && (fp=fopen(argv[i], "r")) == NULL) {
+ fprintf(stderr, "wc: can't open %s\en", argv[i]);
+ continue;
+ }
+ linect = wordct = charct = inword = 0;
+ while ((c = getc(fp)) != EOF) {
+ charct++;
+ if (c == '\en')
+ linect++;
+ if (c == ' ' || c == '\et' || c == '\en')
+ inword = 0;
+ else if (inword == 0) {
+ inword = 1;
+ wordct++;
+ }
+ }
+ printf("%7ld %7ld %7ld", linect, wordct, charct);
+ printf(argc > 1 ? " %s\en" : "\en", argv[i]);
+ fclose(fp);
+ tlinect += linect;
+ twordct += wordct;
+ tcharct += charct;
+ } while (++i < argc);
+ if (argc > 2)
+ printf("%7ld %7ld %7ld total\en", tlinect, twordct, tcharct);
+ exit(0);
+}
+.P2
+The function
+.UL fprintf
+is identical to
+.UL printf ,
+save that the first argument is a file pointer
+that specifies the file to be
+written.
+.PP
+The function
+.UL fclose
+is the inverse of
+.UL fopen ;
+it breaks the connection between the file pointer and the external name
+that was established by
+.UL fopen ,
+freeing the
+file pointer for another file.
+Since there is a limit on the number
+of files
+that a program may have open simultaneously,
+it's a good idea to free things when they are no longer needed.
+There is also another reason to call
+.UL fclose
+on an output file
+\(em it flushes the buffer
+in which
+.UL putc
+is collecting output.
+.UL fclose \& (
+is called automatically for each open file
+when a program terminates normally.)
+.NH 2
+Error Handling \(em Stderr and Exit
+.PP
+.UL stderr
+is assigned to a program in the same way that
+.UL stdin
+and
+.UL stdout
+are.
+Output written on
+.UL stderr
+appears on the user's terminal
+even if the standard output is redirected.
+.IT wc
+writes its diagnostics on
+.UL stderr
+instead of
+.UL stdout
+so that if one of the files can't
+be accessed for some reason,
+the message
+finds its way to the user's terminal instead of disappearing
+down a pipeline
+or into an output file.
+.PP
+The program actually signals errors in another way,
+using the function
+.UL exit
+to terminate program execution.
+The argument of
+.UL exit
+is available to whatever process
+called it (see Section 6),
+so the success or failure
+of the program can be tested by another program
+that uses this one as a sub-process.
+By convention, a return value of 0
+signals that all is well;
+non-zero values signal abnormal situations.
+.PP
+.UL exit
+itself
+calls
+.UL fclose
+for each open output file,
+to flush out any buffered output,
+then calls
+a routine named
+.UL _exit .
+The function
+.UL _exit
+causes immediate termination without any buffer flushing;
+it may be called directly if desired.
+.NH 2
+Miscellaneous I/O Functions
+.PP
+The standard I/O library provides several other I/O functions
+besides those we have illustrated above.
+.PP
+Normally output with
+.UL putc ,
+etc., is buffered (except to
+.UL stderr );
+to force it out immediately, use
+.UL fflush(fp) .
+.PP
+.UL fscanf
+is identical to
+.UL scanf ,
+except that its first argument is a file pointer
+(as with
+.UL fprintf )
+that specifies the file from which the input comes;
+it returns
+.UL EOF
+at end of file.
+.PP
+The functions
+.UL sscanf
+and
+.UL sprintf
+are identical to
+.UL fscanf
+and
+.UL fprintf ,
+except that the first argument names a character string
+instead of a file pointer.
+The conversion is done from the string
+for
+.UL sscanf
+and into it for
+.UL sprintf .
+.PP
+.UL fgets(buf,\ size,\ fp)
+copies the next line from
+.UL fp ,
+up to and including a newline,
+into
+.UL buf ;
+at most
+.UL size-1
+characters are copied;
+it returns
+.UL NULL
+at end of file.
+.UL fputs(buf,\ fp)
+writes the string in
+.UL buf
+onto file
+.UL fp .
+.PP
+The function
+.UL ungetc(c,\ fp)
+``pushes back'' the character
+.UL c
+onto the input stream
+.UL fp ;
+a subsequent call to
+.UL getc ,
+.UL fscanf ,
+etc.,
+will encounter
+.UL c .
+Only one character of pushback per file is permitted.
diff --git a/share/doc/psd/04.uprog/p4 b/share/doc/psd/04.uprog/p4
new file mode 100644
index 0000000..baddb52
--- /dev/null
+++ b/share/doc/psd/04.uprog/p4
@@ -0,0 +1,567 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p4 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.NH
+LOW-LEVEL I/O
+.PP
+This section describes the
+bottom level of I/O on the
+.UC UNIX
+system.
+The lowest level of I/O in
+.UC UNIX
+provides no buffering or any other services;
+it is in fact a direct entry into the operating system.
+You are entirely on your own,
+but on the other hand,
+you have the most control over what happens.
+And since the calls and usage are quite simple,
+this isn't as bad as it sounds.
+.NH 2
+File Descriptors
+.PP
+In the
+.UC UNIX
+operating system,
+all input and output is done
+by reading or writing files,
+because all peripheral devices, even the user's terminal,
+are files in the file system.
+This means that a single, homogeneous interface
+handles all communication between a program and peripheral devices.
+.PP
+In the most general case,
+before reading or writing a file,
+it is necessary to inform the system
+of your intent to do so,
+a process called
+``opening'' the file.
+If you are going to write on a file,
+it may also be necessary to create it.
+The system checks your right to do so
+(Does the file exist?
+Do you have permission to access it?),
+and if all is well,
+returns a small positive integer
+called a
+.ul
+file descriptor.
+Whenever I/O is to be done on the file,
+the file descriptor is used instead of the name to identify the file.
+(This is roughly analogous to the use of
+.UC READ(5,...)
+and
+.UC WRITE(6,...)
+in Fortran.)
+All
+information about an open file is maintained by the system;
+the user program refers to the file
+only
+by the file descriptor.
+.PP
+The file pointers discussed in section 3
+are similar in spirit to file descriptors,
+but file descriptors are more fundamental.
+A file pointer is a pointer to a structure that contains,
+among other things, the file descriptor for the file in question.
+.PP
+Since input and output involving the user's terminal
+are so common,
+special arrangements exist to make this convenient.
+When the command interpreter (the
+``shell'')
+runs a program,
+it opens
+three files, with file descriptors 0, 1, and 2,
+called the standard input,
+the standard output, and the standard error output.
+All of these are normally connected to the terminal,
+so if a program reads file descriptor 0
+and writes file descriptors 1 and 2,
+it can do terminal I/O
+without worrying about opening the files.
+.PP
+If I/O is redirected
+to and from files with
+.UL <
+and
+.UL > ,
+as in
+.P1
+prog <infile >outfile
+.P2
+the shell changes the default assignments for file descriptors
+0 and 1
+from the terminal to the named files.
+Similar observations hold if the input or output is associated with a pipe.
+Normally file descriptor 2 remains attached to the terminal,
+so error messages can go there.
+In all cases,
+the file assignments are changed by the shell,
+not by the program.
+The program does not need to know where its input
+comes from nor where its output goes,
+so long as it uses file 0 for input and 1 and 2 for output.
+.NH 2
+Read and Write
+.PP
+All input and output is done by
+two functions called
+.UL read
+and
+.UL write .
+For both, the first argument is a file descriptor.
+The second argument is a buffer in your program where the data is to
+come from or go to.
+The third argument is the number of bytes to be transferred.
+The calls are
+.P1
+n_read = read(fd, buf, n);
+
+n_written = write(fd, buf, n);
+.P2
+Each call returns a byte count
+which is the number of bytes actually transferred.
+On reading,
+the number of bytes returned may be less than
+the number asked for,
+because fewer than
+.UL n
+bytes remained to be read.
+(When the file is a terminal,
+.UL read
+normally reads only up to the next newline,
+which is generally less than what was requested.)
+A return value of zero bytes implies end of file,
+and
+.UL -1
+indicates an error of some sort.
+For writing, the returned value is the number of bytes
+actually written;
+it is generally an error if this isn't equal
+to the number supposed to be written.
+.PP
+The number of bytes to be read or written is quite arbitrary.
+The two most common values are
+1,
+which means one character at a time
+(``unbuffered''),
+and
+512,
+which corresponds to a physical blocksize on many peripheral devices.
+This latter size will be most efficient,
+but even character at a time I/O
+is not inordinately expensive.
+.PP
+Putting these facts together,
+we can write a simple program to copy
+its input to its output.
+This program will copy anything to anything,
+since the input and output can be redirected to any file or device.
+.P1
+#define BUFSIZE 512 /* best size for PDP-11 UNIX */
+
+main() /* copy input to output */
+{
+ char buf[BUFSIZE];
+ int n;
+
+ while ((n = read(0, buf, BUFSIZE)) > 0)
+ write(1, buf, n);
+ exit(0);
+}
+.P2
+If the file size is not a multiple of
+.UL BUFSIZE ,
+some
+.UL read
+will return a smaller number of bytes
+to be written by
+.UL write ;
+the next call to
+.UL read
+after that
+will return zero.
+.PP
+It is instructive to see how
+.UL read
+and
+.UL write
+can be used to construct
+higher level routines like
+.UL getchar ,
+.UL putchar ,
+etc.
+For example,
+here is a version of
+.UL getchar
+which does unbuffered input.
+.P1
+#define CMASK 0377 /* for making char's > 0 */
+
+getchar() /* unbuffered single character input */
+{
+ char c;
+
+ return((read(0, &c, 1) > 0) ? c & CMASK : EOF);
+}
+.P2
+.UL c
+.ul
+must
+be declared
+.UL char ,
+because
+.UL read
+accepts a character pointer.
+The character being returned must be masked with
+.UL 0377
+to ensure that it is positive;
+otherwise sign extension may make it negative.
+(The constant
+.UL 0377
+is appropriate for the
+.UC PDP -11
+but not necessarily for other machines.)
+.PP
+The second version of
+.UL getchar
+does input in big chunks,
+and hands out the characters one at a time.
+.P1
+#define CMASK 0377 /* for making char's > 0 */
+#define BUFSIZE 512
+
+getchar() /* buffered version */
+{
+ static char buf[BUFSIZE];
+ static char *bufp = buf;
+ static int n = 0;
+
+ if (n == 0) { /* buffer is empty */
+ n = read(0, buf, BUFSIZE);
+ bufp = buf;
+ }
+ return((--n >= 0) ? *bufp++ & CMASK : EOF);
+}
+.P2
+.NH 2
+Open, Creat, Close, Unlink
+.PP
+Other than the default
+standard input, output and error files,
+you must explicitly open files in order to
+read or write them.
+There are two system entry points for this,
+.UL open
+and
+.UL creat
+[sic].
+.PP
+.UL open
+is rather like the
+.UL fopen
+discussed in the previous section,
+except that instead of returning a file pointer,
+it returns a file descriptor,
+which is just an
+.UL int .
+.P1
+int fd;
+
+fd = open(name, rwmode);
+.P2
+As with
+.UL fopen ,
+the
+.UL name
+argument
+is a character string corresponding to the external file name.
+The access mode argument
+is different, however:
+.UL rwmode
+is 0 for read, 1 for write, and 2 for read and write access.
+.UL open
+returns
+.UL -1
+if any error occurs;
+otherwise it returns a valid file descriptor.
+.PP
+It is an error to
+try to
+.UL open
+a file that does not exist.
+The entry point
+.UL creat
+is provided to create new files,
+or to re-write old ones.
+.P1
+fd = creat(name, pmode);
+.P2
+returns a file descriptor
+if it was able to create the file
+called
+.UL name ,
+and
+.UL -1
+if not.
+If the file
+already exists,
+.UL creat
+will truncate it to zero length;
+it is not an error to
+.UL creat
+a file that already exists.
+.PP
+If the file is brand new,
+.UL creat
+creates it with the
+.ul
+protection mode
+specified by
+the
+.UL pmode
+argument.
+In the
+.UC UNIX
+file system,
+there are nine bits of protection information
+associated with a file,
+controlling read, write and execute permission for
+the owner of the file,
+for the owner's group,
+and for all others.
+Thus a three-digit octal number
+is most convenient for specifying the permissions.
+For example,
+0755
+specifies read, write and execute permission for the owner,
+and read and execute permission for the group and everyone else.
+.PP
+To illustrate,
+here is a simplified version of
+the
+.UC UNIX
+utility
+.IT cp ,
+a program which copies one file to another.
+(The main simplification is that our version
+copies only one file,
+and does not permit the second argument
+to be a directory.)
+.P1
+#define NULL 0
+#define BUFSIZE 512
+#define PMODE 0644 /* RW for owner, R for group, others */
+
+main(argc, argv) /* cp: copy f1 to f2 */
+int argc;
+char *argv[];
+{
+ int f1, f2, n;
+ char buf[BUFSIZE];
+
+ if (argc != 3)
+ error("Usage: cp from to", NULL);
+ if ((f1 = open(argv[1], 0)) == -1)
+ error("cp: can't open %s", argv[1]);
+ if ((f2 = creat(argv[2], PMODE)) == -1)
+ error("cp: can't create %s", argv[2]);
+
+ while ((n = read(f1, buf, BUFSIZE)) > 0)
+ if (write(f2, buf, n) != n)
+ error("cp: write error", NULL);
+ exit(0);
+}
+.P2
+.P1
+error(s1, s2) /* print error message and die */
+char *s1, *s2;
+{
+ printf(s1, s2);
+ printf("\en");
+ exit(1);
+}
+.P2
+.PP
+As we said earlier,
+there is a limit (typically 15-25)
+on the number of files which a program
+may have open simultaneously.
+Accordingly, any program which intends to process
+many files must be prepared to re-use
+file descriptors.
+The routine
+.UL close
+breaks the connection between a file descriptor
+and an open file,
+and frees the
+file descriptor for use with some other file.
+Termination of a program
+via
+.UL exit
+or return from the main program closes all open files.
+.PP
+The function
+.UL unlink(filename)
+removes the file
+.UL filename
+from the file system.
+.NH 2
+Random Access \(em Seek and Lseek
+.PP
+File I/O is normally sequential:
+each
+.UL read
+or
+.UL write
+takes place at a position in the file
+right after the previous one.
+When necessary, however,
+a file can be read or written in any arbitrary order.
+The
+system call
+.UL lseek
+provides a way to move around in
+a file without actually reading
+or writing:
+.P1
+lseek(fd, offset, origin);
+.P2
+forces the current position in the file
+whose descriptor is
+.UL fd
+to move to position
+.UL offset ,
+which is taken relative to the location
+specified by
+.UL origin .
+Subsequent reading or writing will begin at that position.
+.UL offset
+is
+a
+.UL long ;
+.UL fd
+and
+.UL origin
+are
+.UL int 's.
+.UL origin
+can be 0, 1, or 2 to specify that
+.UL offset
+is to be
+measured from
+the beginning, from the current position, or from the
+end of the file respectively.
+For example,
+to append to a file,
+seek to the end before writing:
+.P1
+lseek(fd, 0L, 2);
+.P2
+To get back to the beginning (``rewind''),
+.P1
+lseek(fd, 0L, 0);
+.P2
+Notice the
+.UL 0L
+argument;
+it could also be written as
+.UL (long)\ 0 .
+.PP
+With
+.UL lseek ,
+it is possible to treat files more or less like large arrays,
+at the price of slower access.
+For example, the following simple function reads any number of bytes
+from any arbitrary place in a file.
+.P1
+get(fd, pos, buf, n) /* read n bytes from position pos */
+int fd, n;
+long pos;
+char *buf;
+{
+ lseek(fd, pos, 0); /* get to pos */
+ return(read(fd, buf, n));
+}
+.P2
+.PP
+In pre-version 7
+.UC UNIX ,
+the basic entry point to the I/O system
+is called
+.UL seek .
+.UL seek
+is identical to
+.UL lseek ,
+except that its
+.UL offset
+argument is an
+.UL int
+rather than a
+.UL long .
+Accordingly,
+since
+.UC PDP -11
+integers have only 16 bits,
+the
+.UL offset
+specified
+for
+.UL seek
+is limited to 65,535;
+for this reason,
+.UL origin
+values of 3, 4, 5 cause
+.UL seek
+to multiply the given offset by 512
+(the number of bytes in one physical block)
+and then interpret
+.UL origin
+as if it were 0, 1, or 2 respectively.
+Thus to get to an arbitrary place in a large file
+requires two seeks, first one which selects
+the block, then one which
+has
+.UL origin
+equal to 1 and moves to the desired byte within the block.
+.NH 2
+Error Processing
+.PP
+The routines discussed in this section,
+and in fact all the routines which are direct entries into the system
+can incur errors.
+Usually they indicate an error by returning a value of \-1.
+Sometimes it is nice to know what sort of error occurred;
+for this purpose all these routines, when appropriate,
+leave an error number in the external cell
+.UL errno .
+The meanings of the various error numbers are
+listed
+in the introduction to Section II
+of the
+.I
+.UC UNIX
+Programmer's Manual,
+.R
+so your program can, for example, determine if
+an attempt to open a file failed because it did not exist
+or because the user lacked permission to read it.
+Perhaps more commonly,
+you may want to print out the
+reason for failure.
+The routine
+.UL perror
+will print a message associated with the value
+of
+.UL errno ;
+more generally,
+.UL sys\_errno
+is an array of character strings which can be indexed
+by
+.UL errno
+and printed by your program.
diff --git a/share/doc/psd/04.uprog/p5 b/share/doc/psd/04.uprog/p5
new file mode 100644
index 0000000..4987e11
--- /dev/null
+++ b/share/doc/psd/04.uprog/p5
@@ -0,0 +1,544 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p5 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.NH
+PROCESSES
+.PP
+It is often easier to use a program written
+by someone else than to invent one's own.
+This section describes how to
+execute a program from within another.
+.NH 2
+The ``System'' Function
+.PP
+The easiest way to execute a program from another
+is to use
+the standard library routine
+.UL system .
+.UL system
+takes one argument, a command string exactly as typed
+at the terminal
+(except for the newline at the end)
+and executes it.
+For instance, to time-stamp the output of a program,
+.P1
+main()
+{
+ system("date");
+ /* rest of processing */
+}
+.P2
+If the command string has to be built from pieces,
+the in-memory formatting capabilities of
+.UL sprintf
+may be useful.
+.PP
+Remember than
+.UL getc
+and
+.UL putc
+normally buffer their input;
+terminal I/O will not be properly synchronized unless
+this buffering is defeated.
+For output, use
+.UL fflush ;
+for input, see
+.UL setbuf
+in the appendix.
+.NH 2
+Low-Level Process Creation \(em Execl and Execv
+.PP
+If you're not using the standard library,
+or if you need finer control over what
+happens,
+you will have to construct calls to other programs
+using the more primitive routines that the standard
+library's
+.UL system
+routine is based on.
+.PP
+The most basic operation is to execute another program
+.ul
+without
+.IT returning ,
+by using the routine
+.UL execl .
+To print the date as the last action of a running program,
+use
+.P1
+execl("/bin/date", "date", NULL);
+.P2
+The first argument to
+.UL execl
+is the
+.ul
+file name
+of the command; you have to know where it is found
+in the file system.
+The second argument is conventionally
+the program name
+(that is, the last component of the file name),
+but this is seldom used except as a place-holder.
+If the command takes arguments, they are strung out after
+this;
+the end of the list is marked by a
+.UL NULL
+argument.
+.PP
+The
+.UL execl
+call
+overlays the existing program with
+the new one,
+runs that, then exits.
+There is
+.ul
+no
+return to the original program.
+.PP
+More realistically,
+a program might fall into two or more phases
+that communicate only through temporary files.
+Here it is natural to make the second pass
+simply an
+.UL execl
+call from the first.
+.PP
+The one exception to the rule that the original program never gets control
+back occurs when there is an error, for example if the file can't be found
+or is not executable.
+If you don't know where
+.UL date
+is located, say
+.P1
+execl("/bin/date", "date", NULL);
+execl("/usr/bin/date", "date", NULL);
+fprintf(stderr, "Someone stole 'date'\en");
+.P2
+.PP
+A variant of
+.UL execl
+called
+.UL execv
+is useful when you don't know in advance how many arguments there are going to be.
+The call is
+.P1
+execv(filename, argp);
+.P2
+where
+.UL argp
+is an array of pointers to the arguments;
+the last pointer in the array must be
+.UL NULL
+so
+.UL execv
+can tell where the list ends.
+As with
+.UL execl ,
+.UL filename
+is the file in which the program is found, and
+.UL argp[0]
+is the name of the program.
+(This arrangement is identical to the
+.UL argv
+array for program arguments.)
+.PP
+Neither of these routines provides the niceties of normal command execution.
+There is no automatic search of multiple directories \(em
+you have to know precisely where the command is located.
+Nor do you get the expansion of metacharacters like
+.UL < ,
+.UL > ,
+.UL * ,
+.UL ? ,
+and
+.UL []
+in the argument list.
+If you want these, use
+.UL execl
+to invoke the shell
+.UL sh ,
+which then does all the work.
+Construct a string
+.UL commandline
+that contains the complete command as it would have been typed
+at the terminal, then say
+.P1
+execl("/bin/sh", "sh", "-c", commandline, NULL);
+.P2
+The shell is assumed to be at a fixed place,
+.UL /bin/sh .
+Its argument
+.UL -c
+says to treat the next argument
+as a whole command line, so it does just what you want.
+The only problem is in constructing the right information
+in
+.UL commandline .
+.NH 2
+Control of Processes \(em Fork and Wait
+.PP
+So far what we've talked about isn't really all that useful by itself.
+Now we will show how to regain control after running
+a program with
+.UL execl
+or
+.UL execv .
+Since these routines simply overlay the new program on the old one,
+to save the old one requires that it first be split into
+two copies;
+one of these can be overlaid, while the other waits for the new,
+overlaying program to finish.
+The splitting is done by a routine called
+.UL fork :
+.P1
+proc_id = fork();
+.P2
+splits the program into two copies, both of which continue to run.
+The only difference between the two is the value of
+.UL proc_id ,
+the ``process id.''
+In one of these processes (the ``child''),
+.UL proc_id
+is zero.
+In the other
+(the ``parent''),
+.UL proc_id
+is non-zero; it is the process number of the child.
+Thus the basic way to call, and return from,
+another program is
+.P1
+if (fork() == 0)
+ execl("/bin/sh", "sh", "-c", cmd, NULL); /* in child */
+.P2
+And in fact, except for handling errors, this is sufficient.
+The
+.UL fork
+makes two copies of the program.
+In the child, the value returned by
+.UL fork
+is zero, so it calls
+.UL execl
+which does the
+.UL command
+and then dies.
+In the parent,
+.UL fork
+returns non-zero
+so it skips the
+.UL execl.
+(If there is any error,
+.UL fork
+returns
+.UL -1 ).
+.PP
+More often, the parent wants to wait for the child to terminate
+before continuing itself.
+This can be done with
+the function
+.UL wait :
+.P1
+int status;
+
+if (fork() == 0)
+ execl(...);
+wait(&status);
+.P2
+This still doesn't handle any abnormal conditions, such as a failure
+of the
+.UL execl
+or
+.UL fork ,
+or the possibility that there might be more than one child running simultaneously.
+(The
+.UL wait
+returns the
+process id
+of the terminated child, if you want to check it against the value
+returned by
+.UL fork .)
+Finally, this fragment doesn't deal with any
+funny behavior on the part of the child
+(which is reported in
+.UL status ).
+Still, these three lines
+are the heart of the standard library's
+.UL system
+routine,
+which we'll show in a moment.
+.PP
+The
+.UL status
+returned by
+.UL wait
+encodes in its low-order eight bits
+the system's idea of the child's termination status;
+it is 0 for normal termination and non-zero to indicate
+various kinds of problems.
+The next higher eight bits are taken from the argument
+of the call to
+.UL exit
+which caused a normal termination of the child process.
+It is good coding practice
+for all programs to return meaningful
+status.
+.PP
+When a program is called by the shell,
+the three file descriptors
+0, 1, and 2 are set up pointing at the right files,
+and all other possible file descriptors
+are available for use.
+When this program calls another one,
+correct etiquette suggests making sure the same conditions
+hold.
+Neither
+.UL fork
+nor the
+.UL exec
+calls affects open files in any way.
+If the parent is buffering output
+that must come out before output from the child,
+the parent must flush its buffers
+before the
+.UL execl .
+Conversely,
+if a caller buffers an input stream,
+the called program will lose any information
+that has been read by the caller.
+.NH 2
+Pipes
+.PP
+A
+.ul
+pipe
+is an I/O channel intended for use
+between two cooperating processes:
+one process writes into the pipe,
+while the other reads.
+The system looks after buffering the data and synchronizing
+the two processes.
+Most pipes are created by the shell,
+as in
+.P1
+ls | pr
+.P2
+which connects the standard output of
+.UL ls
+to the standard input of
+.UL pr .
+Sometimes, however, it is most convenient
+for a process to set up its own plumbing;
+in this section, we will illustrate how
+the pipe connection is established and used.
+.PP
+The system call
+.UL pipe
+creates a pipe.
+Since a pipe is used for both reading and writing,
+two file descriptors are returned;
+the actual usage is like this:
+.P1
+int fd[2];
+
+stat = pipe(fd);
+if (stat == -1)
+ /* there was an error ... */
+.P2
+.UL fd
+is an array of two file descriptors, where
+.UL fd[0]
+is the read side of the pipe and
+.UL fd[1]
+is for writing.
+These may be used in
+.UL read ,
+.UL write
+and
+.UL close
+calls just like any other file descriptors.
+.PP
+If a process reads a pipe which is empty,
+it will wait until data arrives;
+if a process writes into a pipe which
+is too full, it will wait until the pipe empties somewhat.
+If the write side of the pipe is closed,
+a subsequent
+.UL read
+will encounter end of file.
+.PP
+To illustrate the use of pipes in a realistic setting,
+let us write a function called
+.UL popen(cmd,\ mode) ,
+which creates a process
+.UL cmd
+(just as
+.UL system
+does),
+and returns a file descriptor that will either
+read or write that process, according to
+.UL mode .
+That is,
+the call
+.P1
+fout = popen("pr", WRITE);
+.P2
+creates a process that executes
+the
+.UL pr
+command;
+subsequent
+.UL write
+calls using the file descriptor
+.UL fout
+will send their data to that process
+through the pipe.
+.PP
+.UL popen
+first creates the
+the pipe with a
+.UL pipe
+system call;
+it then
+.UL fork s
+to create two copies of itself.
+The child decides whether it is supposed to read or write,
+closes the other side of the pipe,
+then calls the shell (via
+.UL execl )
+to run the desired process.
+The parent likewise closes the end of the pipe it does not use.
+These closes are necessary to make end-of-file tests work properly.
+For example, if a child that intends to read
+fails to close the write end of the pipe, it will never
+see the end of the pipe file, just because there is one writer
+potentially active.
+.P1
+#include <stdio.h>
+
+#define READ 0
+#define WRITE 1
+#define tst(a, b) (mode == READ ? (b) : (a))
+static int popen_pid;
+
+popen(cmd, mode)
+char *cmd;
+int mode;
+{
+ int p[2];
+
+ if (pipe(p) < 0)
+ return(NULL);
+ if ((popen_pid = fork()) == 0) {
+ close(tst(p[WRITE], p[READ]));
+ close(tst(0, 1));
+ dup(tst(p[READ], p[WRITE]));
+ close(tst(p[READ], p[WRITE]));
+ execl("/bin/sh", "sh", "-c", cmd, 0);
+ _exit(1); /* disaster has occurred if we get here */
+ }
+ if (popen_pid == -1)
+ return(NULL);
+ close(tst(p[READ], p[WRITE]));
+ return(tst(p[WRITE], p[READ]));
+}
+.P2
+The sequence of
+.UL close s
+in the child
+is a bit tricky.
+Suppose
+that the task is to create a child process that will read data from the parent.
+Then the first
+.UL close
+closes the write side of the pipe,
+leaving the read side open.
+The lines
+.P1
+close(tst(0, 1));
+dup(tst(p[READ], p[WRITE]));
+.P2
+are the conventional way to associate the pipe descriptor
+with the standard input of the child.
+The
+.UL close
+closes file descriptor 0,
+that is, the standard input.
+.UL dup
+is a system call that
+returns a duplicate of an already open file descriptor.
+File descriptors are assigned in increasing order
+and the first available one is returned,
+so
+the effect of the
+.UL dup
+is to copy the file descriptor for the pipe (read side)
+to file descriptor 0;
+thus the read side of the pipe becomes the standard input.
+(Yes, this is a bit tricky, but it's a standard idiom.)
+Finally, the old read side of the pipe is closed.
+.PP
+A similar sequence of operations takes place
+when the child process is supposed to write
+from the parent instead of reading.
+You may find it a useful exercise to step through that case.
+.PP
+The job is not quite done,
+for we still need a function
+.UL pclose
+to close the pipe created by
+.UL popen .
+The main reason for using a separate function rather than
+.UL close
+is that it is desirable to wait for the termination of the child process.
+First, the return value from
+.UL pclose
+indicates whether the process succeeded.
+Equally important when a process creates several children
+is that only a bounded number of unwaited-for children
+can exist, even if some of them have terminated;
+performing the
+.UL wait
+lays the child to rest.
+Thus:
+.P1
+#include <signal.h>
+
+pclose(fd) /* close pipe fd */
+int fd;
+{
+ register r, (*hstat)(), (*istat)(), (*qstat)();
+ int status;
+ extern int popen_pid;
+
+ close(fd);
+ istat = signal(SIGINT, SIG_IGN);
+ qstat = signal(SIGQUIT, SIG_IGN);
+ hstat = signal(SIGHUP, SIG_IGN);
+ while ((r = wait(&status)) != popen_pid && r != -1);
+ if (r == -1)
+ status = -1;
+ signal(SIGINT, istat);
+ signal(SIGQUIT, qstat);
+ signal(SIGHUP, hstat);
+ return(status);
+}
+.P2
+The calls to
+.UL signal
+make sure that no interrupts, etc.,
+interfere with the waiting process;
+this is the topic of the next section.
+.PP
+The routine as written has the limitation that only one pipe may
+be open at once, because of the single shared variable
+.UL popen_pid ;
+it really should be an array indexed by file descriptor.
+A
+.UL popen
+function, with slightly different arguments and return value is available
+as part of the standard I/O library discussed below.
+As currently written, it shares the same limitation.
diff --git a/share/doc/psd/04.uprog/p6 b/share/doc/psd/04.uprog/p6
new file mode 100644
index 0000000..8d93a36
--- /dev/null
+++ b/share/doc/psd/04.uprog/p6
@@ -0,0 +1,328 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p6 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.NH
+SIGNALS \(em INTERRUPTS AND ALL THAT
+.PP
+This section is concerned with how to
+deal gracefully with signals from
+the outside world (like interrupts), and with program faults.
+Since there's nothing very useful that
+can be done from within C about program
+faults, which arise mainly from illegal memory references
+or from execution of peculiar instructions,
+we'll discuss only the outside-world signals:
+.IT interrupt ,
+which is sent when the
+.UC DEL
+character is typed;
+.IT quit ,
+generated by the
+.UC FS
+character;
+.IT hangup ,
+caused by hanging up the phone;
+and
+.IT terminate ,
+generated by the
+.IT kill
+command.
+When one of these events occurs,
+the signal is sent to
+.IT all
+processes which were started
+from the corresponding terminal;
+unless other arrangements have been made,
+the signal
+terminates the process.
+In the
+.IT quit
+case, a core image file is written for debugging
+purposes.
+.PP
+The routine which alters the default action
+is
+called
+.UL signal .
+It has two arguments: the first specifies the signal, and the second
+specifies how to treat it.
+The first argument is just a number code, but the second is the
+address is either a function, or a somewhat strange code
+that requests that the signal either be ignored, or that it be
+given the default action.
+The include file
+.UL signal.h
+gives names for the various arguments, and should always be included
+when signals are used.
+Thus
+.P1
+#include <signal.h>
+ ...
+signal(SIGINT, SIG_IGN);
+.P2
+causes interrupts to be ignored, while
+.P1
+signal(SIGINT, SIG_DFL);
+.P2
+restores the default action of process termination.
+In all cases,
+.UL signal
+returns the previous value of the signal.
+The second argument to
+.UL signal
+may instead be the name of a function
+(which has to be declared explicitly if
+the compiler hasn't seen it already).
+In this case, the named routine will be called
+when the signal occurs.
+Most commonly this facility is used
+to allow the program to clean up
+unfinished business before terminating, for example to
+delete a temporary file:
+.P1
+#include <signal.h>
+
+main()
+{
+ int onintr();
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, onintr);
+
+ /* Process ... */
+
+ exit(0);
+}
+
+onintr()
+{
+ unlink(tempfile);
+ exit(1);
+}
+.P2
+.PP
+Why the test and the double call to
+.UL signal ?
+Recall that signals like interrupt are sent to
+.ul
+all
+processes started from a particular terminal.
+Accordingly, when a program is to be run
+non-interactively
+(started by
+.UL & ),
+the shell turns off interrupts for it
+so it won't be stopped by interrupts intended for foreground processes.
+If this program began by announcing that all interrupts were to be sent
+to the
+.UL onintr
+routine regardless,
+that would undo the shell's effort to protect it
+when run in the background.
+.PP
+The solution, shown above, is to test the state of interrupt handling,
+and to continue to ignore interrupts if they are already being ignored.
+The code as written
+depends on the fact that
+.UL signal
+returns the previous state of a particular signal.
+If signals were already being ignored, the process should continue to ignore them;
+otherwise, they should be caught.
+.PP
+A more sophisticated program may wish to intercept
+an interrupt and interpret it as a request
+to stop what it is doing
+and return to its own command-processing loop.
+Think of a text editor:
+interrupting a long printout should not cause it
+to terminate and lose the work
+already done.
+The outline of the code for this case is probably best written like this:
+.P1
+#include <signal.h>
+#include <setjmp.h>
+jmp_buf sjbuf;
+
+main()
+{
+ int (*istat)(), onintr();
+
+ istat = signal(SIGINT, SIG_IGN); /* save original status */
+ setjmp(sjbuf); /* save current stack position */
+ if (istat != SIG_IGN)
+ signal(SIGINT, onintr);
+
+ /* main processing loop */
+}
+.P2
+.P1
+onintr()
+{
+ printf("\enInterrupt\en");
+ longjmp(sjbuf); /* return to saved state */
+}
+.P2
+The include file
+.UL setjmp.h
+declares the type
+.UL jmp_buf
+an object in which the state
+can be saved.
+.UL sjbuf
+is such an object; it is an array of some sort.
+The
+.UL setjmp
+routine then saves
+the state of things.
+When an interrupt occurs,
+a call is forced to the
+.UL onintr
+routine,
+which can print a message, set flags, or whatever.
+.UL longjmp
+takes as argument an object stored into by
+.UL setjmp ,
+and restores control
+to the location after the call to
+.UL setjmp ,
+so control (and the stack level) will pop back
+to the place in the main routine where
+the signal is set up and the main loop entered.
+Notice, by the way, that
+the signal
+gets set again after an interrupt occurs.
+This is necessary; most signals are automatically
+reset to their default action when they occur.
+.PP
+Some programs that want to detect signals simply can't be stopped
+at an arbitrary point,
+for example in the middle of updating a linked list.
+If the routine called on occurrence of a signal
+sets a flag and then
+returns instead of calling
+.UL exit
+or
+.UL longjmp ,
+execution will continue
+at the exact point it was interrupted.
+The interrupt flag can then be tested later.
+.PP
+There is one difficulty associated with this
+approach.
+Suppose the program is reading the
+terminal when the interrupt is sent.
+The specified routine is duly called; it sets its flag
+and returns.
+If it were really true, as we said
+above, that ``execution resumes at the exact point it was interrupted,''
+the program would continue reading the terminal
+until the user typed another line.
+This behavior might well be confusing, since the user
+might not know that the program is reading;
+he presumably would prefer to have the signal take effect instantly.
+The method chosen to resolve this difficulty
+is to terminate the terminal read when execution
+resumes after the signal, returning an error code
+which indicates what happened.
+.PP
+Thus programs which catch and resume
+execution after signals should be prepared for ``errors''
+which are caused by interrupted
+system calls.
+(The ones to watch out for are reads from a terminal,
+.UL wait ,
+and
+.UL pause .)
+A program
+whose
+.UL onintr
+program just sets
+.UL intflag ,
+resets the interrupt signal, and returns,
+should usually include code like the following when it reads
+the standard input:
+.P1
+if (getchar() == EOF)
+ if (intflag)
+ /* EOF caused by interrupt */
+ else
+ /* true end-of-file */
+.P2
+.PP
+A final subtlety to keep in mind becomes important
+when signal-catching is combined with execution of other programs.
+Suppose a program catches interrupts, and also includes
+a method (like ``!'' in the editor)
+whereby other programs can be executed.
+Then the code should look something like this:
+.P1
+if (fork() == 0)
+ execl(...);
+signal(SIGINT, SIG_IGN); /* ignore interrupts */
+wait(&status); /* until the child is done */
+signal(SIGINT, onintr); /* restore interrupts */
+.P2
+Why is this?
+Again, it's not obvious but not really difficult.
+Suppose the program you call catches its own interrupts.
+If you interrupt the subprogram,
+it will get the signal and return to its
+main loop, and probably read your terminal.
+But the calling program will also pop out of
+its wait for the subprogram and read your terminal.
+Having two processes reading
+your terminal is very unfortunate,
+since the system figuratively flips a coin to decide
+who should get each line of input.
+A simple way out is to have the parent program
+ignore interrupts until the child is done.
+This reasoning is reflected in the standard I/O library function
+.UL system :
+.P1
+#include <signal.h>
+
+system(s) /* run command string s */
+char *s;
+{
+ int status, pid, w;
+ register int (*istat)(), (*qstat)();
+
+ if ((pid = fork()) == 0) {
+ execl("/bin/sh", "sh", "-c", s, 0);
+ _exit(127);
+ }
+ istat = signal(SIGINT, SIG_IGN);
+ qstat = signal(SIGQUIT, SIG_IGN);
+ while ((w = wait(&status)) != pid && w != -1)
+ ;
+ if (w == -1)
+ status = -1;
+ signal(SIGINT, istat);
+ signal(SIGQUIT, qstat);
+ return(status);
+}
+.P2
+.PP
+As an aside on declarations,
+the function
+.UL signal
+obviously has a rather strange second argument.
+It is in fact a pointer to a function delivering an integer,
+and this is also the type of the signal routine itself.
+The two values
+.UL SIG_IGN
+and
+.UL SIG_DFL
+have the right type, but are chosen so they coincide with
+no possible actual functions.
+For the enthusiast, here is how they are defined for the PDP-11;
+the definitions should be sufficiently ugly
+and nonportable to encourage use of the include file.
+.P1
+#define SIG_DFL (int (*)())0
+#define SIG_IGN (int (*)())1
+.P2
diff --git a/share/doc/psd/04.uprog/p8 b/share/doc/psd/04.uprog/p8
new file mode 100644
index 0000000..c38d79b
--- /dev/null
+++ b/share/doc/psd/04.uprog/p8
@@ -0,0 +1,29 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p8 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.SH
+References
+.LP
+.IP [1]
+K. L. Thompson and D. M. Ritchie,
+.ul
+The
+.ul
+.UC UNIX
+.ul
+Programmer's Manual,
+Bell Laboratories, 1978.
+.IP [2]
+B. W. Kernighan and D. M. Ritchie,
+.ul
+The C Programming Language,
+Prentice-Hall, Inc., 1978.
+.IP [3]
+B. W. Kernighan,
+.UC UNIX \& ``
+for Beginners \(em Second Edition.''
+Bell Laboratories, 1978.
diff --git a/share/doc/psd/04.uprog/p9 b/share/doc/psd/04.uprog/p9
new file mode 100644
index 0000000..fa534df
--- /dev/null
+++ b/share/doc/psd/04.uprog/p9
@@ -0,0 +1,647 @@
+.\" This module is believed to contain source code proprietary to AT&T.
+.\" Use and redistribution is subject to the Berkeley Software License
+.\" Agreement and your Software Agreement with AT&T (Western Electric).
+.\"
+.\" @(#)p9 8.1 (Berkeley) 6/8/93
+.\"
+.\" $FreeBSD$
+.sp 100
+.TL
+.ft R
+Appendix \(em The Standard I/O Library
+.AU
+D. M. Ritchie
+.AI
+AT&T Bell Laboratories
+Murray Hill, NJ 07974
+.PP
+The standard I/O library
+was designed with the following goals in mind.
+.IP 1.
+It must be as efficient as possible, both in time and in space,
+so that there will be no hesitation in using it
+no matter how critical the application.
+.IP 2.
+It must be simple to use, and also free of the magic
+numbers and mysterious calls
+whose use mars the understandability and portability
+of many programs using older packages.
+.IP 3.
+The interface provided should be applicable on all machines,
+whether or not the programs which implement it are directly portable
+to other systems,
+or to machines other than the PDP-11 running a version of
+.UC UNIX .
+.SH
+1. General Usage
+.PP
+Each program using the library must have the line
+.P1
+ #include <stdio.h>
+.P2
+which defines certain macros and variables.
+The routines are in the normal C library,
+so no special library argument is needed for loading.
+All names in the include file intended only for internal use begin
+with an underscore
+.UL _
+to reduce the possibility
+of collision with a user name.
+The names intended to be visible outside the package are
+.IP \f3stdin\f1 10
+The name of the standard input file
+.IP \f3stdout\f1 10
+The name of the standard output file
+.IP \f3stderr\f1 10
+The name of the standard error file
+.IP \f3EOF\f1 10
+is actually \-1, and is the value returned by
+the read routines on end-of-file or error.
+.IP \f3NULL\f1 10
+is a notation for the null pointer, returned by
+pointer-valued functions
+to indicate an error
+.IP \f3FILE\f1 10
+expands to
+.UL struct
+.UL _iob
+and is a useful
+shorthand when declaring pointers
+to streams.
+.IP \f3BUFSIZ\f1 10
+is a number (viz. 512)
+of the size suitable for an I/O buffer supplied by the user.
+See
+.UL setbuf ,
+below.
+.IP \f3getc,\ getchar,\ putc,\ putchar,\ feof,\ ferror,\ f\&ileno\f1 10
+.br
+are defined as macros.
+Their actions are described below;
+they are mentioned here
+to point out that it is not possible to
+redeclare them
+and that they are not actually functions;
+thus, for example, they may not have breakpoints set on them.
+.PP
+The routines in this package
+offer the convenience of automatic buffer allocation
+and output flushing where appropriate.
+The names
+.UL stdin ,
+.UL stdout ,
+and
+.UL stderr
+are in effect constants and may not be assigned to.
+.SH
+2. Calls
+.nr PD .4v
+.LP
+.UL FILE\ *fopen(filename,\ type)\ char\ *filename,\ *type;
+.nr PD 0
+.IP
+.br
+opens the file and, if needed, allocates a buffer for it.
+.UL filename
+is a character string specifying the name.
+.UL type
+is a character string (not a single character).
+It may be
+.UL \&"r" ,
+.UL \&"w" ,
+or
+.UL \&"a"
+to indicate
+intent to read, write, or append.
+The value returned is a file pointer.
+If it is
+.UL NULL
+the attempt to open failed.
+.ne 3
+.nr PD .4v
+.LP
+.UL FILE\ *freopen(filename,\ type,\ ioptr)\ char\ *filename,\ *type;\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+The stream named by
+.UL ioptr
+is closed, if necessary, and then reopened
+as if by
+.UL fopen .
+If the attempt to open fails,
+.UL NULL
+is returned,
+otherwise
+.UL ioptr ,
+which will now refer to the new file.
+Often the reopened stream is
+.UL stdin
+or
+.UL stdout .
+.nr PD .4v
+.LP
+.UL int\ getc(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+returns the next character from the stream named by
+.UL ioptr ,
+which is a pointer to a file such as returned by
+.UL fopen ,
+or the name
+.UL stdin .
+The integer
+.UL EOF
+is returned on end-of-file or when
+an error occurs.
+The null character
+.UL \e0
+is a legal character.
+.nr PD .4v
+.LP
+.UL int\ fgetc(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+acts like
+.UL getc
+but is a genuine function,
+not a macro,
+so it can be pointed to, passed as an argument, etc.
+.nr PD .4v
+.LP
+.UL putc(c,\ ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+.UL putc
+writes the character
+.UL c
+on the output stream named by
+.UL ioptr ,
+which is a value returned from
+.UL fopen
+or perhaps
+.UL stdout
+or
+.UL stderr .
+The character is returned as value,
+but
+.UL EOF
+is returned on error.
+.nr PD .4v
+.LP
+.UL fputc(c,\ ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+acts like
+.UL putc
+but is a genuine
+function, not a macro.
+.nr PD .4v
+.LP
+.UL fclose(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+The file corresponding to
+.UL ioptr
+is closed after any buffers are emptied.
+A buffer allocated by the I/O system is freed.
+.UL fclose
+is automatic on normal termination of the program.
+.nr PD .4v
+.LP
+.UL fflush(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+Any buffered information on the (output) stream named by
+.UL ioptr
+is written out.
+Output files are normally buffered
+if and only if they are not directed to the terminal;
+however,
+.UL stderr
+always starts off unbuffered and remains so unless
+.UL setbuf
+is used, or unless it is reopened.
+.nr PD .4v
+.LP
+.UL exit(errcode);
+.nr PD 0
+.IP
+.br
+terminates the process and returns its argument as status
+to the parent.
+This is a special version of the routine
+which calls
+.UL fflush
+for each output file.
+To terminate without flushing,
+use
+.UL _exit .
+.nr PD .4v
+.LP
+.UL feof(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+returns non-zero when end-of-file
+has occurred on the specified input stream.
+.nr PD .4v
+.LP
+.UL ferror(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+returns non-zero when an error has occurred while reading
+or writing the named stream.
+The error indication lasts until the file has been closed.
+.nr PD .4v
+.LP
+.UL getchar();
+.nr PD 0
+.IP
+.br
+is identical to
+.UL getc(stdin) .
+.nr PD .4v
+.LP
+.UL putchar(c);
+.nr PD 0
+.IP
+.br
+is identical to
+.UL putc(c,\ stdout) .
+.nr PD .4v
+.nr PD .4v
+.ne 2
+.LP
+.UL char\ *fgets(s,\ n,\ ioptr)\ char\ *s;\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+reads up to
+.UL n-1
+characters from the stream
+.UL ioptr
+into the character pointer
+.UL s .
+The read terminates with a newline character.
+The newline character is placed in the buffer
+followed by a null character.
+.UL fgets
+returns the first argument,
+or
+.UL NULL
+if error or end-of-file occurred.
+.nr PD .4v
+.nr PD .4v
+.LP
+.UL fputs(s,\ ioptr)\ char\ *s;\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+writes the null-terminated string (character array)
+.UL s
+on the stream
+.UL ioptr .
+No newline is appended.
+No value is returned.
+.nr PD .4v
+.LP
+.UL ungetc(c,\ ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+The argument character
+.UL c
+is pushed back on the input stream named by
+.UL ioptr .
+Only one character may be pushed back.
+.ne 5
+.nr PD .4v
+.LP
+.UL printf(format,\ a1,\ ...)\ char\ *format;
+.br
+.UL fprintf(ioptr,\ format,\ a1,\ ...)\ FILE\ *ioptr;\ char\ *format;
+.br
+.UL sprintf(s,\ format,\ a1,\ ...)char\ *s,\ *format;
+.br
+.nr PD 0
+.IP
+.UL printf
+writes on the standard output.
+.UL fprintf
+writes on the named output stream.
+.UL sprintf
+puts characters in the character array (string)
+named by
+.UL s .
+The specifications are as described in section
+.UL printf (3)
+of the
+.ul
+.UC UNIX
+.ul
+Programmer's Manual.
+.nr PD .4v
+.LP
+.UL scanf(format,\ a1,\ ...)\ char\ *format;
+.br
+.UL fscanf(ioptr,\ format,\ a1,\ ...)\ FILE\ *ioptr;\ char\ *format;
+.br
+.UL sscanf(s,\ format,\ a1,\ ...)\ char\ *s,\ *format;
+.nr PD 0
+.IP
+.br
+.UL scanf
+reads from the standard input.
+.UL fscanf
+reads from the named input stream.
+.UL sscanf
+reads from the character string
+supplied as
+.UL s .
+.UL scanf
+reads characters, interprets
+them according to a format, and stores the results in its arguments.
+Each routine expects as arguments
+a control string
+.UL format ,
+and a set of arguments,
+.I
+each of which must be a pointer,
+.R
+indicating where the converted input should be stored.
+.if t .sp .4v
+.UL scanf
+returns as its value the number of successfully matched and assigned input
+items.
+This can be used to decide how many input items were found.
+On end of file,
+.UL EOF
+is returned; note that this is different
+from 0, which means that the next input character does not
+match what was called for in the control string.
+.nr PD .4v
+.LP
+.UL fread(ptr,\ sizeof(*ptr),\ nitems,\ ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+reads
+.UL nitems
+of data beginning at
+.UL ptr
+from file
+.UL ioptr .
+No advance notification
+that binary I/O is being done is required;
+when, for portability reasons,
+it becomes required, it will be done
+by adding an additional character to the mode-string on the
+.UL fopen
+call.
+.nr PD .4v
+.LP
+.UL fwrite(ptr,\ sizeof(*ptr),\ nitems,\ ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+Like
+.UL fread ,
+but in the other direction.
+.nr PD .4v
+.LP
+.UL rewind(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+rewinds the stream
+named by
+.UL ioptr .
+It is not very useful except on input,
+since a rewound output file is still open only for output.
+.nr PD .4v
+.LP
+.UL system(string)\ char\ *string;
+.nr PD 0
+.IP
+.br
+The
+.UL string
+is executed by the shell as if typed at the terminal.
+.nr PD .4v
+.LP
+.UL getw(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+returns the next word from the input stream named by
+.UL ioptr .
+.UL EOF
+is returned on end-of-file or error,
+but since this a perfectly good
+integer
+.UL feof
+and
+.UL ferror
+should be used.
+A ``word'' is 16 bits on the
+.UC PDP-11.
+.nr PD .4v
+.LP
+.UL putw(w,\ ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+writes the integer
+.UL w
+on the named output stream.
+.nr PD .4v
+.LP
+.UL setbuf(ioptr,\ buf)\ FILE\ *ioptr;\ char\ *buf;
+.nr PD 0
+.IP
+.br
+.UL setbuf
+may be used after a stream has been opened
+but before I/O has started.
+If
+.UL buf
+is
+.UL NULL ,
+the stream will be unbuffered.
+Otherwise the buffer supplied will be used.
+It must be a character array of sufficient size:
+.P1
+char buf[BUFSIZ];
+.P2
+.nr PD .4v
+.LP
+.UL fileno(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+returns the integer file descriptor associated with the file.
+.nr PD .4v
+.LP
+.UL fseek(ioptr,\ offset,\ ptrname)\ FILE\ *ioptr;\ long\ offset;
+.nr PD 0
+.IP
+.br
+The location of the next byte in the stream
+named by
+.UL ioptr
+is adjusted.
+.UL offset
+is a long integer.
+If
+.UL ptrname
+is 0, the offset is measured from the beginning of the file;
+if
+.UL ptrname
+is 1, the offset is measured from the current read or
+write pointer;
+if
+.UL ptrname
+is 2, the offset is measured from the end of the file.
+The routine accounts properly for any buffering.
+(When this routine is used on
+.UC UNIX \& non-
+systems,
+the offset must be a value returned from
+.UL ftell
+and the ptrname must be 0).
+.ne 3
+.nr PD .4v
+.LP
+.UL long\ ftell(ioptr)\ FILE\ *ioptr;
+.nr PD 0
+.IP
+.br
+The byte offset, measured from the beginning of the file,
+associated with the named stream is returned.
+Any buffering is properly accounted for.
+(On
+.UC UNIX \& non-
+systems the value of this call is useful only
+for handing to
+.UL fseek ,
+so as to position the file to the same place it was when
+.UL ftell
+was called.)
+.nr PD .4v
+.LP
+.UL getpw(uid,\ buf)\ char\ *buf;
+.nr PD 0
+.IP
+.br
+The password file is searched for the given integer user ID.
+If an appropriate line is found, it is copied into
+the character array
+.UL buf ,
+and 0 is returned.
+If no line is found corresponding to the user ID
+then 1 is returned.
+.nr PD .4v
+.LP
+.UL char\ *malloc(num);
+.nr PD 0
+.IP
+.br
+allocates
+.UL num
+bytes.
+The pointer returned is sufficiently well aligned to be usable for any purpose.
+.UL NULL
+is returned if no space is available.
+.nr PD .4v
+.LP
+.UL char\ *calloc(num,\ size);
+.nr PD 0
+.IP
+.br
+allocates space for
+.UL num
+items each of size
+.UL size .
+The space is guaranteed to be set to 0 and the pointer is
+sufficiently well aligned to be usable for any purpose.
+.UL NULL
+is returned if no space is available .
+.nr PD .4v
+.LP
+.UL cfree(ptr)\ char\ *ptr;
+.nr PD 0
+.IP
+.br
+Space is returned to the pool used by
+.UL calloc .
+Disorder can be expected if the pointer was not obtained
+from
+.UL calloc .
+.nr PD .4v
+.LP
+The following are macros whose definitions may be obtained by including
+.UL <ctype.h> .
+.nr PD .4v
+.LP
+.UL isalpha(c)
+returns non-zero if the argument is alphabetic.
+.nr PD .4v
+.LP
+.UL isupper(c)
+returns non-zero if the argument is upper-case alphabetic.
+.nr PD .4v
+.LP
+.UL islower(c)
+returns non-zero if the argument is lower-case alphabetic.
+.nr PD .4v
+.LP
+.UL isdigit(c)
+returns non-zero if the argument is a digit.
+.nr PD .4v
+.LP
+.UL isspace(c)
+returns non-zero if the argument is a spacing character:
+tab, newline, carriage return, vertical tab,
+form feed, space.
+.nr PD .4v
+.LP
+.UL ispunct(c)
+returns non-zero if the argument is
+any punctuation character, i.e., not a space, letter,
+digit or control character.
+.nr PD .4v
+.LP
+.UL isalnum(c)
+returns non-zero if the argument is a letter or a digit.
+.nr PD .4v
+.LP
+.UL isprint(c)
+returns non-zero if the argument is printable \(em
+a letter, digit, or punctuation character.
+.nr PD .4v
+.LP
+.UL iscntrl(c)
+returns non-zero if the argument is a control character.
+.nr PD .4v
+.LP
+.UL isascii(c)
+returns non-zero if the argument is an ascii character, i.e., less than octal 0200.
+.nr PD .4v
+.LP
+.UL toupper(c)
+returns the upper-case character corresponding to the lower-case
+letter
+.UL c.
+.nr PD .4v
+.LP
+.UL tolower(c)
+returns the lower-case character corresponding to the upper-case
+letter
+.UL c .
OpenPOWER on IntegriCloud