Path: utzoo!attcan!utgpu!watmath!uunet!ethos!att!icus!lenny From: lenny@icus.islp.ny.us (Lenny Tropiano) Newsgroups: unix-pc.sources Subject: POSIX/SVID/X3J11 standard routines (libposix.a) (Part 4 of 5) Keywords: POSIX, SVID, X3J11, dirent, News 3.0, good stuff! Message-ID: <939@icus.islp.ny.us> Date: 3 Aug 89 01:53:09 GMT Distribution: unix-pc Organization: ICUS Software Systems, Islip, New York Lines: 903 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh getdents.c <<'END_OF_getdents.c' X/* X getdents -- get directory entries in a file system independent format X (SVR3 system call emulation) X X last edit: 15-Feb-1988 D A Gwyn X X This single source file supports several different methods of X getting directory entries from the operating system. Define X whichever one of the following describes your system: X X UFS original UNIX filesystem (14-character name limit) X BFS 4.2BSD (also 4.3BSD) native filesystem (long names) X NFS getdirentries() system call X X Also define any of the following that are pertinent: X X ATT_SPEC check user buffer address for longword alignment X BSD_SYSV BRL UNIX System V emulation environment on 4.nBSD X UNK have _getdents() system call, but kernel may not X support it X UW_NFS You are running an NFS filesystem with an X underlying 4.2 BSD filesystem. This is true X in particular if you running the NFS port from X the University of Wisconsin. X X If your C library has a getdents() system call interface, but you X can't count on all kernels on which your application binaries may X run to support it, change the system call interface name to X _getdents() and define "UNK" to enable the system-call validity X test in this "wrapper" around _getdents(). X X If your system has a getdents() system call that is guaranteed X to always work, you shouldn't be using this source file at all. X*/ X X#define UFS X#define ATT_SPEC X X#include X#include X#ifdef BSD_SYSV X#include /* BSD flavor, not System V */ X#else X#include X#undef MAXNAMLEN /* avoid conflict with SVR3 */ X /* Good thing we don't need to use the DIRSIZ() macro! */ X#ifdef d_ino /* 4.3BSD/NFS using d_fileno */ X#undef d_ino /* (not absolutely necessary) */ X#else X#define d_fileno d_ino /* (struct direct) member */ X#endif X#endif X#include X#include X#ifdef UNK X#ifndef UFS X#include "***** ERROR ***** UNK applies only to UFS" X/* One could do something similar for getdirentries(), but I didn't bother. */ X#endif X#include X#endif X X#if defined(UFS) + defined(BFS) + defined(NFS) != 1 /* sanity check */ X#include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined" X#endif X X#ifdef BSD_SYSV Xstruct dirent __dirent; /* (just for the DIRENTBASESIZ macro) */ X#endif X X#ifdef UFS X#define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */ X#else /* BFS || NFS */ X#define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */ X#endif X X#ifdef NFS X#ifdef BSD_SYSV X#define getdirentries _getdirentries /* package hides this system call */ X#endif Xextern int getdirentries(); Xstatic long dummy; /* getdirentries() needs basep */ X#define GetBlock( fd, buf, n ) getdirentries( fd, buf, (unsigned)n, &dummy ) X#else /* UFS || BFS */ X#ifdef BSD_SYSV X#define read _read /* avoid emulation overhead */ X#endif Xextern int read(); X#define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n ) X#endif X X#ifdef UNK Xextern int _getdents(); /* actual system call */ X#endif X Xextern char *strncpy(); Xextern int fstat(); Xextern off_t lseek(); X Xextern int errno; X X#ifndef DIRBLKSIZ X#define DIRBLKSIZ 4096 /* directory file read buffer size */ X#endif X X#ifndef NULL X#define NULL 0 X#endif X X#ifndef SEEK_CUR X#define SEEK_CUR 1 X#endif X X#ifndef S_ISDIR /* macro to test for directory file */ X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) X#endif X X#ifdef UFS X X/* X The following routine is necessary to handle DIRSIZ-long entry names. X Thanks to Richard Todd for pointing this out. X*/ X Xstatic int XNameLen( name ) /* return # chars in embedded name */ X char name[]; /* -> name embedded in struct direct */ X { X register char *s; /* -> name[.] */ X register char *stop = &name[DIRSIZ]; /* -> past end of name field */ X X for ( s = &name[1]; /* (empty names are impossible) */ X *s != '\0' /* not NUL terminator */ X && ++s < stop; /* < DIRSIZ characters scanned */ X ) X ; X X return s - name; /* # valid characters in name */ X } X X#else /* BFS || NFS */ X Xextern int strlen(); X X#define NameLen( name ) strlen( name ) /* names are always NUL-terminated */ X X#endif X X#ifdef UNK Xstatic enum { maybe, no, yes } state = maybe; X /* does _getdents() work? */ X X/*ARGSUSED*/ Xstatic void Xsig_catch( sig ) X int sig; /* must be SIGSYS */ X { X state = no; /* attempted _getdents() faulted */ X } X#endif X Xint Xgetdents( fildes, buf, nbyte ) /* returns # bytes read; X 0 on EOF, -1 on error */ X int fildes; /* directory file descriptor */ X char *buf; /* where to put the (struct dirent)s */ X unsigned nbyte; /* size of buf[] */ X { X int serrno; /* entry errno */ X off_t offset; /* initial directory file offset */ X struct stat statb; /* fstat() info */ X union { X char dblk[DIRBLKSIZ X#ifdef UFS X +1 /* for last entry name terminator */ X#endif X ]; X /* directory file block buffer */ X struct direct dummy; /* just for alignment */ X } u; /* (avoids having to malloc()) */ X register struct direct *dp; /* -> u.dblk[.] */ X register struct dirent *bp; /* -> buf[.] */ X X#ifdef UNK X switch ( state ) X { X void (*shdlr)(); /* entry SIGSYS handler */ X register int retval; /* return from _getdents() if any */ X X case yes: /* _getdents() is known to work */ X return _getdents( fildes, buf, nbyte ); X X case maybe: /* first time only */ X shdlr = signal( SIGSYS, sig_catch ); X retval = _getdents( fildes, buf, nbyte ); /* try it */ X (void)signal( SIGSYS, shdlr ); X X if ( state == maybe ) /* SIGSYS did not occur */ X { X state = yes; /* so _getdents() must have worked */ X return retval; X } X /* else fall through into emulation */ X X/* case no: /* fall through into emulation */ X } X#endif X X if ( buf == NULL X#ifdef ATT_SPEC X || (unsigned long)buf % sizeof(long) != 0 /* ugh */ X#endif X ) { X errno = EFAULT; /* invalid pointer */ X return -1; X } X X if ( fstat( fildes, &statb ) != 0 ) X return -1; /* errno set by fstat() */ X X if ( !S_ISDIR( statb.st_mode ) ) X { X errno = ENOTDIR; /* not a directory */ X return -1; X } X X if ( (offset = lseek( fildes, (off_t)0, SEEK_CUR )) < 0 ) X return -1; /* errno set by lseek() */ X X#ifdef BFS /* no telling what remote hosts do */ X if ( (unsigned long)offset % DIRBLKSIZ != 0 ) X { X errno = ENOENT; /* file pointer probably misaligned */ X return -1; X } X#endif X X serrno = errno; /* save entry errno */ X X for ( bp = (struct dirent *)buf; bp == (struct dirent *)buf; ) X { /* convert next directory block */ X int size; X X do size = GetBlock( fildes, u.dblk, DIRBLKSIZ ); X while ( size == -1 && errno == EINTR ); X X if ( size <= 0 ) X return size; /* EOF or error (EBADF) */ X X for ( dp = (struct direct *)u.dblk; X (char *)dp < &u.dblk[size]; X dp = (struct direct *)((char *)dp + RecLen( dp )) X ) { X#ifndef UFS X if ( dp->d_reclen <= 0 ) X { X errno = EIO; /* corrupted directory */ X return -1; X } X#endif X X if ( dp->d_fileno != 0 ) X { /* non-empty; copy to user buffer */ X register int reclen = X DIRENTSIZ( NameLen( dp->d_name ) ); X X if ( (char *)bp + reclen > &buf[nbyte] ) X { X errno = EINVAL; X return -1; /* buf too small */ X } X X bp->d_ino = dp->d_fileno; X bp->d_off = offset + ((char *)dp - u.dblk); X bp->d_reclen = reclen; X X { X#ifdef UFS X /* Is the following kludge ugly? You bet. */ X X register char save = dp->d_name[DIRSIZ]; X /* save original data */ X X dp->d_name[DIRSIZ] = '\0'; X /* ensure NUL termination */ X#endif X (void)strncpy( bp->d_name, dp->d_name, X reclen - DIRENTBASESIZ X ); /* adds NUL padding */ X#ifdef UFS X dp->d_name[DIRSIZ] = save; X /* restore original data */ X#endif X } X X bp = (struct dirent *)((char *)bp + reclen); X } X } X X#ifndef UW_NFS X#if !(defined(BFS) || defined(sun)) /* 4.2BSD screwed up; fixed in 4.3BSD */ X if ( (char *)dp > &u.dblk[size] ) X { X errno = EIO; /* corrupted directory */ X return -1; X } X#endif X#endif X } X X errno = serrno; /* restore entry errno */ X return (char *)bp - buf; /* return # bytes read */ X } END_OF_getdents.c if test 8062 -ne `wc -c string.3 <<'END_OF_string.3' X.TH STRING 3 "ANSI/POSIX Standard" X.SH NAME Xstrcat, strdup, strncat, strcmp, strncmp, strcpy, Xstrncpy, strlen, strchr, strrchr, strpbrk, strspn, strcspn, Xstrtok \- string operations X.SH SYNOPSIS X.B #include X.br X.B #include X.P X.B "char \(**strcat(s1, s2)" X.br X.B "char \(**s1, \(**s2;" X.P X.B "char \(**strdup(s1)" X.br X.B "char \(**s1;" X.P X.B "char \(**strncat(s1, s2, n)" X.br X.B "char \(**s1, \(**s2;" X.br X.B "size_t n;" X.P X.B "int strcmp(s1, s2)" X.br X.B "char \(**s1, \(**s2;" X.P X.B "strncmp(s1, s2, n)" X.br X.B "char \(**s1, \(**s2;" X.br X.B "size_t n;" X.P X.B "char \(**strcpy(s1, s2)" X.br X.B "char \(**s1, \(**s2;" X.P X.B "char \(**strncpy(s1, s2, n)" X.br X.B "char \(**s1, \(**s2;" X.br X.B "size_t n;" X.P X.B "int strlen(s)" X.br X.B "char \(**s;" X.P X.B "char \(**strchr(s, c)" X.br X.B "char \(**s;" X.br X.B "int c;" X.P X.B "char \(**strrchr(s, c)" X.br X.B "char \(**s;" X.br X.B "int c;" X.P X.B "char \(**strpbrk(s1, s2)" X.br X.B "char \(**s1, s2;" X.P X.B "int strspn(s1, s2)" X.br X.B "char \(**s1, \(**s2;" X.P X.B "int strcspn(s1, s2)" X.br X.B "char \(**s1, \(**s2;" X.P X.B "char \(**strtok(s1, s2)" X.br X.B "char \(**s1, s2;" X.br X.SH DESCRIPTION XThe arguments \fBs1\fR, \fBs2\fR, and s point to strings (arrays of Xcharacters terminated by a null character). The functions Xstrcat, strncat, strcpy, and strncpy all alter \fBs1\fR. These Xfunctions do not check for overflow of the array pointed to Xby \fBs1\fR. X.P X\fBStrcat\fR appends a copy of string \fBs2\fR to the end of string \fBs1\fR. X.P X\fBStrdup\fR returns a pointer to a new string that is a duplicate Xof the string pointed to by \fBs1\fR. The space for the new Xstring is obtained using malloc(3C). If the new string Xcannot be created, a null pointer is returned. X.P X\fBStrncat\fR appends at most n characters. Each returns a Xpointer to the null-terminated result. X.P X\fBStrcmp\fR compares its arguments and returns an integer less Xthan, equal to, or greater than 0, according as \fBs1\fR is Xlexicographically less than, equal to, or greater than \fBs2\fR. X\fBStrncmp\fR makes the same comparison but looks at, at most, n Xcharacters. X.P X\fBStrcpy\fR copies string \fBs2\fR to \fBs1\fR, stopping after the null Xcharacter has been copied. \fBStrncpy\fR copies exactly n Xcharacters, truncating \fBs2\fR or adding null characters to \fBs1\fR if Xnecessary. The result will not be null-terminated if the Xlength of \fBs2\fR is n or more. Each function returns \fBs1\fR. X.P X\fBStrlen\fR returns the number of characters in s, not including Xthe terminating null character. X.P X\fBStrchr\fR (\fBstrrchr\fR) returns a pointer to the first (last) Xoccurrence of character c in string s, or a NULL pointer if Xc does not occur in the string. The null character Xterminating a string is considered to be part of the string. X.P X\fBStrpbrk\fR returns a pointer to the first occurrence in string X\fBS1\fR of any character from string \fBs2\fR, or a NULL pointer if no Xcharacter from \fBs2\fR exists in \fBs1\fR. X.P X\fBStrspn\fR (\fBstrcspn\fR) returns the length of the initial segment Xof string \fBs1\fR, which consists entirely of characters from X(not from) string \fBs2\fR. X.P X\fBStrtok\fR considers the string \fBs1\fR to consist of a sequence of Xzero or more text tokens separated by spans of one or more Xcharacters from the separator string \fBs2\fR. The first call X(with pointer \fBs1\fR specified) returns a pointer to the first Xcharacter of the first token, and will have written a null Xcharacter into \fBs1\fR immediately following the returned token. XThe function keeps track of its position in the string Xbetween separate calls, so that subsequent calls (which must Xbe made with the first argument a NULL pointer) will work Xthrough the string \fBs1\fR immediately following that token. In Xthis way, subsequent calls will work through the string \fBs1\fR Xuntil no tokens remain. The separator string \fBs2\fR may be Xdifferent from call to call. When no token remains in \fBs1\fR, a XNULL pointer is returned. X.P XFor user convenience, all these functions are declared in Xthe optional header file. X.SH SEE ALSO Xmalloc(3C), malloc(3X). X.SH CAVEATS X\fBStrcmp\fR and \fBstrncmp\fR are implemented by using the most natural Xcharacter comparison on the machine. Thus, the sign of the Xvalue returned when one of the characters has its high-order Xbit set is not the same in all implementations and should Xnot be relied upon. X.P XCharacter movement is performed differently in different Ximplementations. Thus, overlapping moves may yield Xsurprises.!STUFFY!FUNK! Xchmod 644 src/D.posix/string.3 Xecho Extracting src/D.posix/getopt.3c Xsed >src/D.posix/getopt.3c <<'!STUFFY!FUNK!' -e 's///' X.TH GETOPT 3C "Standard Extensions" X.SH NAME Xgetopt \- parse arguments from an argument token vector X.SH SYNOPSIS X.B int getopt (argc, argv, optstring) X.br X.B int argc; X.br X.B char \(**\(**argv, \(**opstring; X.PP X.B extern char \(**optarg; X.br X.B extern int optind, opterr; X.SH DESCRIPTION X.I Getopt Xreturns the next option letter in X.I argv Xthat matches Xa letter in X.IR optstring . X.I Optstring Xis a string of recognized option letters. If a letter is followed by a colon, Xthe option is expected to have an argument that may or may not be separated Xfrom it by white space. X.I Optarg Xis set to point to the start of the option argument on return from X.IR getopt . X.PP X.I Getopt Xplaces in X.I optind Xthe X.I argv Xindex of the next argument to be processed. Because X.I optind Xis external, it is normally initialized to zero automatically before the first Xcall to X.IR getopt . X.PP XWhen all options have been processed (i.e., up to the first non-option Xargument), X.I getopt Xreturns X.SM X.BR EOF . XThe special option X.B \-\- Xmay be used to delimit the end of the options; X.SM X.B EOF Xwill be returned, and X.B \-\- Xwill be skipped. X.SH DIAGNOSTICS X.I Getopt Xprints an error message on X.I stderr Xand returns a Xquestion mark X.RB ( ? ) Xwhen it encounters an option letter not included in X.IR optstring . XThis error message may be disabled by setting X.I opterr Xto a non-zero value. X.SH EXAMPLE XThe following code fragment shows how one might process the arguments for a Xcommand that can take the mutually exclusive options X.B a Xand X.BR b , Xand the options X.B f Xand X.BR o , Xboth of which require arguments: X.PP X.RS X.nf X.ss 18 Xmain (argc, argv) Xint argc; Xchar \(**\(**argv; X{ X int c; X extern char \(**optarg; X extern int optind; X \&\f3.\fP X \&\f3.\fP X \&\f3.\fP X while ((c = getopt(argc, argv, "abf:o:")) != \s-1EOF\s+1) X switch (c) { X case \(fma\(fm: X if (bflg) X errflg++; X else X aflg++; X break; X case \(fmb\(fm: X if (aflg) X errflg++; X else X bproc( ); X break; X case \(fmf\(fm: X ifile = optarg; X break; X case \(fmo\(fm: X ofile = optarg; X break; X case \(fm?\(fm: X errflg++; X } X if (errflg) { X fprintf(stderr, "usage: . . . "); X exit (2); X } X for ( ; optind < argc; optind++) { X if (access(argv[optind], 4)) { X \&\f3.\fP X \&\f3.\fP X \&\f3.\fP X} X.ss 12 X.fi END_OF_string.3 if test 6925 -ne `wc -c tsearch.3c <<'END_OF_tsearch.3c' X.TH TSEARCH 3C "Standard Extension" X.SH NAME Xtsearch, tfind, tdelete, twalk \- manipulate binary search trees X.SH SYNOPSIS X.B #include X.PP X.B "char \(**tsearch ((char \(**) key, (char \(**\(**) rootp, compar)" X.br X.B int (\(**compar)( ); X.PP X.B "char \(**tfind ((char \(**) key, (char \(**\(**) rootp, compar)" X.br X.B int (\(**compar)( ); X.PP X.B "char \(**tdelete ((char \(**) key, (char \(**\(**) rootp, compar)" X.br X.B int (\(**compar)( ); X.PP X.B "void twalk ((char \(**) root, action)" X.br X.B void (\(**action)( ); X.SH DESCRIPTION X.I Tsearch, X.I tfind, X.I tdelete, Xand X.I twalk Xare routines for manipulating binary search trees. XThey are generalized from Knuth (6.2.2) Algorithms T and D. XAll comparisons are done with a user-supplied hook. XThis routine is called with two arguments, Xthe pointers to the elements being compared. XIt returns an integer less than, equal to, Xor greater than 0, according to whether the first argument Xis to be considered less than, equal to or greater than the Xsecond argument (this is the convention used by X.IR strncmp (3)). XThe comparison function need not compare every byte, Xso arbitrary data may be contained in the elements Xin addition to the key values being compared. X.PP X.I Tsearch Xis used to build and access the tree. X.B Key Xis a pointer to a datum to be accessed or stored. XIf there is a datum in the tree Xequal to \(**key (the value pointed to by key), Xa pointer to this found datum is returned. XOtherwise, \(**key is inserted, and a pointer to it returned. XOnly pointers are copied, so the calling routine must store the data. X.B Rootp Xmust point to a variable that points to the root Xof the tree. XA X.SM NULL Xvalue for the variable pointed to by X.B rootp Xdenotes an empty tree; in this case, Xthe variable will be set to point to the datum Xwhich will be at the root of the new tree. X.PP XLike X.IR tsearch , X.I tfind Xwill search for a datum in the tree, returning a pointer Xto it if found. XHowever, if it is not found, X.I tfind Xwill return a X.SM NULL Xpointer. XThe arguments for X.I tfind Xare the same as for X.IR tsearch . X.PP X.I Tdelete Xdeletes a node from a binary search tree. XThe arguments are the same as for X.IR tsearch . XThe variable pointed to by X.B rootp Xwill be changed if the deleted node was the root of the tree. X.I Tdelete Xreturns a pointer to the parent of the deleted node, Xor a X.SM NULL Xpointer if the node is not found. X.PP X.I Twalk Xtraverses a binary search tree. X.B Root Xis the root of the tree to be traversed. X(Any node in a tree may be used as the root for a walk below that node.) X.I Action Xis the name of a routine Xto be invoked at each node. XThis routine is, in turn, Xcalled with three arguments. XThe first argument is the address of the node being visited. XThe second argument is a value from an enumeration data type X.I "typedef enum { preorder, postorder, endorder, leaf }" X.SM X.I VISIT; X(defined in the X.RI < search.h > Xheader file), Xdepending on whether this is the first, second or third Xtime that the node has been visited X(during a depth-first, left-to-right traversal of the tree), Xor whether the node is a leaf. XThe third argument is the level of the node Xin the tree, with the root being level zero. X.PP XThe pointers to the key and the root of the tree should be Xof type pointer-to-element, Xand cast to type pointer-to-character. XSimilarly, although declared as type pointer-to-character, Xthe value returned should be cast into type pointer-to-element. X.SH EXAMPLE XThe following code reads in strings and Xstores structures containing a pointer to each string Xand a count of its length. XIt then walks the tree, printing out the stored strings Xand their lengths in alphabetical order. X.PP X.RS X.nf X.ss 18 X#include X#include X Xstruct node { /\(** pointers to these are stored in the tree \(**/ X char \(**string; X int length; X}; Xchar string_space[10000]; /\(** space to store strings \(**/ Xstruct node nodes[500]; /\(** nodes to store \(**/ Xstruct node \(**root = \s-1NULL\s+1; /\(** this points to the root \(**/ X Xmain( ) X{ X char \(**strptr = string_space; X struct node \(**nodeptr = nodes; X void print_node( ), twalk( ); X int i = 0, node_compare( ); X X while (gets(strptr) != \s-1NULL\s+1 && i++ < 500) { X /\(** set node \(**/ X nodeptr\(mi>string = strptr; X nodeptr\(mi>length = strlen(strptr); X /\(** put node into the tree \(**/ X (void) tsearch((char \(**)nodeptr, &root, X node_compare); X /\(** adjust pointers, so we don't overwrite tree \(**/ X strptr += nodeptr\(mi>length + 1; X nodeptr++; X } X twalk(root, print_node); X} X/\(** X This routine compares two nodes, based on an X alphabetical ordering of the string field. X\(**/ Xint Xnode_compare(node1, node2) Xstruct node \(**node1, \(**node2; X{ X return strcmp(node1\(mi>string, node2\(mi>string); X} X/\(** X This routine prints out a node, the first time X twalk encounters it. X\(**/ X.bp Xvoid Xprint_node(node, order, level) Xstruct node \(**\(**node; X\s-1VISIT\s+1 order; Xint level; X{ X if (order == preorder \(or\(or order == leaf) { X (void)printf("string = %20s, length = %d\en", X (\(**node)\(mi>string, (\(**node)\(mi>length); X } X} X.fi X.RE X.SH SEE ALSO Xbsearch(3C), hsearch(3C), lsearch(3C). X.SH DIAGNOSTICS XA X.SM NULL Xpointer is returned by X.I tsearch Xif there is not enough space available to create a new node. X.br XA X.SM NULL Xpointer is returned by X.I tsearch, X.I tfind Xand X.I tdelete Xif X.B rootp Xis X.SM NULL Xon entry. X.br XIf the datum is found, both X.I tsearch Xand X.I tfind Xreturn a pointer to it. XIf not, X.I tfind Xreturns \s-1NULL\s+1, and X.I tsearch Xreturns a pointer to the inserted Xitem. X.SH WARNINGS XThe X.B root Xargument to X.I twalk Xis one level of indirection less than the X.B rootp Xarguments to X.I tsearch Xand X.IR tdelete . X.br XThere are two nomenclatures used to refer to the order in which Xtree nodes are visited. X.I Tsearch Xuses preorder, postorder and endorder to respectively refer to Xvisting a node before any of its children, after its left child Xand before its right, and after both its children. XThe alternate nomenclature uses preorder, inorder and postorder to Xrefer to the same visits, which could result in some confusion over Xthe meaning of postorder. X.SH BUGS XIf the calling function alters the pointer to the Xroot, results are unpredictable. END_OF_tsearch.3c if test 6251 -ne `wc -c