Path: seismo!harvard!husc6!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: strings (2 of 3) Message-ID: <1846@panda.UUCP> Date: 10 May 86 20:58:23 GMT Sender: jpn@panda.UUCP Lines: 1308 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 111 Submitted by: #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # str2int.c # strcat.c # strchr.c # strcmp.c # strcpack.c # strcpbrk.c # strcpy.c # strcspn.c # strctrim.c # strend.c # strfield.c # strfind.c # strings.h # strkey.c # strlen.c # strmov.c # strncat.c # strncmp.c # strncpy.c # strnend.c # strnlen.c # strnmov.c # strnrev.c # strnrpt.c # strntran.c sed 's/^X//' << 'SHAR_EOF' > str2int.c X/* File : str2int.c X Author : Richard A. O'Keefe X Updated: 27 April 1984 X Defines: str2int(), atoi(), atol() X X str2int(src, radix, lower, upper, &val) X converts the string pointed to by src to an integer and stores it in X val. It skips leading spaces and tabs (but not newlines, formfeeds, X backspaces), then it accepts an optional sign and a sequence of digits X in the specified radix. The result should satisfy lower <= *val <= upper. X The result is a pointer to the first character after the number; X trailing spaces will NOT be skipped. X X If an error is detected, the result will be NullS, the value put X in val will be 0, and errno will be set to X EDOM if there are no digits X ERANGE if the result would overflow or otherwise fail to lie X within the specified bounds. X Check that the bounds are right for your machine. X This looks amazingly complicated for what you probably thought was an X easy task. Coping with integer overflow and the asymmetric range of X twos complement machines is anything but easy. X X So that users of atoi and atol can check whether an error occured, X I have taken a wholly unprecedented step: errno is CLEARED if this X call has no problems. X*/ X X#include "strings.h" X#include "ctypes.h" X#include Xextern int errno; X X/* CHECK THESE CONSTANTS FOR YOUR MACHINE!!! */ X X#if pdp11 X# define MaxInt 0x7fffL /* int = 16 bits */ X# define MinInt 0x8000L X# define MaxLong 0x7fffffffL /* long = 32 bits */ X# define MinLong 0x80000000L X#else !pdp11 X# define MaxInt 0x7fffffffL /* int = 32 bits */ X# define MinInt 0x80000000L X# define MaxLong 0x7fffffffL /* long = 32 bits */ X# define MinLong 0x80000000L X#endif pdp11 X X Xchar *str2int(src, radix, lower, upper, val) X register char *src; X register int radix; X long lower, upper, *val; X { X int sign; /* is number negative (+1) or positive (-1) */ X int n; /* number of digits yet to be converted */ X long limit; /* "largest" possible valid input */ X long scale; /* the amount to multiply next digit by */ X long sofar; /* the running value */ X register int d; /* (negative of) next digit */ X char *answer; X X /* Make sure *val is sensible in case of error */ X X *val = 0; X X /* Check that the radix is in the range 2..36 */ X X if (radix < 2 || radix > 36) { X errno = EDOM; X return NullS; X } X X /* The basic problem is: how do we handle the conversion of X a number without resorting to machine-specific code to X check for overflow? Obviously, we have to ensure that X no calculation can overflow. We are guaranteed that the X "lower" and "upper" arguments are valid machine integers. X On sign-and-magnitude, twos-complement, and ones-complement X machines all, if +|n| is representable, so is -|n|, but on X twos complement machines the converse is not true. So the X "maximum" representable number has a negative representative. X Limit is set to min(-|lower|,-|upper|); this is the "largest" X number we are concerned with. */ X X /* Calculate Limit using Scale as a scratch variable */ X X if ((limit = lower) > 0) limit = -limit; X if ((scale = upper) > 0) scale = -scale; X if (scale < limit) limit = scale; X X /* Skip leading spaces and check for a sign. X Note: because on a 2s complement machine MinLong is a valid X integer but |MinLong| is not, we have to keep the current X converted value (and the scale!) as *negative* numbers, X so the sign is the opposite of what you might expect. X Should the test in the loop be isspace(*src)? X */ X while (*src == ' ' || *src == '\t') src++; X sign = -1; X if (*src == '+') src++; else X if (*src == '-') src++, sign = 1; X X /* Check that there is at least one digit */ X X if (_c2type[1+ *src] >= radix) { X errno = EDOM; X return NullS; X } X X /* Skip leading zeros so that we never compute a power of radix X in scale that we won't have a need for. Otherwise sticking X enough 0s in front of a number could cause the multiplication X to overflow when it neededn't. X */ X while (*src == '0') src++; X X /* Move over the remaining digits. We have to convert from left X to left in order to avoid overflow. Answer is after last digit. X */ X for (n = 0; _c2type[1+ *src++] < radix; n++) ; X answer = --src; X X /* The invariant we want to maintain is that src is just X to the right of n digits, we've converted k digits to X sofar, scale = -radix**k, and scale < sofar < 0. Now X if the final number is to be within the original X Limit, we must have (to the left)*scale+sofar >= Limit, X or (to the left)*scale >= Limit-sofar, i.e. the digits X to the left of src must form an integer <= (Limit-sofar)/(scale). X In particular, this is true of the next digit. In our X incremental calculation of Limit, X X IT IS VITAL that (-|N|)/(-|D|) = |N|/|D| X */ X X for (sofar = 0, scale = -1; --n >= 0; ) { X d = _c2type[1+ *--src]; X if (-d < limit) { X errno = ERANGE; X return NullS; X } X limit = (limit+d)/radix, sofar += d*scale; X if (n != 0) scale *= radix; /* watch out for overflow!!! */ X } X /* Now it might still happen that sofar = -32768 or its equivalent, X so we can't just multiply by the sign and check that the result X is in the range lower..upper. All of this caution is a right X pain in the neck. If only there were a standard routine which X says generate thus and such a signal on integer overflow... X But not enough machines can do it *SIGH*. X */ X if (sign < 0 && sofar < -MaxLong /* twos-complement problem */ X || (sofar*=sign) < lower || sofar > upper) { X errno = ERANGE; X return NullS; X } X *val = sofar; X errno = 0; /* indicate that all went well */ X return answer; X } X X Xint atoi(src) X char *src; X { X long val; X str2int(src, 10, MinInt, MaxInt, &val); X return (int)val; X } X X Xlong atol(src) X char *src; X { X long val; X str2int(src, 10, MinLong, MaxLong, &val); X return val; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strcat.c X/* File : strcat.c X Author : Richard A. O'Keefe. X Updated: 10 April 1984 X Defines: strcat() X X strcat(s, t) concatenates t on the end of s. There had better be X enough room in the space s points to; strcat has no way to tell. X Note that strcat has to search for the end of s, so if you are doing X a lot of concatenating it may be better to use strmov, e.g. X strmov(strmov(strmov(strmov(s,a),b),c),d) X rather than X strcat(strcat(strcat(strcpy(s,a),b),c),d). X strcat returns the old value of s. X*/ X X#include "strings.h" X Xchar *strcat(s, t) X register char *s, *t; X { X char *save; X X for (save = s; *s++; ) ; X for (--s; *s++ = *t++; ) ; X return save; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strchr.c X/* File : strchr.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strchr(), index() X X strchr(s, c) returns a pointer to the first place in s where c X occurs, or NullS if c does not occur in s. This function is called X index in V7 and 4.?bsd systems; while not ideal the name is clearer X than strchr, so index remains in strings.h as a macro. NB: strchr X looks for single characters, not for sets or strings. To find the X NUL character which closes s, use strchr(s, '\0') or strend(s). The X parameter 'c' is declared 'int' so it will go in a register; if your X C compiler is happy with register _char_ change it to that. X*/ X X#include "strings.h" X Xchar *strchr(s, c) X register _char_ *s; X register int c; X { X for (;;) { X if (*s == c) return s; X if (!*s++) return NullS; X } X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strcmp.c X/* File : strcmp.c X Author : Richard A. O'Keefe. X Updated: 10 April 1984 X Defines: strcmp() X X strcmp(s, t) returns > 0, = 0, or < 0 when s > t, s = t, or s < t X according to the ordinary lexicographical order. To test for X equality, the macro streql(s,t) is clearer than !strcmp(s,t). Note X that if the string contains characters outside the range 0..127 the X result is machine-dependent; PDP-11s and VAXen use signed bytes, X some other machines use unsigned bytes. X*/ X X#include "strings.h" X Xint strcmp(s, t) X register char *s, *t; X { X while (*s == *t++) if (!*s++) return 0; X return s[0]-t[-1]; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strcpack.c X/* File : strcpack.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strcpack() X X strcpack(dst, src, set, c) X copies characters from src to dst, stopping when it finds a NUL. If X c is NUL, characters not in the set are not copied to dst. If c is X not NUL, sequences of characters not in the set are copied as a X single c. strcpack is to strpack as strcspn is to strspn. If your C X compiler is happy with register _char_, change the declaration of c. X The result is the address of the NUL byte that now terminates "dst". X Note that dst may safely be the same as src. X*/ X X#include "strings.h" X#include "_str2set.h" X Xchar *strcpack(dst, src, set, c) X register _char_ *dst, *src; X char *set; X register int c; X { X register int chr; X X _str2set(set); X while (chr = *src++) { X if (_set_vec[chr] != _set_ctr) { X while ((chr = *src++) && _set_vec[chr] != _set_ctr) ; X if (c) *dst++ = c; /* 1. If you don't want trailing */ X if (!chr) break; /* 2. things turned into "c", swap */ X } /* lines 1 and 2. */ X *dst++ = chr; X } X *dst = 0; X return dst; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strcpbrk.c X/* File : strcpbrk.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strcpbrk() X X strcpbrk(s1, s2) returns a pointer to the first character of s1 which X does not occur in s2. It is to strpbrk as strcspn is to strspn. It X relies on NUL never being in a set. X*/ X X#include "strings.h" X#include "_str2set.h" X Xchar *strcpbrk(str, set) X register _char_ *str; X char *set; X { X _str2set(set); X while (_set_vec[*str++] == _set_ctr); X return *--str ? str : NullS; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strcpy.c X/* File : strcpy.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strcpy() X X strcpy(dst, src) copies all the characters of src (including the X closing NUL) to dst, and returns the old value of dst. Maybe this X is useful for doing i = strlen(strcpy(dst, src)); I've always found X strmov handier. X*/ X X#include "strings.h" X Xchar *strcpy(dst, src) X register char *dst, *src; X { X char *save; X X for (save = dst; *dst++ = *src++; ) ; X return save; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strcspn.c X/* File : strcspn.c X Author : Richard A. O'Keefe. X Updated: 11 April 1984 X Defines: strspn() X X strcspn(s1, s2) returns the length of the longest prefix of s1 X consisting entirely of characters which are NOT in s2 ("c" is X "complement"). NUL is considered to be part of s2. As _str2set X will never include NUL in a set, we have to check for it explicitly. X*/ X X#include "strings.h" X#include "_str2set.h" X Xint strcspn(str, set) X register _char_ *str; X char *set; X { X register int L; X X _str2set(set); X for (L = 0; *str && _set_vec[*str++] != _set_ctr; L++) ; X return L; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strctrim.c X/* File : strctrim.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strctrim() X X strctrim(dst, src, set, ends) X copies src to dst, but will skip leading characters not in set if X ends <= 0 and will skip trailing characters not in set if ends >= 0. X Thus there are three cases: X ends < 0 : trim a prefix X ends = 0 : trim a prefix and a suffix both X ends > 0 : trim a suffix X This is to strtrim as strcspn is to strspn. X*/ X X#include "strings.h" X#include "_str2set.h" X Xchar *strctrim(dst, src, set, ends) X register char *dst, *src; X char *set; X int ends; X { X _str2set(set); X if (ends <= 0) { X register int chr; X while ((chr = *src++) && _set_vec[chr] != _set_ctr) ; X --src; X } X if (ends >= 0) { X register int chr; X register char *save = dst; X while (chr = *src++) { X *dst++ = chr; X if (_set_vec[chr] == _set_ctr) save = dst; X } X dst = save, *dst = NUL; X } else { X while (*dst++ = *src++) ; X --dst; X } X return dst; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strend.c X/* File : strend.c X Author : Richard A. O'Keefe. X Updated: 23 April 1984 X Defines: strend() X X strend(s) returns a character pointer to the NUL which ends s. That X is, strend(s)-s == strlen(s). This is useful for adding things at X the end of strings. It is redundant, because strchr(s,'\0') could X be used instead, but this is clearer and faster. X Beware: the asm version works only if strlen(s) < 65535. X*/ X X#include "strings.h" X X#if VaxAsm X Xchar *strend(s) X char *s; X { X asm("locc $0,$65535,*4(ap)"); X asm("movl r1,r0"); X } X X#else ~VaxAsm X Xchar *strend(s) X register char *s; X { X while (*s++); X return s-1; X } X X#endif VaxAsm X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strfield.c X/* File : strfield.c X Author : Richard A. O'Keefe. X Updated: 21 April 1984 X Defines: strfield() X X strfield(src, fields, chars, blanks, tabch) X is based on the key specifications of the sort(1) command. X X tabch corresponds to 'x' in -t'x'. If it is NUL, a field X is leading layout (spaces, tabs &c) followed by at least X one non-layout character, and is terminated by the next X layout character or NUL. If it is not NUL, a field is X terminated by tabch or NUL. X X fields is the number of fields to skip over. It corresponds X to m in -m.n or +m.n . There must be at least this many X fields, and only the last may be terminated by NUL. X X chars is the number of characters to skip after the fields X have been skipped. At least this many non-NUL characters X must remain after the fields have been skipped. Note that X it is entirely possible for this skip to cross one or more X field boundaries. This corresponds to n in +m.n or -m.n . X X Finally, if blanks is not 0, any layout characters will be X skipped. There need not be any. This corresponds to the X letter b in +2.0b or -0.4b . X X The result is NullS if the source ran out of fields or ran X out of chars. Otherwise it is a pointer to the first X character of src which was not skipped. It is quite possible X for this character to be the terminating NUL. X X Example: X to skip to the user-id field of /etc/passwd: X user_id = strfield(line, 2, 0, 0, ':'); X X to check whether "line" is at least 27 characters long: X if (strfield(line, 0, 27, 0, 0)) then-it-is; X X to select the third blank-delimited field in a line: X head = strfield(line, 2, 0, 1, 0); X tail = strfield(head, 1, 0, 0, 0); X (* the field is the tail-head characters starting at head *) X X It's not a bug, it's a feature: "layout" means any ASCII character X in the range '\1' .. ' ', including '\n', '\f' and so on. X*/ X X#include "strings.h" X Xchar *strfield(src, fields, chars, blanks, tabch) X register char *src; X int fields, chars, blanks, tabch; X { X if (tabch <= 0) { X while (--fields >= 0) { X while (*src <= ' ') if (!*src++) return NullS; X while (*++src > ' ') ; X } X } else X if (fields > 0) { X do if (!*src) return NullS; X while (*src++ != tabch || --fields > 0); X } X while (--chars >= 0) if (!*src++) return NullS; X if (blanks) while (*src && *src++ <= ' ') ; X return src; X } SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strfind.c X/* File : strfind.c X Author : Richard A. O'Keefe. X Updated: 23 April 1984 X Defines: strfind() X X strfind(src, pat) looks for an instance of pat in src. pat is not a X regex(3) pattern, it is a literal string which must be matched exactly. X As a special hack to prevent infinite loops, the empty string will be X found just once, at the far end of src. This is hard to justify. The X result is a pointer to the first character AFTER the located instance, X or NullS if pat does not occur in src. The reason for returning the X place after the instance is so that you can count the number of instances X by writing X _str2pat(ToBeFound); X for (p = src, n = 0; p = strfind(p, NullS); n++) ; X If you want a pointer to the first character of the instance, it is up X to you to subtract strlen(pat). X X If there were a strnfind it wouldn't have to look at all the characters X of src, this version does otherwise it could miss the closing NUL. X*/ X X#include "strings.h" X#include "_str2pat.h" X Xchar *strfind(src, pat) X char *src, *pat; X { X register char *s, *p; X register int c, lastch; X X pat = _str2pat(pat); X if (_pat_lim < 0) { X for (s = src; *s++; ) ; X return s-1; X } X /* The pattern is non-empty */ X for (c = _pat_lim, lastch = pat[c]; ; c = _pat_vec[c]) { X for (s = src; --c >= 0; ) X if (!*s++) return NullS; X c = *s, src = s; X if (c == lastch) { X for (s -= _pat_lim, p = pat; *p; ) X if (*s++ != *p++) goto not_yet; X return s; Xnot_yet:; } X } X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strings.h X/* File : strings.h X Author : Richard A. O'Keefe. X Updated: 1 June 1984 X Purpose: Header file for the "string(3C)" package. X X All the routines in this package are the original work of X R.A.O'Keefe. Any resemblance between them and any routines in X licensed software is due entirely to these routines having been X written using the "man 3 string" UNIX manual page, or in some cases X the "man 1 sort" manual page as a specification. See the READ-ME to X find the conditions under which these routines may be used & copied. X*/ X X#ifndef NullS X#define NullS (char*)0 X#define NUL '\0' X X/* MAKE SURE THE RIGHT VERSION OF THE FOLLOWING MACRO IS INSTALLED! */ X X#if vax | pdp11 | m68000 | perq X#define CharsAreSigned 1 /* default is unsigned */ X#endif vax | pdp11 | m68000 | perq X X#if CharsAreSigned X#define int2char(i) (((i)<<((sizeof (int) -1)*8))>>((sizeof (int) -1)*8)) X#else !CharsAreSigned X#define int2char(i) ((i)&255) X#endif CharsAreSigned X/* If characters are signed, but the above doesn't work, X try ((127-(255&~(i)))^(-128)) X*/ X X#ifndef _AlphabetSize X#define _AlphabetSize 128 X#endif X X#if _AlphabetSize == 128 Xtypedef char _char_; X#endif X#if _AlphabetSize == 256 Xtypedef unsigned char _char_; X#endif X X/* NullS is the "nil" character pointer. NULL would work in most X cases, but in some C compilers pointers and integers may be of X different sizes, so it is handy to have a nil pointer that one can X pass to a function as well as compare pointers against. X X NUL is the ASCII name for the character with code 0. Its use to end X strings is a convention of the C programming language. There are in X fact three different end of string conventions supported by routines X in this package: X str : end at the first NUL character X strn : end at the first NUL character, or when the X extra "len" parameter runs out. X mem,b : length determined solely by "len" parameter. X Unfortunately, the VAX hardware only supports the last convention, a X pity really. Fortran 77 users BEWARE: Fortran 77's convention is an X entirely different one, and there are NO routines in this package as X yet which support it. (But see section 3F of the 4.2 BSD manual.) X X The routines which move characters around don't care whether they X are signed or unsigned. But the routines which compare a character X in a string with an argument, or use a character from a string as an X index into an array, do care. I have assumed that X _AlphabetSize = 128 => only 0..127 appear in strings X _AlphabetSize = 256 => only 0..255 appear in strings X The files _str2set.c and _str2map.c declare character vectors using X this size. If you don't have unsigned char, your machine may treat X char as unsigned anyway. X X Some string operations (*cmp, *chr) are explicitly defined in various X UNIX manuals to use "native" comparison, so I have not used _char_ in X them. This package is meant to be compatible, not rational! X*/ X Xextern char *strcat(/*char^,char^*/); Xextern char *strncat(/*char^,char^,int*/); X Xextern int strcmp(/*char^,char^*/); Xextern int strncmp(/*char^,char^,int*/); X X#define streql !strcmp X#define strneql !strncmp /* (str-N)-eql not str-(neq-l)! */ X Xextern char *strcpy(/*char^,char^*/); Xextern char *strncpy(/*char^,char^,int*/); X Xextern int strlen(/*char^*/); Xextern int strnlen(/*char^,int*/); X Xextern char *strchr(/*char^,_char_*/); Xextern char *strrchr(/*char^,_char_*/); X#define index strchr X#define rindex strrchr X Xextern char *strmov(/*char^,char^*/); Xextern char *strnmov(/*char^,char^,int*/); X Xextern void strrev(/*char^,char^*/); Xextern void strnrev(/*char^,char^,int*/); X Xextern char *strend(/*char^*/); Xextern char *strnend(/*char^*/); X Xextern char *strpbrk(/*char^,char^*/); Xextern char *strcpbrk(/*char^,char^*/); X Xextern int strspn(/*char^,char^*/); Xextern int strcspn(/*char^,char^*/); X Xextern char *strtok(/*char^,char^*/); Xextern void istrtok(/*char^,char^*/); X Xextern char *strpack(/*_char_^,_char_^,char^,int*/); Xextern char *strcpack(/*_char_^,_char_^,char^,int*/); X Xextern int strrpt(/*char^,char^,int*/); Xextern int strnrpt(/*char^,int,char^,int*/); X Xextern void strtrans(/*_char_^,_char_^,_char_^,_char_^*/); Xextern void strntrans(/*_char_^,_char_^,int,_char_^,_char_^*/); X Xextern char *strtrim(/*char^,char^,char^,int*/); Xextern char *strctrim(/*char^,char^,char^,int*/); X Xextern char *strfield(/*char^,int,int,int,int*/); Xextern char *strkey(/*char^,char^,char^,char^*/); X Xextern char *strfind(/*char^,char^*/); Xextern char *strrepl(/*char^,char^,char^,char^*/); X Xextern void bcopy(/*char^,char^,int*/); Xextern void bmove(/*char^,char^,int*/); X Xextern void bfill(/*char^,int,char*/); Xextern void bzero(/*char^,int*/); X Xextern int bcmp(/*char^,char^,int*/); X#define beql !bcmp X Xextern int ffs(/*int*/); Xextern int ffc(/*int*/); X Xextern char *substr(/*char^,char^,int,int*/); X Xextern char *strxcat(/*VARARGS*/); Xextern char *strxcpy(/*VARARGS*/); Xextern char *strxmov(/*VARARGS*/); X Xextern char *strxncat(/*VARARGS*/); Xextern char *strxncpy(/*VARARGS*/); Xextern char *strxnmov(/*VARARGS*/); X X#endif NullS X X#ifndef memeql X#include "memory.h" X#endif memeql X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strkey.c X/* File : strkey.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strkey() X X strkey(dst, head, tail, options) X copies tail-head characters from head to dst according to the X options. If tail is NullS, it copies up to the terminating X NUL of head. This function is meant for doing comparisons as X by sort(1). The options are thus a string of characters X taken from "bdfin". In case the options came from somewhere X else other letters are ignored. X X -b: leading layout characters are not copied. X X -d: only letters, digits, and blanks are copied. X -i: only graphic characters (32..126) are copied. X -n: a numeric string is copied. X These options are incompatible, and the last is taken. X X -f: upper case letters are copied as lower case. X X The question of what to do with a numeric string is an interesting X one, and I don't claim that this is a brilliant answer. However, X the solution used here does mean that the caller can compare two X strings as strings without needing to know that they are numeric. A X number is copied as <9 digits>., where X is '-' for a negative number and '0' for a positive number. X The magic number 9 is defined to be DigitMagic. X X The idea is that to compare two lines using the keys X -tx +m1.n1 -m2.n2 X you do X h1 = strfield(line1, m1, n1, 0, 'x'); X t1 = strfield(h1, 1, 0, 0, 'x'); X strkey(buff1, h1, t1, "flags"); X h2 = strfield(line2, m2, n2, 0, 'x'); X t2 = strfield(h2, 1, 0, 0, 'x'); X strkey(buff2, h2, t2, "flags"); X ... strcmp(buff1, buff2) ... X X The point of all this, of course, is to make it easier to write new X utilities which are compatible with sort(1) than ones which are not. X*/ X X#include "strings.h" X X#define DigitMagic 9 X Xchar *strkey(dst, head, tail, flags) X register char *dst, *head, *tail; X char *flags; X { X register int c; X int b = 0; /* b option? */ X int f = 0; /* f option? */ X int k = 0; /* 3->n, 2->d, 1->i, 0->none of them */ X X while (*flags) switch (*flags++|32) { X case 'b': b++; break; X case 'f': f++; break; X case 'i': k = 1; break; X case 'd': k = 2; break; X case 'n': k = 3; break; X default : /*ignore*/break; X } X flags = dst; /* save return value */ X X if (tail == NullS) for (tail = head; *tail; tail++) ; X X if (b) while (head != tail && *head <= ' ') head++; X X switch (k) { X case 0: X if (f) { X while (head != tail) { X c = *head++; X if (c >= 'A' && c <= 'Z') c |= 32; X *dst++ = c; X } X } else { X while (head != tail) *dst++ = *head++; X } X break; X case 1: X if (f) { X while (head != tail) { X c = *head++; X if (c >= 32 && c <= 126) { X if (c >= 'A' && c <= 'Z') c |= 32; X *dst++ = c; X } X } X } else { X while (head != tail) { X c = *head++; X if (c >= 32 && c <= 126) *dst++ = c; X } X } X break; X case 2: X if (f) f = 32; X while (head != tail) { X c = *head++; X if (c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c == ' ') { X *dst++ = c; X } else X if (c >= 'A' && c <= 'Z') { X *dst++ = c|f; X } X } X break; X case 3: X if (*head == '-' && head != tail) { X *dst++ = *head++; X head++; X } else { X *dst++ = '0'; X } X b = 0; X while (head != tail) { X c = *head; X if (c < '0' || c > '9') break; X b++, head++; X } X f = DigitMagic-b; X while (--f >= 0) *dst++ = '0'; X head -= b; X while (--b >= 0) *dst++ = *head++; X if (*head == '.' && head != tail) { X *dst++ = *head++; X while (head != tail) { X c = *head++; X if (c < '0' || c > '9') break; X *dst++ = c; X } X /* now remove trailing 0s and possibly the '.' as well */ X while (*--dst == '0') ; X if (*dst != '.') dst++; X } X break; X } X *dst = NUL; X return flags; /* saved initial value of dst */ X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strlen.c X/* File : strlen.c X Author : Richard A. O'Keefe. X Updated: 23 April 1984 X Defines: strlen() X X strlen(s) returns the number of characters in s, that is, the number X of non-NUL characters found before the closing NULEosCh. Note: some X non-standard C compilers for 32-bit machines take int to be 16 bits, X either put up with short strings or change int to long throughout X this package. Better yet, BOYCOTT such shoddy compilers. X Beware: the asm version works only if strlen(s) < 65536. X*/ X X#include "strings.h" X X#if VaxAsm X Xint strlen(s) X char *s; X { X asm("locc $0,$65535,*4(ap)"); X asm("subl3 r0,$65535,r0"); X } X X#else ~VaxAsm X Xint strlen(s) X register char *s; X { X register int L; X X for (L = 0; *s++; L++) ; X return L; X } X X#endif VaxAsm X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strmov.c X/* File : strmov.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strmov() X X strmov(dst, src) moves all the characters of src (including the X closing NUL) to dst, and returns a pointer to the new closing NUL in X dst. The similar UNIX routine strcpy returns the old value of dst, X which I have never found useful. strmov(strmov(dst,a),b) moves a//b X into dst, which seems useful. X*/ X X#include "strings.h" X Xchar *strmov(dst, src) X register char *dst, *src; X { X while (*dst++ = *src++) ; X return dst-1; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strncat.c X/* File : strncat.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strncat() X X strncat(dst, src, n) copies up to n characters of src to the end of X dst. As with strcat, it has to search for the end of dst. Even if X it abandons src early because n runs out it will still close dst X with a NUL. See also strnmov. X*/ X X#include "strings.h" X Xchar *strncat(dst, src, n) X register char *dst, *src; X register int n; X { X char *save; X X for (save = dst; *dst++; ) ; X for (--dst; --n >= 0; ) X if (!(*dst++ = *src++)) return save; X *dst = NUL; X return save; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strncmp.c X/* File : strncmp.c X Author : Richard A. O'Keefe. X Updated: 10 April 1984 X Defines: strncmp() X X strncmp(s, t, n) compares the first n characters of s and t. X If they are the same in the first n characters it returns 0, X otherwise it returns the same value as strcmp(s, t) would. X*/ X X#include "strings.h" X Xint strncmp(s, t, n) X register char *s, *t; X register int n; X { X while (--n >= 0) { X if (*s != *t++) return s[0]-t[-1]; X if (!*s++) return 0; X } X return 0; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strncpy.c X/* File : strncpy.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strncpy() X X strncpy(dst, src, n) copies up to n characters of src to dst. It X will pad dst on the right with NUL or truncate it as necessary to X ensure that n characters exactly are transferred. It returns the X old value of dst as strcpy does. X*/ X X#include "strings.h" X Xchar *strncpy(dst, src, n) X register char *dst, *src; X register int n; X { X char *save; X X for (save = dst; --n >= 0; ) { X if (!(*dst++ = *src++)) { X while (--n >= 0) *dst++ = NUL; X return save; X } X } X return save; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strnend.c X/* File : strnend.c X Author : Richard A. O'Keefe. X Updated: 1 June 1984 X Defines: strnend() X X strnend(src, len) X returns a pointer to just after the end of the string src, which is X terminated by a NUL character, or by exhaustion of the length bound X len. That is, strnend(s,L)-s = strnlen(s,L). s+strnlen(s,L) could X of course be used instead, but this is sometimes clearer. X Beware: the asm version works only if 0 <= len < 65535. X*/ X X#include "strings.h" X X#if VaxAsm X Xchar *strnend(src, len) X char *src; X int len; X { X asm("locc $0,8(ap),*4(ap)"); X asm("movl r1,r0"); X } X X#else ~VaxAsm X Xchar *strnend(src, len) X register char *src; X register int len; X { X while (--len >= 0 && *src) src++; X return src; X } X X#endif VaxAsm X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strnlen.c X/* File : strnlen.c X Author : Richard A. O'Keefe. X Updated: 10 April 1984 X Defines: strnlen() X X strnlen(src, len) X returns the number of characters up to the first NUL in src, or len, X whichever is smaller. This is the same as strnend(src,len)-src. X X Beware: the VaxAsm version only works for 0 <= len < 65535. X*/ X X#include "strings.h" X X#if VaxAsm X Xint strnlen(src, len) X char *src; X int len; X { X asm("locc $0,8(ap),*4(ap)"); X asm("subl3 4(ap),r1,r0"); X } X X#else ~VaxAsm X Xint strnlen(s, n) X register char *s; X register int n; X { X register int L; X X for (L = 0; --n >= 0 && *s++; L++) ; X return L; X } X X#endif VaxAsm X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strnmov.c X/* File : strnmov.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strnmov() X X strnmov(dst, src, n) moves up to n characters of src to dst. It X always moves exactly n characters to dst; if src is shorter than n X characters dst will be extended on the right with NULs, while if src X is longer than n characters dst will be a truncated version of src X and will not have a closing NUL. The result is a pointer to the X first NUL in dst, or is dst+n if dst was truncated. X*/ X X#include "strings.h" X Xchar *strnmov(dst, src, n) X register char *dst, *src; X register int n; X { X while (--n >= 0) { X if (!(*dst++ = *src++)) { X src = dst-1; X while (--n >= 0) *dst++ = NUL; X return src; X } X } X return dst; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strnrev.c X/* File : strnrev.c X Author : Richard A. O'Keefe. X Updated: 1 June 1984 X Defines: strnrev() X X strnrev(dst, src, len) X copies all the characters of src to dst, in REVERSE order. If src X was terminated by a NUL character, so will dst be, otherwise dst & X src are both exactly len non-NUL characters long. This returns no X result. It is to strrev as strncpy is to strcpy. X X Note: this function is perfectly happy to reverse a string into the X same place, strnrev(x, x, L) will work. X It will not work for partially overlapping source and destination. X*/ X X#include "strings.h" X Xvoid strnrev(dsta, srca, len) X register char *dsta, *srca; X register int len; X { X register char *dstz, *srcz; X register int t; X /* On a machine which doesn't supply 6 register variables, X you could #define t len, as the two variables don't overlap. X */ X X for (srcz = srca; --len >= 0 && *srcz; srcz++) ; X dstz = dsta+(srcz-srca); X /* If srcz was stopped by len running out, it points just after X the last character of the source string, and it and dstz are X just right. Otherwise, it was stopped by hitting NUL, and is X in the right place, but dstz should get a NUL as well. X */ X if (len >= 0) *dstz = NUL; X /* That was the very last use of len */ X while (srcz > srca) { X t = *--srcz; X *--dstz = *srca++; X *dsta++ = t; X } X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strnrpt.c X/* File : strnrpt.c X Author : Richard A. O'Keefe. X Updated: 20 April 1984 X Defines: strnrpt() X X strnrpt(dst, n, src, k) "RePeaTs" the string src into dst k times, X but will truncate the result at n characters if necessary. E.g. X strnrpt(dst, 7, "hack ", 2) will move "hack ha" to dst WITHOUT the X closing NUL. The result is the number of characters moved, not X counting the closing NUL. Equivalent to strrpt-ing into an infinite X buffer and then strnmov-ing the result. X*/ X X#include "strings.h" X Xint strnrpt(dst, n, src, k) X register char *dst; X register int n; X char *src; X int k; X { X char *save; X X for (save = dst; --k >= 0; dst--) { X register char *p; X for (p = src; ; ) { X if (--n < 0) return dst-save; X if (!(*dst++ = *p++)) break; X } X } X return dst-save; X } X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > strntran.c X/* File : strntrans.c X Author : Richard A. O'Keefe. X Updated: 2 June 1984 X Defines: strntrans() X X strntrans(dst, src, len, from, to) X Moves characters from src to dst, translating characters in from[] X to the corresponding characters in to[], until either len characters X have been moved or a NUL has been moved. If fewer than len characters X are moved, the remainder of dst will be filled with NULs, much like X strncpy and family. No value is returned. X X Apology: in the previous distribution of this package, strntrans was X defined the way memtrans is now defined. This is more consistent with X the general naming conventions. X*/ X X#include "strings.h" X#include "_str2map.h" X X#if VaxAsm X Xvoid strntrans(dst, src, len, from, to) X _char_ *dst, *src, *from, *to; X int len; X { X _str2map(0, from, to); X asm("movtuc 20(ap),*8(ap),$0,__map_vec,20(ap),*4(ap)"); X /* now pad the destination out with NUL characters */ X asm("movc5 $0,*8(ap),$0,r4,(r5)"); X } X X#else ~VaxAsm X Xvoid strntrans(dst, src, len, from, to) X register _char_ *dst, *src; X register int len; X _char_ *from, *to; X { X _str2map(0, from, to); X while (--len >= 0 && (*dst++ = _map_vec[*src++])) ; X while (--len >= 0) *dst++ = NUL; X } X X#endif VaxAsm X SHAR_EOF exit