home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / stringlib < prev    next >
Text File  |  1986-11-30  |  41KB  |  1,521 lines

  1. Subject: v06i043:  X3J11/SVID/4BSD/etc string library (stringlib)
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: ihnp4!utzoo!henry (Henry Spencer)
  6. Mod.sources: Volume 6, Issue 43
  7. Archive-name: stringlib
  8.  
  9. [  This is an update of the string library Henry posted to net.sources
  10.    some time ago.  It is different from a recent library published in
  11.    volume 4 in these two respects:
  12.     1. It comes with a fairly exhaustive test program, which it passes.
  13.     2. It does not invent new functions; it implements the union of those
  14.        described in X3J11, the SVID, etc., and nothing else.
  15.    It would be nice if everyone -- vendors, users -- put the "missing"
  16.    functions into their C library, and we could all live in harmony,
  17.    but I suspect that's wishful thinking.  (Yeah, yeah:  efficiency, too.)
  18.    This is also excempted from my mandatory manpage requirement, for
  19.    reasons mentioned and alluded to in the second paragraph of the README
  20.    file.  --r$ ]
  21.  
  22. ------------------
  23. echo README:
  24. sed 's/^X//' >README <<'!'
  25. XThis is a public-domain reimplementation of string(3) and friends, notably
  26. Xmemory(3) and bstring(3) (except ffs).  Not derived from licensed software.
  27. XThis code may be used on any computer system for any purpose by anyone.
  28. X
  29. XRelative to my old net.sources posting, this one adds some functions and
  30. Xfixes one or two obscure bugs.  There has been another string library
  31. Xposted in recent times, with many more functions; I haven't inspected it
  32. Xand can't comment on its relationship to mine.  Alas, the manual pages
  33. Xfor this stuff are copyright by various people other than me, so I can't
  34. Xinclude them.  See your local Unix manuals.
  35. X
  36. XThis distribution implements precisely the union of the string functions
  37. Xof the SVID, 4BSD, X3J11, and V7.  Included is a large test program that
  38. Xexercises everything quite thoroughly.  (Note that some existing libraries,
  39. Xincluding e.g. V7, flunk one or more of these tests.)
  40. X
  41. XIn the event of conflict between the definitions from various places, the
  42. Xnewer or more portable one is chosen.  That is, X3J11 overrules the SVID,
  43. Xwhich in turn overrules older Unixes.
  44. X
  45. XThe code is written for maximal portability.  Some efficiency has been
  46. Xsacrificed in the cause of meticulously avoiding possible portability
  47. Xproblems.  For example, this code never assumes that a pointer can be
  48. Xmoved past the end of an array and then backed up.  Many of these functions
  49. Xcan be implemented more efficiently if machine-dependent assumptions are
  50. Xmade; memcpy is a particular glaring case.
  51. X
  52. XSimplistically:  put this stuff into a source directory, inspect Makefile
  53. Xfor compilation options that need changing to suit your local environment,
  54. Xand then do "make r".  This compiles the functions and the test program and
  55. Xruns the tests.  If there are no complaints, put string.h in /usr/include
  56. X(you may also want to "make memory.h" and put it in /usr/include) and add
  57. Xthe functions (*.o except for tester.o) to your C library.  The internal
  58. Xinterdependencies are:
  59. X
  60. X    index    needs    strchr
  61. X    rindex    needs    strrchr
  62. X    bcopy    needs    memcpy
  63. X    bcmp    needs    memcmp
  64. X    bzero    needs    memset
  65. X
  66. XI haven't included an implementation of Berkeley's ffs function partly
  67. Xbecause it's not trivial to do in a portable way, and partly because I
  68. Xdon't really see it as a string function.
  69. X
  70. XA weakness in the tester program is that it uses quite short strings for
  71. Xeverything, and pays no real attention to alignment issues.  Optimized
  72. Ximplementations of things like memcpy would need a more elaborate set of
  73. Xtest cases to put them through their full paces.
  74. X
  75. X                Henry Spencer @ U of Toronto Zoology
  76. X                {allegra,ihnp4,decvax,pyramid}!utzoo!henry
  77. X                Wed Jun 25 19:21:34 EDT 1986
  78. !
  79. echo Makefile:
  80. sed 's/^X//' >Makefile <<'!'
  81. X# String library.
  82. X
  83. X# Configuration settings:  how should "size_t", "void *", "const" be written?
  84. X# "size_t" is what's needed to hold the result of sizeof; beware of problems
  85. X# with compatibility here, because X3J11 uses this for e.g. the third
  86. X# argument of strncpy() as well.  You may need to make it "int" even if
  87. X# this is a lie.  "void *" is the generic pointer type, "char *" in most
  88. X# existing implementations.  "const" is the keyword marking read-only
  89. X# variables and parameters, unimplemented in most existing implementations.
  90. X# These things need to be defined this way because they must be fitted into
  91. X# both the .h files and the .c files; see the make instructions for string.h
  92. X# farther down.
  93. XSIZET = int
  94. XVOIDSTAR = char *
  95. XLVOIDSTAR = char*    # Lint shell file has problems with * alone.  Barf.
  96. XCONST = 
  97. X
  98. XCONF = -DSIZET=$(SIZET) -DVOIDSTAR='$(VOIDSTAR)' -DCONST='$(CONST)'
  99. XLCONF = -DSIZET=$(SIZET) -DVOIDSTAR='$(LVOIDSTAR)' -DCONST='$(CONST)'
  100. X
  101. X# Things you might want to put in CFLAGS or LINTFLAGS.
  102. X# -DCHARBITS=0377        Required if compiler lacks "unsigned char".
  103. X# -Dvoid=int            Required if compiler lacks "void".
  104. X# -DUNIXERR            Unix-like errno stuff, can test strerror().
  105. X# -DBERKERR            Like UNIXERR but for Berklix (4BSD).
  106. X# -I.                string.h from here, not /usr/include.
  107. X
  108. XCFLAGS = -O $(CONF) -DUNIXERR -I.
  109. XLINTFLAGS = -hpan $(LCONF) -DUNIXERR -Dvoid=int -DCHARBITS=0377 -I.
  110. XLDFLAGS = -i
  111. X
  112. X# Name lists.
  113. XSTRING = index.o rindex.o strcat.o strchr.o strcmp.o strcpy.o strcspn.o \
  114. X    strlen.o strncat.o strncmp.o strncpy.o strpbrk.o strrchr.o strspn.o \
  115. X    strtok.o strstr.o memcpy.o memccpy.o memcmp.o memchr.o memset.o \
  116. X    bcopy.o bcmp.o bzero.o strerror.o
  117. XCSTRING = index.c rindex.c strcat.c strchr.c strcmp.c strcpy.c strcspn.c \
  118. X    strlen.c strncat.c strncmp.c strncpy.c strpbrk.c strrchr.c strspn.c \
  119. X    strtok.c strstr.c memcpy.c memccpy.c memcmp.c memchr.c memset.c \
  120. X    bcopy.c bcmp.c bzero.c strerror.c
  121. XDTR = README Makefile $(CSTRING) tester.c string.h.proto
  122. X
  123. X# Locations, for installation (somewhat system-dependent).
  124. XDEST=..
  125. X
  126. Xtester.o:    string.h
  127. X
  128. Xmv:    $(STRING)
  129. X    mv $(STRING) $(DEST)
  130. X
  131. Xr:    tester
  132. X    @echo 'No news is good news.  Note: strerror() test is VERY system-dependent.'
  133. X    tester
  134. X
  135. Xtester:    tester.o $(STRING)
  136. X    cc $(LDFLAGS) tester.o $(STRING) -o tester
  137. X
  138. Xstring.h:    string.h.proto
  139. X    sed 's/SIZET/$(SIZET)/g;s/VOIDSTAR /$(VOIDSTAR)/g' string.h.proto >string.h
  140. X
  141. Xmemory.h:    string.h
  142. X    egrep mem string.h >memory.h
  143. X
  144. Xlint:    string.h
  145. X    lint $(LINTFLAGS) tester.c $(CSTRING)
  146. X
  147. Xclean:
  148. X    rm -f tester a.out *.o string.h memory.h dtr
  149. X
  150. Xdtr:    $(DTR)
  151. X    makedtr $(DTR) >dtr
  152. !
  153. echo index.c:
  154. sed 's/^X//' >index.c <<'!'
  155. X/*
  156. X * index - find first occurrence of a character in a string
  157. X */
  158. X
  159. X#define    NULL    0
  160. X
  161. Xchar *                /* found char, or NULL if none */
  162. Xindex(s, charwanted)
  163. XCONST char *s;
  164. Xchar charwanted;
  165. X{
  166. X    extern char *strchr();
  167. X
  168. X    return(strchr(s, charwanted));
  169. X}
  170. !
  171. echo rindex.c:
  172. sed 's/^X//' >rindex.c <<'!'
  173. X/*
  174. X * rindex - find last occurrence of a character in a string
  175. X */
  176. X
  177. X#define    NULL    0
  178. X
  179. Xchar *                /* found char, or NULL if none */
  180. Xrindex(s, charwanted)
  181. XCONST char *s;
  182. Xchar charwanted;
  183. X{
  184. X    extern char *strrchr();
  185. X
  186. X    return(strrchr(s, charwanted));
  187. X}
  188. !
  189. echo strcat.c:
  190. sed 's/^X//' >strcat.c <<'!'
  191. X/*
  192. X * strcat - append string src to dst
  193. X */
  194. Xchar *                /* dst */
  195. Xstrcat(dst, src)
  196. Xchar *dst;
  197. XCONST char *src;
  198. X{
  199. X    register char *dscan;
  200. X    register CONST char *sscan;
  201. X
  202. X    for (dscan = dst; *dscan != '\0'; dscan++)
  203. X        continue;
  204. X    sscan = src;
  205. X    while ((*dscan++ = *sscan++) != '\0')
  206. X        continue;
  207. X    return(dst);
  208. X}
  209. !
  210. echo strchr.c:
  211. sed 's/^X//' >strchr.c <<'!'
  212. X/*
  213. X * strchr - find first occurrence of a character in a string
  214. X */
  215. X
  216. X#define    NULL    0
  217. X
  218. Xchar *                /* found char, or NULL if none */
  219. Xstrchr(s, charwanted)
  220. XCONST char *s;
  221. Xregister char charwanted;
  222. X{
  223. X    register CONST char *scan;
  224. X
  225. X    /*
  226. X     * The odd placement of the two tests is so NUL is findable.
  227. X     */
  228. X    for (scan = s; *scan != charwanted;)    /* ++ moved down for opt. */
  229. X        if (*scan++ == '\0')
  230. X            return(NULL);
  231. X    return(scan);
  232. X}
  233. !
  234. echo strcmp.c:
  235. sed 's/^X//' >strcmp.c <<'!'
  236. X/*
  237. X * strcmp - compare string s1 to s2
  238. X */
  239. X
  240. Xint                /* <0 for <, 0 for ==, >0 for > */
  241. Xstrcmp(s1, s2)
  242. XCONST char *s1;
  243. XCONST char *s2;
  244. X{
  245. X    register CONST char *scan1;
  246. X    register CONST char *scan2;
  247. X
  248. X    scan1 = s1;
  249. X    scan2 = s2;
  250. X    while (*scan1 != '\0' && *scan1 == *scan2) {
  251. X        scan1++;
  252. X        scan2++;
  253. X    }
  254. X
  255. X    /*
  256. X     * The following case analysis is necessary so that characters
  257. X     * which look negative collate low against normal characters but
  258. X     * high against the end-of-string NUL.
  259. X     */
  260. X    if (*scan1 == '\0' && *scan2 == '\0')
  261. X        return(0);
  262. X    else if (*scan1 == '\0')
  263. X        return(-1);
  264. X    else if (*scan2 == '\0')
  265. X        return(1);
  266. X    else
  267. X        return(*scan1 - *scan2);
  268. X}
  269. !
  270. echo strcpy.c:
  271. sed 's/^X//' >strcpy.c <<'!'
  272. X/*
  273. X * strcpy - copy string src to dst
  274. X */
  275. Xchar *                /* dst */
  276. Xstrcpy(dst, src)
  277. Xchar *dst;
  278. XCONST char *src;
  279. X{
  280. X    register char *dscan;
  281. X    register CONST char *sscan;
  282. X
  283. X    dscan = dst;
  284. X    sscan = src;
  285. X    while ((*dscan++ = *sscan++) != '\0')
  286. X        continue;
  287. X    return(dst);
  288. X}
  289. !
  290. echo strcspn.c:
  291. sed 's/^X//' >strcspn.c <<'!'
  292. X/*
  293. X * strcspn - find length of initial segment of s consisting entirely
  294. X * of characters not from reject
  295. X */
  296. X
  297. XSIZET
  298. Xstrcspn(s, reject)
  299. XCONST char *s;
  300. XCONST char *reject;
  301. X{
  302. X    register CONST char *scan;
  303. X    register CONST char *rscan;
  304. X    register SIZET count;
  305. X
  306. X    count = 0;
  307. X    for (scan = s; *scan != '\0'; scan++) {
  308. X        for (rscan = reject; *rscan != '\0';)    /* ++ moved down. */
  309. X            if (*scan == *rscan++)
  310. X                return(count);
  311. X        count++;
  312. X    }
  313. X    return(count);
  314. X}
  315. !
  316. echo strlen.c:
  317. sed 's/^X//' >strlen.c <<'!'
  318. X/*
  319. X * strlen - length of string (not including NUL)
  320. X */
  321. XSIZET
  322. Xstrlen(s)
  323. XCONST char *s;
  324. X{
  325. X    register CONST char *scan;
  326. X    register SIZET count;
  327. X
  328. X    count = 0;
  329. X    scan = s;
  330. X    while (*scan++ != '\0')
  331. X        count++;
  332. X    return(count);
  333. X}
  334. !
  335. echo strncat.c:
  336. sed 's/^X//' >strncat.c <<'!'
  337. X/*
  338. X * strncat - append at most n characters of string src to dst
  339. X */
  340. Xchar *                /* dst */
  341. Xstrncat(dst, src, n)
  342. Xchar *dst;
  343. XCONST char *src;
  344. XSIZET n;
  345. X{
  346. X    register char *dscan;
  347. X    register CONST char *sscan;
  348. X    register SIZET count;
  349. X
  350. X    for (dscan = dst; *dscan != '\0'; dscan++)
  351. X        continue;
  352. X    sscan = src;
  353. X    count = n;
  354. X    while (*sscan != '\0' && --count >= 0)
  355. X        *dscan++ = *sscan++;
  356. X    *dscan++ = '\0';
  357. X    return(dst);
  358. X}
  359. !
  360. echo strncmp.c:
  361. sed 's/^X//' >strncmp.c <<'!'
  362. X/*
  363. X * strncmp - compare at most n characters of string s1 to s2
  364. X */
  365. X
  366. Xint                /* <0 for <, 0 for ==, >0 for > */
  367. Xstrncmp(s1, s2, n)
  368. XCONST char *s1;
  369. XCONST char *s2;
  370. XSIZET n;
  371. X{
  372. X    register CONST char *scan1;
  373. X    register CONST char *scan2;
  374. X    register SIZET count;
  375. X
  376. X    scan1 = s1;
  377. X    scan2 = s2;
  378. X    count = n;
  379. X    while (--count >= 0 && *scan1 != '\0' && *scan1 == *scan2) {
  380. X        scan1++;
  381. X        scan2++;
  382. X    }
  383. X    if (count < 0)
  384. X        return(0);
  385. X
  386. X    /*
  387. X     * The following case analysis is necessary so that characters
  388. X     * which look negative collate low against normal characters but
  389. X     * high against the end-of-string NUL.
  390. X     */
  391. X    if (*scan1 == '\0' && *scan2 == '\0')
  392. X        return(0);
  393. X    else if (*scan1 == '\0')
  394. X        return(-1);
  395. X    else if (*scan2 == '\0')
  396. X        return(1);
  397. X    else
  398. X        return(*scan1 - *scan2);
  399. X}
  400. !
  401. echo strncpy.c:
  402. sed 's/^X//' >strncpy.c <<'!'
  403. X/*
  404. X * strncpy - copy at most n characters of string src to dst
  405. X */
  406. Xchar *                /* dst */
  407. Xstrncpy(dst, src, n)
  408. Xchar *dst;
  409. XCONST char *src;
  410. XSIZET n;
  411. X{
  412. X    register char *dscan;
  413. X    register CONST char *sscan;
  414. X    register SIZET count;
  415. X
  416. X    dscan = dst;
  417. X    sscan = src;
  418. X    count = n;
  419. X    while (--count >= 0 && (*dscan++ = *sscan++) != '\0')
  420. X        continue;
  421. X    while (--count >= 0)
  422. X        *dscan++ = '\0';
  423. X    return(dst);
  424. X}
  425. !
  426. echo strpbrk.c:
  427. sed 's/^X//' >strpbrk.c <<'!'
  428. X/*
  429. X * strpbrk - find first occurrence of any char from breakat in s
  430. X */
  431. X
  432. X#define    NULL    0
  433. X
  434. Xchar *                /* found char, or NULL if none */
  435. Xstrpbrk(s, breakat)
  436. XCONST char *s;
  437. XCONST char *breakat;
  438. X{
  439. X    register CONST char *sscan;
  440. X    register CONST char *bscan;
  441. X
  442. X    for (sscan = s; *sscan != '\0'; sscan++) {
  443. X        for (bscan = breakat; *bscan != '\0';)    /* ++ moved down. */
  444. X            if (*sscan == *bscan++)
  445. X                return(sscan);
  446. X    }
  447. X    return(NULL);
  448. X}
  449. !
  450. echo strrchr.c:
  451. sed 's/^X//' >strrchr.c <<'!'
  452. X/*
  453. X * strrchr - find last occurrence of a character in a string
  454. X */
  455. X
  456. X#define    NULL    0
  457. X
  458. Xchar *                /* found char, or NULL if none */
  459. Xstrrchr(s, charwanted)
  460. XCONST char *s;
  461. Xregister char charwanted;
  462. X{
  463. X    register CONST char *scan;
  464. X    register CONST char *place;
  465. X
  466. X    place = NULL;
  467. X    for (scan = s; *scan != '\0'; scan++)
  468. X        if (*scan == charwanted)
  469. X            place = scan;
  470. X    if (charwanted == '\0')
  471. X        return(scan);
  472. X    return(place);
  473. X}
  474. !
  475. echo strspn.c:
  476. sed 's/^X//' >strspn.c <<'!'
  477. X/*
  478. X * strspn - find length of initial segment of s consisting entirely
  479. X * of characters from accept
  480. X */
  481. X
  482. XSIZET
  483. Xstrspn(s, accept)
  484. XCONST char *s;
  485. XCONST char *accept;
  486. X{
  487. X    register CONST char *sscan;
  488. X    register CONST char *ascan;
  489. X    register SIZET count;
  490. X
  491. X    count = 0;
  492. X    for (sscan = s; *sscan != '\0'; sscan++) {
  493. X        for (ascan = accept; *ascan != '\0'; ascan++)
  494. X            if (*sscan == *ascan)
  495. X                break;
  496. X        if (*ascan == '\0')
  497. X            return(count);
  498. X        count++;
  499. X    }
  500. X    return(count);
  501. X}
  502. !
  503. echo strtok.c:
  504. sed 's/^X//' >strtok.c <<'!'
  505. X/*
  506. X * Get next token from string s (NULL on 2nd, 3rd, etc. calls),
  507. X * where tokens are nonempty strings separated by runs of
  508. X * chars from delim.  Writes NULs into s to end tokens.  delim need not
  509. X * remain constant from call to call.
  510. X */
  511. X
  512. X#define    NULL    0
  513. X
  514. Xstatic char *scanpoint = NULL;
  515. X
  516. Xchar *                /* NULL if no token left */
  517. Xstrtok(s, delim)
  518. Xchar *s;
  519. Xregister CONST char *delim;
  520. X{
  521. X    register char *scan;
  522. X    char *tok;
  523. X    register CONST char *dscan;
  524. X
  525. X    if (s == NULL && scanpoint == NULL)
  526. X        return(NULL);
  527. X    if (s != NULL)
  528. X        scan = s;
  529. X    else
  530. X        scan = scanpoint;
  531. X
  532. X    /*
  533. X     * Scan leading delimiters.
  534. X     */
  535. X    for (; *scan != '\0'; scan++) {
  536. X        for (dscan = delim; *dscan != '\0'; dscan++)
  537. X            if (*scan == *dscan)
  538. X                break;
  539. X        if (*dscan == '\0')
  540. X            break;
  541. X    }
  542. X    if (*scan == '\0') {
  543. X        scanpoint = NULL;
  544. X        return(NULL);
  545. X    }
  546. X
  547. X    tok = scan;
  548. X
  549. X    /*
  550. X     * Scan token.
  551. X     */
  552. X    for (; *scan != '\0'; scan++) {
  553. X        for (dscan = delim; *dscan != '\0';)    /* ++ moved down. */
  554. X            if (*scan == *dscan++) {
  555. X                scanpoint = scan+1;
  556. X                *scan = '\0';
  557. X                return(tok);
  558. X            }
  559. X    }
  560. X
  561. X    /*
  562. X     * Reached end of string.
  563. X     */
  564. X    scanpoint = NULL;
  565. X    return(tok);
  566. X}
  567. !
  568. echo strstr.c:
  569. sed 's/^X//' >strstr.c <<'!'
  570. X/*
  571. X * strstr - find first occurrence of wanted in s
  572. X */
  573. X
  574. X#define    NULL    0
  575. X
  576. Xchar *                /* found string, or NULL if none */
  577. Xstrstr(s, wanted)
  578. XCONST char *s;
  579. XCONST char *wanted;
  580. X{
  581. X    register CONST char *scan;
  582. X    register SIZET len;
  583. X    register char firstc;
  584. X    extern int strcmp();
  585. X    extern SIZET strlen();
  586. X
  587. X    /*
  588. X     * The odd placement of the two tests is so "" is findable.
  589. X     * Also, we inline the first char for speed.
  590. X     * The ++ on scan has been moved down for optimization.
  591. X     */
  592. X    firstc = *wanted;
  593. X    len = strlen(wanted);
  594. X    for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
  595. X        if (*scan++ == '\0')
  596. X            return(NULL);
  597. X    return(scan);
  598. X}
  599. !
  600. echo memcpy.c:
  601. sed 's/^X//' >memcpy.c <<'!'
  602. X/*
  603. X * memcpy - copy bytes
  604. X */
  605. X
  606. XVOIDSTAR
  607. Xmemcpy(dst, src, size)
  608. XVOIDSTAR dst;
  609. XCONST VOIDSTAR src;
  610. XSIZET size;
  611. X{
  612. X    register char *d;
  613. X    register CONST char *s;
  614. X    register SIZET n;
  615. X
  616. X    if (size <= 0)
  617. X        return(dst);
  618. X
  619. X    s = src;
  620. X    d = dst;
  621. X    if (s <= d && s + (size-1) >= d) {
  622. X        /* Overlap, must copy right-to-left. */
  623. X        s += size-1;
  624. X        d += size-1;
  625. X        for (n = size; n > 0; n--)
  626. X            *d-- = *s--;
  627. X    } else
  628. X        for (n = size; n > 0; n--)
  629. X            *d++ = *s++;
  630. X
  631. X    return(dst);
  632. X}
  633. !
  634. echo memccpy.c:
  635. sed 's/^X//' >memccpy.c <<'!'
  636. X/*
  637. X * memccpy - copy bytes up to a certain char
  638. X *
  639. X * CHARBITS should be defined only if the compiler lacks "unsigned char".
  640. X * It should be a mask, e.g. 0377 for an 8-bit machine.
  641. X */
  642. X
  643. X#define    NULL    0
  644. X
  645. X#ifndef CHARBITS
  646. X#    define    UNSCHAR(c)    ((unsigned char)(c))
  647. X#else
  648. X#    define    UNSCHAR(c)    ((c)&CHARBITS)
  649. X#endif
  650. X
  651. XVOIDSTAR
  652. Xmemccpy(dst, src, ucharstop, size)
  653. XVOIDSTAR dst;
  654. XCONST VOIDSTAR src;
  655. XSIZET size;
  656. X{
  657. X    register char *d;
  658. X    register CONST char *s;
  659. X    register SIZET n;
  660. X    register int uc;
  661. X
  662. X    if (size <= 0)
  663. X        return(NULL);
  664. X
  665. X    s = src;
  666. X    d = dst;
  667. X    uc = UNSCHAR(ucharstop);
  668. X    for (n = size; n > 0; n--)
  669. X        if (UNSCHAR(*d++ = *s++) == uc)
  670. X            return(d);
  671. X
  672. X    return(NULL);
  673. X}
  674. !
  675. echo memcmp.c:
  676. sed 's/^X//' >memcmp.c <<'!'
  677. X/*
  678. X * memcmp - compare bytes
  679. X */
  680. X
  681. Xint                /* <0, == 0, >0 */
  682. Xmemcmp(s1, s2, size)
  683. XCONST VOIDSTAR s1;
  684. XCONST VOIDSTAR s2;
  685. XSIZET size;
  686. X{
  687. X    register CONST char *scan1;
  688. X    register CONST char *scan2;
  689. X    register SIZET n;
  690. X
  691. X    scan1 = s1;
  692. X    scan2 = s2;
  693. X    for (n = size; n > 0; n--)
  694. X        if (*scan1 == *scan2) {
  695. X            scan1++;
  696. X            scan2++;
  697. X        } else
  698. X            return(*scan1 - *scan2);
  699. X
  700. X    return(0);
  701. X}
  702. !
  703. echo memchr.c:
  704. sed 's/^X//' >memchr.c <<'!'
  705. X/*
  706. X * memchr - search for a byte
  707. X *
  708. X * CHARBITS should be defined only if the compiler lacks "unsigned char".
  709. X * It should be a mask, e.g. 0377 for an 8-bit machine.
  710. X */
  711. X
  712. X#define    NULL    0
  713. X
  714. X#ifndef CHARBITS
  715. X#    define    UNSCHAR(c)    ((unsigned char)(c))
  716. X#else
  717. X#    define    UNSCHAR(c)    ((c)&CHARBITS)
  718. X#endif
  719. X
  720. XVOIDSTAR
  721. Xmemchr(s, ucharwanted, size)
  722. XCONST VOIDSTAR s;
  723. Xint ucharwanted;
  724. XSIZET size;
  725. X{
  726. X    register CONST char *scan;
  727. X    register SIZET n;
  728. X    register int uc;
  729. X
  730. X    scan = s;
  731. X    uc = UNSCHAR(ucharwanted);
  732. X    for (n = size; n > 0; n--)
  733. X        if (UNSCHAR(*scan) == uc)
  734. X            return(scan);
  735. X        else
  736. X            scan++;
  737. X
  738. X    return(NULL);
  739. X}
  740. !
  741. echo memset.c:
  742. sed 's/^X//' >memset.c <<'!'
  743. X/*
  744. X * memset - set bytes
  745. X *
  746. X * CHARBITS should be defined only if the compiler lacks "unsigned char".
  747. X * It should be a mask, e.g. 0377 for an 8-bit machine.
  748. X */
  749. X
  750. X#ifndef CHARBITS
  751. X#    define    UNSCHAR(c)    ((unsigned char)(c))
  752. X#else
  753. X#    define    UNSCHAR(c)    ((c)&CHARBITS)
  754. X#endif
  755. X
  756. XVOIDSTAR
  757. Xmemset(s, ucharfill, size)
  758. XCONST VOIDSTAR s;
  759. Xregister int ucharfill;
  760. XSIZET size;
  761. X{
  762. X    register CONST char *scan;
  763. X    register SIZET n;
  764. X    register int uc;
  765. X
  766. X    scan = s;
  767. X    uc = UNSCHAR(ucharfill);
  768. X    for (n = size; n > 0; n--)
  769. X        *scan++ = uc;
  770. X
  771. X    return(s);
  772. X}
  773. !
  774. echo bcopy.c:
  775. sed 's/^X//' >bcopy.c <<'!'
  776. X/*
  777. X - bcopy - Berklix equivalent of memcpy
  778. X */
  779. X
  780. Xbcopy(src, dst, length)
  781. XCONST char *src;
  782. Xchar *dst;
  783. Xint length;
  784. X{
  785. X    extern VOIDSTAR memcpy();
  786. X
  787. X    (void) memcpy((VOIDSTAR)dst, (CONST VOIDSTAR)src, (SIZET)length);
  788. X}
  789. !
  790. echo bcmp.c:
  791. sed 's/^X//' >bcmp.c <<'!'
  792. X/*
  793. X - bcmp - Berklix equivalent of memcmp
  794. X */
  795. X
  796. Xint                /* == 0 or != 0 for equality and inequality */
  797. Xbcmp(s1, s2, length)
  798. XCONST char *s1;
  799. XCONST char *s2;    
  800. Xint length;
  801. X{
  802. X    return(memcmp((CONST VOIDSTAR)s1, (CONST VOIDSTAR)s2, (SIZET)length));
  803. X}
  804. !
  805. echo bzero.c:
  806. sed 's/^X//' >bzero.c <<'!'
  807. X/*
  808. X - bzero - Berklix subset of memset
  809. X */
  810. X
  811. Xbzero(dst, length)
  812. Xchar *dst;
  813. Xint length;
  814. X{
  815. X    extern VOIDSTAR memset();
  816. X
  817. X    (void) memset((VOIDSTAR)dst, 0, (SIZET)length);
  818. X}
  819. !
  820. echo strerror.c:
  821. sed 's/^X//' >strerror.c <<'!'
  822. X/*
  823. X * strerror - map error number to descriptive string
  824. X *
  825. X * This version is obviously somewhat Unix-specific.
  826. X */
  827. Xchar *
  828. Xstrerror(errnum)
  829. Xint errnum;
  830. X{
  831. X    extern int errno, sys_nerr;
  832. X    extern char *sys_errlist[];
  833. X
  834. X    if (errnum > 0 && errnum < sys_nerr)
  835. X        return(sys_errlist[errnum]);
  836. X    else
  837. X        return("unknown error");
  838. X}
  839. !
  840. echo tester.c:
  841. sed 's/^X//' >tester.c <<'!'
  842. X/*
  843. X * Test program for string(3) routines.
  844. X * 
  845. X * Note that at least one Bell Labs implementation of the string
  846. X * routines flunks a couple of these tests -- the ones which test
  847. X * behavior on "negative" characters.
  848. X */
  849. X
  850. X#include <stdio.h>
  851. X#include <string.h>
  852. X
  853. X#define    STREQ(a, b)    (strcmp((a), (b)) == 0)
  854. X
  855. Xchar *it = "<UNSET>";        /* Routine name for message routines. */
  856. Xint waserror = 0;        /* For exit status. */
  857. X
  858. Xchar uctest[] = "\004\203";    /* For testing signedness of chars. */
  859. Xint charsigned;            /* Result. */
  860. X
  861. X/*
  862. X - check - complain if condition is not true
  863. X */
  864. Xvoid
  865. Xcheck(thing, number)
  866. Xint thing;
  867. Xint number;            /* Test number for error message. */
  868. X{
  869. X    if (!thing) {
  870. X        printf("%s flunked test %d\n", it, number);
  871. X        waserror = 1;
  872. X    }
  873. X}
  874. X
  875. X/*
  876. X - equal - complain if first two args don't strcmp as equal
  877. X */
  878. Xvoid
  879. Xequal(a, b, number)
  880. Xchar *a;
  881. Xchar *b;
  882. Xint number;            /* Test number for error message. */
  883. X{
  884. X    check(a != NULL && b != NULL && STREQ(a, b), number);
  885. X}
  886. X
  887. Xchar one[50];
  888. Xchar two[50];
  889. X
  890. X#ifdef UNIXERR
  891. X#define ERR 1
  892. X#endif
  893. X#ifdef BERKERR
  894. X#define ERR 1
  895. X#endif
  896. X#ifdef ERR
  897. Xint f;
  898. Xextern char *sys_errlist[];
  899. Xextern int sys_nerr;
  900. Xextern int errno;
  901. X#endif
  902. X
  903. X/* ARGSUSED */
  904. Xmain(argc, argv)
  905. Xint argc;
  906. Xchar *argv[];
  907. X{
  908. X    /*
  909. X     * First, establish whether chars are signed.
  910. X     */
  911. X    if (uctest[0] < uctest[1])
  912. X        charsigned = 0;
  913. X    else
  914. X        charsigned = 1;
  915. X
  916. X    /*
  917. X     * Then, do the rest of the work.  Split into two functions because
  918. X     * some compilers get unhappy about a single immense function.
  919. X     */
  920. X    first();
  921. X    second();
  922. X
  923. X    exit((waserror) ? 1 : 0);
  924. X}
  925. X
  926. Xfirst()
  927. X{
  928. X    /*
  929. X     * Test strcmp first because we use it to test other things.
  930. X     */
  931. X    it = "strcmp";
  932. X    check(strcmp("", "") == 0, 1);        /* Trivial case. */
  933. X    check(strcmp("a", "a") == 0, 2);    /* Identity. */
  934. X    check(strcmp("abc", "abc") == 0, 3);    /* Multicharacter. */
  935. X    check(strcmp("abc", "abcd") < 0, 4);    /* Length mismatches. */
  936. X    check(strcmp("abcd", "abc") > 0, 5);
  937. X    check(strcmp("abcd", "abce") < 0, 6);    /* Honest miscompares. */
  938. X    check(strcmp("abce", "abcd") > 0, 7);
  939. X    check(strcmp("a\203", "a") > 0, 8);    /* Tricky if char signed. */
  940. X    if (charsigned)                /* Sign-bit comparison. */
  941. X        check(strcmp("a\203", "a\003") < 0, 9);
  942. X    else
  943. X        check(strcmp("a\203", "a\003") > 0, 9);
  944. X
  945. X    /*
  946. X     * Test strcpy next because we need it to set up other tests.
  947. X     */
  948. X    it = "strcpy";
  949. X    check(strcpy(one, "abcd") == one, 1);    /* Returned value. */
  950. X    equal(one, "abcd", 2);            /* Basic test. */
  951. X
  952. X    (void) strcpy(one, "x");
  953. X    equal(one, "x", 3);            /* Writeover. */
  954. X    equal(one+2, "cd", 4);            /* Wrote too much? */
  955. X
  956. X    (void) strcpy(two, "hi there");
  957. X    (void) strcpy(one, two);
  958. X    equal(one, "hi there", 5);        /* Basic test encore. */
  959. X    equal(two, "hi there", 6);        /* Stomped on source? */
  960. X
  961. X    (void) strcpy(one, "");
  962. X    equal(one, "", 7);            /* Boundary condition. */
  963. X
  964. X    /*
  965. X     * strcat
  966. X     */
  967. X    it = "strcat";
  968. X    (void) strcpy(one, "ijk");
  969. X    check(strcat(one, "lmn") == one, 1);    /* Returned value. */
  970. X    equal(one, "ijklmn", 2);        /* Basic test. */
  971. X
  972. X    (void) strcpy(one, "x");
  973. X    (void) strcat(one, "yz");
  974. X    equal(one, "xyz", 3);            /* Writeover. */
  975. X    equal(one+4, "mn", 4);            /* Wrote too much? */
  976. X
  977. X    (void) strcpy(one, "gh");
  978. X    (void) strcpy(two, "ef");
  979. X    (void) strcat(one, two);
  980. X    equal(one, "ghef", 5);            /* Basic test encore. */
  981. X    equal(two, "ef", 6);            /* Stomped on source? */
  982. X
  983. X    (void) strcpy(one, "");
  984. X    (void) strcat(one, "");
  985. X    equal(one, "", 7);            /* Boundary conditions. */
  986. X    (void) strcpy(one, "ab");
  987. X    (void) strcat(one, "");
  988. X    equal(one, "ab", 8);
  989. X    (void) strcpy(one, "");
  990. X    (void) strcat(one, "cd");
  991. X    equal(one, "cd", 9);
  992. X
  993. X    /*
  994. X     * strncat - first test it as strcat, with big counts, then
  995. X     * test the count mechanism.
  996. X     */
  997. X    it = "strncat";
  998. X    (void) strcpy(one, "ijk");
  999. X    check(strncat(one, "lmn", 99) == one, 1);    /* Returned value. */
  1000. X    equal(one, "ijklmn", 2);        /* Basic test. */
  1001. X
  1002. X    (void) strcpy(one, "x");
  1003. X    (void) strncat(one, "yz", 99);
  1004. X    equal(one, "xyz", 3);            /* Writeover. */
  1005. X    equal(one+4, "mn", 4);            /* Wrote too much? */
  1006. X
  1007. X    (void) strcpy(one, "gh");
  1008. X    (void) strcpy(two, "ef");
  1009. X    (void) strncat(one, two, 99);
  1010. X    equal(one, "ghef", 5);            /* Basic test encore. */
  1011. X    equal(two, "ef", 6);            /* Stomped on source? */
  1012. X
  1013. X    (void) strcpy(one, "");
  1014. X    (void) strncat(one, "", 99);
  1015. X    equal(one, "", 7);            /* Boundary conditions. */
  1016. X    (void) strcpy(one, "ab");
  1017. X    (void) strncat(one, "", 99);
  1018. X    equal(one, "ab", 8);
  1019. X    (void) strcpy(one, "");
  1020. X    (void) strncat(one, "cd", 99);
  1021. X    equal(one, "cd", 9);
  1022. X
  1023. X    (void) strcpy(one, "ab");
  1024. X    (void) strncat(one, "cdef", 2);
  1025. X    equal(one, "abcd", 10);            /* Count-limited. */
  1026. X
  1027. X    (void) strncat(one, "gh", 0);
  1028. X    equal(one, "abcd", 11);            /* Zero count. */
  1029. X
  1030. X    (void) strncat(one, "gh", 2);
  1031. X    equal(one, "abcdgh", 12);        /* Count and length equal. */
  1032. X
  1033. X    /*
  1034. X     * strncmp - first test as strcmp with big counts, then test
  1035. X     * count code.
  1036. X     */
  1037. X    it = "strncmp";
  1038. X    check(strncmp("", "", 99) == 0, 1);    /* Trivial case. */
  1039. X    check(strncmp("a", "a", 99) == 0, 2);    /* Identity. */
  1040. X    check(strncmp("abc", "abc", 99) == 0, 3);    /* Multicharacter. */
  1041. X    check(strncmp("abc", "abcd", 99) < 0, 4);    /* Length unequal. */
  1042. X    check(strncmp("abcd", "abc", 99) > 0, 5);
  1043. X    check(strncmp("abcd", "abce", 99) < 0, 6);    /* Honestly unequal. */
  1044. X    check(strncmp("abce", "abcd", 99) > 0, 7);
  1045. X    check(strncmp("a\203", "a", 2) > 0, 8);    /* Tricky if '\203' < 0 */
  1046. X    if (charsigned)                /* Sign-bit comparison. */
  1047. X        check(strncmp("a\203", "a\003", 2) < 0, 9);
  1048. X    else
  1049. X        check(strncmp("a\203", "a\003", 2) > 0, 9);
  1050. X    check(strncmp("abce", "abcd", 3) == 0, 10);    /* Count limited. */
  1051. X    check(strncmp("abce", "abc", 3) == 0, 11);    /* Count == length. */
  1052. X    check(strncmp("abcd", "abce", 4) < 0, 12);    /* Nudging limit. */
  1053. X    check(strncmp("abc", "def", 0) == 0, 13);    /* Zero count. */
  1054. X
  1055. X    /*
  1056. X     * strncpy - testing is a bit different because of odd semantics
  1057. X     */
  1058. X    it = "strncpy";
  1059. X    check(strncpy(one, "abc", 4) == one, 1);    /* Returned value. */
  1060. X    equal(one, "abc", 2);            /* Did the copy go right? */
  1061. X
  1062. X    (void) strcpy(one, "abcdefgh");
  1063. X    (void) strncpy(one, "xyz", 2);
  1064. X    equal(one, "xycdefgh", 3);        /* Copy cut by count. */
  1065. X
  1066. X    (void) strcpy(one, "abcdefgh");
  1067. X    (void) strncpy(one, "xyz", 3);        /* Copy cut just before NUL. */
  1068. X    equal(one, "xyzdefgh", 4);
  1069. X
  1070. X    (void) strcpy(one, "abcdefgh");
  1071. X    (void) strncpy(one, "xyz", 4);        /* Copy just includes NUL. */
  1072. X    equal(one, "xyz", 5);
  1073. X    equal(one+4, "efgh", 6);        /* Wrote too much? */
  1074. X
  1075. X    (void) strcpy(one, "abcdefgh");
  1076. X    (void) strncpy(one, "xyz", 5);        /* Copy includes padding. */
  1077. X    equal(one, "xyz", 7);
  1078. X    equal(one+4, "", 8);
  1079. X    equal(one+5, "fgh", 9);
  1080. X
  1081. X    (void) strcpy(one, "abc");
  1082. X    (void) strncpy(one, "xyz", 0);        /* Zero-length copy. */
  1083. X    equal(one, "abc", 10);    
  1084. X
  1085. X    (void) strncpy(one, "", 2);        /* Zero-length source. */
  1086. X    equal(one, "", 11);
  1087. X    equal(one+1, "", 12);    
  1088. X    equal(one+2, "c", 13);
  1089. X
  1090. X    (void) strcpy(one, "hi there");
  1091. X    (void) strncpy(two, one, 9);
  1092. X    equal(two, "hi there", 14);        /* Just paranoia. */
  1093. X    equal(one, "hi there", 15);        /* Stomped on source? */
  1094. X
  1095. X    /*
  1096. X     * strlen
  1097. X     */
  1098. X    it = "strlen";
  1099. X    check(strlen("") == 0, 1);        /* Empty. */
  1100. X    check(strlen("a") == 1, 2);        /* Single char. */
  1101. X    check(strlen("abcd") == 4, 3);        /* Multiple chars. */
  1102. X
  1103. X    /*
  1104. X     * strchr
  1105. X     */
  1106. X    it = "strchr";
  1107. X    check(strchr("abcd", 'z') == NULL, 1);    /* Not found. */
  1108. X    (void) strcpy(one, "abcd");
  1109. X    check(strchr(one, 'c') == one+2, 2);    /* Basic test. */
  1110. X    check(strchr(one, 'd') == one+3, 3);    /* End of string. */
  1111. X    check(strchr(one, 'a') == one, 4);    /* Beginning. */
  1112. X    check(strchr(one, '\0') == one+4, 5);    /* Finding NUL. */
  1113. X    (void) strcpy(one, "ababa");
  1114. X    check(strchr(one, 'b') == one+1, 6);    /* Finding first. */
  1115. X    (void) strcpy(one, "");
  1116. X    check(strchr(one, 'b') == NULL, 7);    /* Empty string. */
  1117. X    check(strchr(one, '\0') == one, 8);    /* NUL in empty string. */
  1118. X
  1119. X    /*
  1120. X     * index - just like strchr
  1121. X     */
  1122. X    it = "index";
  1123. X    check(index("abcd", 'z') == NULL, 1);    /* Not found. */
  1124. X    (void) strcpy(one, "abcd");
  1125. X    check(index(one, 'c') == one+2, 2);    /* Basic test. */
  1126. X    check(index(one, 'd') == one+3, 3);    /* End of string. */
  1127. X    check(index(one, 'a') == one, 4);    /* Beginning. */
  1128. X    check(index(one, '\0') == one+4, 5);    /* Finding NUL. */
  1129. X    (void) strcpy(one, "ababa");
  1130. X    check(index(one, 'b') == one+1, 6);    /* Finding first. */
  1131. X    (void) strcpy(one, "");
  1132. X    check(index(one, 'b') == NULL, 7);    /* Empty string. */
  1133. X    check(index(one, '\0') == one, 8);    /* NUL in empty string. */
  1134. X
  1135. X    /*
  1136. X     * strrchr
  1137. X     */
  1138. X    it = "strrchr";
  1139. X    check(strrchr("abcd", 'z') == NULL, 1);    /* Not found. */
  1140. X    (void) strcpy(one, "abcd");
  1141. X    check(strrchr(one, 'c') == one+2, 2);    /* Basic test. */
  1142. X    check(strrchr(one, 'd') == one+3, 3);    /* End of string. */
  1143. X    check(strrchr(one, 'a') == one, 4);    /* Beginning. */
  1144. X    check(strrchr(one, '\0') == one+4, 5);    /* Finding NUL. */
  1145. X    (void) strcpy(one, "ababa");
  1146. X    check(strrchr(one, 'b') == one+3, 6);    /* Finding last. */
  1147. X    (void) strcpy(one, "");
  1148. X    check(strrchr(one, 'b') == NULL, 7);    /* Empty string. */
  1149. X    check(strrchr(one, '\0') == one, 8);    /* NUL in empty string. */
  1150. X
  1151. X    /*
  1152. X     * rindex - just like strrchr
  1153. X     */
  1154. X    it = "rindex";
  1155. X    check(rindex("abcd", 'z') == NULL, 1);    /* Not found. */
  1156. X    (void) strcpy(one, "abcd");
  1157. X    check(rindex(one, 'c') == one+2, 2);    /* Basic test. */
  1158. X    check(rindex(one, 'd') == one+3, 3);    /* End of string. */
  1159. X    check(rindex(one, 'a') == one, 4);    /* Beginning. */
  1160. X    check(rindex(one, '\0') == one+4, 5);    /* Finding NUL. */
  1161. X    (void) strcpy(one, "ababa");
  1162. X    check(rindex(one, 'b') == one+3, 6);    /* Finding last. */
  1163. X    (void) strcpy(one, "");
  1164. X    check(rindex(one, 'b') == NULL, 7);    /* Empty string. */
  1165. X    check(rindex(one, '\0') == one, 8);    /* NUL in empty string. */
  1166. X}
  1167. X
  1168. Xsecond()
  1169. X{
  1170. X    /*
  1171. X     * strpbrk - somewhat like strchr
  1172. X     */
  1173. X    it = "strpbrk";
  1174. X    check(strpbrk("abcd", "z") == NULL, 1);    /* Not found. */
  1175. X    (void) strcpy(one, "abcd");
  1176. X    check(strpbrk(one, "c") == one+2, 2);    /* Basic test. */
  1177. X    check(strpbrk(one, "d") == one+3, 3);    /* End of string. */
  1178. X    check(strpbrk(one, "a") == one, 4);    /* Beginning. */
  1179. X    check(strpbrk(one, "") == NULL, 5);    /* Empty search list. */
  1180. X    check(strpbrk(one, "cb") == one+1, 6);    /* Multiple search. */
  1181. X    (void) strcpy(one, "abcabdea");
  1182. X    check(strpbrk(one, "b") == one+1, 7);    /* Finding first. */
  1183. X    check(strpbrk(one, "cb") == one+1, 8);    /* With multiple search. */
  1184. X    check(strpbrk(one, "db") == one+1, 9);    /* Another variant. */
  1185. X    (void) strcpy(one, "");
  1186. X    check(strpbrk(one, "bc") == NULL, 10);    /* Empty string. */
  1187. X    check(strpbrk(one, "") == NULL, 11);    /* Both strings empty. */
  1188. X
  1189. X    /*
  1190. X     * strstr - somewhat like strchr
  1191. X     */
  1192. X    it = "strstr";
  1193. X    check(strstr("abcd", "z") == NULL, 1);    /* Not found. */
  1194. X    check(strstr("abcd", "abx") == NULL, 2);    /* Dead end. */
  1195. X    (void) strcpy(one, "abcd");
  1196. X    check(strstr(one, "c") == one+2, 3);    /* Basic test. */
  1197. X    check(strstr(one, "bc") == one+1, 4);    /* Multichar. */
  1198. X    check(strstr(one, "d") == one+3, 5);    /* End of string. */
  1199. X    check(strstr(one, "cd") == one+2, 6);    /* Tail of string. */
  1200. X    check(strstr(one, "abc") == one, 7);    /* Beginning. */
  1201. X    check(strstr(one, "abcd") == one, 8);    /* Exact match. */
  1202. X    check(strstr(one, "abcde") == NULL, 9);    /* Too long. */
  1203. X    check(strstr(one, "de") == NULL, 10);    /* Past end. */
  1204. X    check(strstr(one, "") == one+4, 11);    /* Finding empty. */
  1205. X    (void) strcpy(one, "ababa");
  1206. X    check(strstr(one, "ba") == one+1, 12);    /* Finding first. */
  1207. X    (void) strcpy(one, "");
  1208. X    check(strstr(one, "b") == NULL, 13);    /* Empty string. */
  1209. X    check(strstr(one, "") == one, 14);    /* Empty in empty string. */
  1210. X    (void) strcpy(one, "bcbca");
  1211. X    check(strstr(one, "bca") == one+2, 15);    /* False start. */
  1212. X    (void) strcpy(one, "bbbcabbca");
  1213. X    check(strstr(one, "bbca") == one+1, 16);    /* With overlap. */
  1214. X
  1215. X    /*
  1216. X     * strspn
  1217. X     */
  1218. X    it = "strspn";
  1219. X    check(strspn("abcba", "abc") == 5, 1);    /* Whole string. */
  1220. X    check(strspn("abcba", "ab") == 2, 2);    /* Partial. */
  1221. X    check(strspn("abc", "qx") == 0, 3);    /* None. */
  1222. X    check(strspn("", "ab") == 0, 4);    /* Null string. */
  1223. X    check(strspn("abc", "") == 0, 5);    /* Null search list. */
  1224. X
  1225. X    /*
  1226. X     * strcspn
  1227. X     */
  1228. X    it = "strcspn";
  1229. X    check(strcspn("abcba", "qx") == 5, 1);    /* Whole string. */
  1230. X    check(strcspn("abcba", "cx") == 2, 2);    /* Partial. */
  1231. X    check(strcspn("abc", "abc") == 0, 3);    /* None. */
  1232. X    check(strcspn("", "ab") == 0, 4);    /* Null string. */
  1233. X    check(strcspn("abc", "") == 3, 5);    /* Null search list. */
  1234. X
  1235. X    /*
  1236. X     * strtok - the hard one
  1237. X     */
  1238. X    it = "strtok";
  1239. X    (void) strcpy(one, "first, second, third");
  1240. X    equal(strtok(one, ", "), "first", 1);    /* Basic test. */
  1241. X    equal(one, "first", 2);
  1242. X    equal(strtok((char *)NULL, ", "), "second", 3);
  1243. X    equal(strtok((char *)NULL, ", "), "third", 4);
  1244. X    check(strtok((char *)NULL, ", ") == NULL, 5);
  1245. X    (void) strcpy(one, ", first, ");
  1246. X    equal(strtok(one, ", "), "first", 6);    /* Extra delims, 1 tok. */
  1247. X    check(strtok((char *)NULL, ", ") == NULL, 7);
  1248. X    (void) strcpy(one, "1a, 1b; 2a, 2b");
  1249. X    equal(strtok(one, ", "), "1a", 8);    /* Changing delim lists. */
  1250. X    equal(strtok((char *)NULL, "; "), "1b", 9);
  1251. X    equal(strtok((char *)NULL, ", "), "2a", 10);
  1252. X    (void) strcpy(two, "x-y");
  1253. X    equal(strtok(two, "-"), "x", 11);    /* New string before done. */
  1254. X    equal(strtok((char *)NULL, "-"), "y", 12);
  1255. X    check(strtok((char *)NULL, "-") == NULL, 13);
  1256. X    (void) strcpy(one, "a,b, c,, ,d");
  1257. X    equal(strtok(one, ", "), "a", 14);    /* Different separators. */
  1258. X    equal(strtok((char *)NULL, ", "), "b", 15);
  1259. X    equal(strtok((char *)NULL, " ,"), "c", 16);    /* Permute list too. */
  1260. X    equal(strtok((char *)NULL, " ,"), "d", 17);
  1261. X    check(strtok((char *)NULL, ", ") == NULL, 18);
  1262. X    check(strtok((char *)NULL, ", ") == NULL, 19);    /* Persistence. */
  1263. X    (void) strcpy(one, ", ");
  1264. X    check(strtok(one, ", ") == NULL, 20);    /* No tokens. */
  1265. X    (void) strcpy(one, "");
  1266. X    check(strtok(one, ", ") == NULL, 21);    /* Empty string. */
  1267. X    (void) strcpy(one, "abc");
  1268. X    equal(strtok(one, ", "), "abc", 22);    /* No delimiters. */
  1269. X    check(strtok((char *)NULL, ", ") == NULL, 23);
  1270. X    (void) strcpy(one, "abc");
  1271. X    equal(strtok(one, ""), "abc", 24);    /* Empty delimiter list. */
  1272. X    check(strtok((char *)NULL, "") == NULL, 25);
  1273. X    (void) strcpy(one, "abcdefgh");
  1274. X    (void) strcpy(one, "a,b,c");
  1275. X    equal(strtok(one, ","), "a", 26);    /* Basics again... */
  1276. X    equal(strtok((char *)NULL, ","), "b", 27);
  1277. X    equal(strtok((char *)NULL, ","), "c", 28);
  1278. X    check(strtok((char *)NULL, ",") == NULL, 29);
  1279. X    equal(one+6, "gh", 30);            /* Stomped past end? */
  1280. X    equal(one, "a", 31);            /* Stomped old tokens? */
  1281. X    equal(one+2, "b", 32);
  1282. X    equal(one+4, "c", 33);
  1283. X
  1284. X    /*
  1285. X     * memcmp
  1286. X     */
  1287. X    it = "memcmp";
  1288. X    check(memcmp("a", "a", 1) == 0, 1);    /* Identity. */
  1289. X    check(memcmp("abc", "abc", 3) == 0, 2);    /* Multicharacter. */
  1290. X    check(memcmp("abcd", "abce", 4) < 0, 3);    /* Honestly unequal. */
  1291. X    check(memcmp("abce", "abcd", 4) > 0, 4);
  1292. X    check(memcmp("alph", "beta", 4) < 0, 5);
  1293. X    if (charsigned)                /* Sign-bit comparison. */
  1294. X        check(memcmp("a\203", "a\003", 2) < 0, 6);
  1295. X    else
  1296. X        check(memcmp("a\203", "a\003", 2) > 0, 6);
  1297. X    check(memcmp("abce", "abcd", 3) == 0, 7);    /* Count limited. */
  1298. X    check(memcmp("abc", "def", 0) == 0, 8);    /* Zero count. */
  1299. X
  1300. X    /*
  1301. X     * memchr
  1302. X     */
  1303. X    it = "memchr";
  1304. X    check(memchr("abcd", 'z', 4) == NULL, 1);    /* Not found. */
  1305. X    (void) strcpy(one, "abcd");
  1306. X    check(memchr(one, 'c', 4) == one+2, 2);    /* Basic test. */
  1307. X    check(memchr(one, 'd', 4) == one+3, 3);    /* End of string. */
  1308. X    check(memchr(one, 'a', 4) == one, 4);    /* Beginning. */
  1309. X    check(memchr(one, '\0', 5) == one+4, 5);    /* Finding NUL. */
  1310. X    (void) strcpy(one, "ababa");
  1311. X    check(memchr(one, 'b', 5) == one+1, 6);    /* Finding first. */
  1312. X    check(memchr(one, 'b', 0) == NULL, 7);    /* Zero count. */
  1313. X    check(memchr(one, 'a', 1) == one, 8);    /* Singleton case. */
  1314. X    (void) strcpy(one, "a\203b");
  1315. X    check(memchr(one, 0203, 3) == one+1, 9);    /* Unsignedness. */
  1316. X
  1317. X    /*
  1318. X     * memcpy
  1319. X     *
  1320. X     * Note that X3J11 says memcpy must work regardless of overlap.
  1321. X     * The SVID says it might fail.
  1322. X     */
  1323. X    it = "memcpy";
  1324. X    check(memcpy(one, "abc", 4) == one, 1);    /* Returned value. */
  1325. X    equal(one, "abc", 2);            /* Did the copy go right? */
  1326. X
  1327. X    (void) strcpy(one, "abcdefgh");
  1328. X    (void) memcpy(one+1, "xyz", 2);
  1329. X    equal(one, "axydefgh", 3);        /* Basic test. */
  1330. X
  1331. X    (void) strcpy(one, "abc");
  1332. X    (void) memcpy(one, "xyz", 0);
  1333. X    equal(one, "abc", 4);            /* Zero-length copy. */
  1334. X
  1335. X    (void) strcpy(one, "hi there");
  1336. X    (void) strcpy(two, "foo");
  1337. X    (void) memcpy(two, one, 9);
  1338. X    equal(two, "hi there", 5);        /* Just paranoia. */
  1339. X    equal(one, "hi there", 6);        /* Stomped on source? */
  1340. X
  1341. X    (void) strcpy(one, "abcdefgh");
  1342. X    (void) memcpy(one+1, one, 9);
  1343. X    equal(one, "aabcdefgh", 7);        /* Overlap, right-to-left. */
  1344. X
  1345. X    (void) strcpy(one, "abcdefgh");
  1346. X    (void) memcpy(one+1, one+2, 7);
  1347. X    equal(one, "acdefgh", 8);        /* Overlap, left-to-right. */
  1348. X
  1349. X    (void) strcpy(one, "abcdefgh");
  1350. X    (void) memcpy(one, one, 9);
  1351. X    equal(one, "abcdefgh", 9);        /* 100% overlap. */
  1352. X
  1353. X    /*
  1354. X     * memccpy - first test like memcpy, then the search part
  1355. X     *
  1356. X     * The SVID, the only place where memccpy is mentioned, says
  1357. X     * overlap might fail, so we don't try it.  Besides, it's hard
  1358. X     * to see the rationale for a non-left-to-right memccpy.
  1359. X     */
  1360. X    it = "memccpy";
  1361. X    check(memccpy(one, "abc", 'q', 4) == NULL, 1);    /* Returned value. */
  1362. X    equal(one, "abc", 2);            /* Did the copy go right? */
  1363. X
  1364. X    (void) strcpy(one, "abcdefgh");
  1365. X    (void) memccpy(one+1, "xyz", 'q', 2);
  1366. X    equal(one, "axydefgh", 3);        /* Basic test. */
  1367. X
  1368. X    (void) strcpy(one, "abc");
  1369. X    (void) memccpy(one, "xyz", 'q', 0);
  1370. X    equal(one, "abc", 4);            /* Zero-length copy. */
  1371. X
  1372. X    (void) strcpy(one, "hi there");
  1373. X    (void) strcpy(two, "foo");
  1374. X    (void) memccpy(two, one, 'q', 9);
  1375. X    equal(two, "hi there", 5);        /* Just paranoia. */
  1376. X    equal(one, "hi there", 6);        /* Stomped on source? */
  1377. X
  1378. X    (void) strcpy(one, "abcdefgh");
  1379. X    (void) strcpy(two, "horsefeathers");
  1380. X    check(memccpy(two, one, 'f', 9) == two+6, 7);    /* Returned value. */
  1381. X    equal(one, "abcdefgh", 8);        /* Source intact? */
  1382. X    equal(two, "abcdefeathers", 9);        /* Copy correct? */
  1383. X
  1384. X    (void) strcpy(one, "abcd");
  1385. X    (void) strcpy(two, "bumblebee");
  1386. X    check(memccpy(two, one, 'a', 4) == two+1, 10);    /* First char. */
  1387. X    equal(two, "aumblebee", 11);
  1388. X    check(memccpy(two, one, 'd', 4) == two+4, 12);    /* Last char. */
  1389. X    equal(two, "abcdlebee", 13);
  1390. X    (void) strcpy(one, "xyz");
  1391. X    check(memccpy(two, one, 'x', 1) == two+1, 14);    /* Singleton. */
  1392. X    equal(two, "xbcdlebee", 15);
  1393. X
  1394. X    /*
  1395. X     * memset
  1396. X     */
  1397. X    it = "memset";
  1398. X    (void) strcpy(one, "abcdefgh");
  1399. X    check(memset(one+1, 'x', 3) == one+1, 1);    /* Return value. */
  1400. X    equal(one, "axxxefgh", 2);        /* Basic test. */
  1401. X
  1402. X    (void) memset(one+2, 'y', 0);
  1403. X    equal(one, "axxxefgh", 3);        /* Zero-length set. */
  1404. X
  1405. X    (void) memset(one+5, 0, 1);
  1406. X    equal(one, "axxxe", 4);            /* Zero fill. */
  1407. X    equal(one+6, "gh", 5);            /* And the leftover. */
  1408. X
  1409. X    (void) memset(one+2, 010045, 1);
  1410. X    equal(one, "ax\045xe", 6);        /* Unsigned char convert. */
  1411. X
  1412. X    /*
  1413. X     * bcopy - much like memcpy
  1414. X     *
  1415. X     * Berklix manual is silent about overlap, so don't test it.
  1416. X     */
  1417. X    it = "bcopy";
  1418. X    (void) bcopy("abc", one, 4);
  1419. X    equal(one, "abc", 1);            /* Simple copy. */
  1420. X
  1421. X    (void) strcpy(one, "abcdefgh");
  1422. X    (void) bcopy("xyz", one+1, 2);
  1423. X    equal(one, "axydefgh", 2);        /* Basic test. */
  1424. X
  1425. X    (void) strcpy(one, "abc");
  1426. X    (void) bcopy("xyz", one, 0);
  1427. X    equal(one, "abc", 3);            /* Zero-length copy. */
  1428. X
  1429. X    (void) strcpy(one, "hi there");
  1430. X    (void) strcpy(two, "foo");
  1431. X    (void) bcopy(one, two, 9);
  1432. X    equal(two, "hi there", 4);        /* Just paranoia. */
  1433. X    equal(one, "hi there", 5);        /* Stomped on source? */
  1434. X
  1435. X    /*
  1436. X     * bzero
  1437. X     */
  1438. X    it = "bzero";
  1439. X    (void) strcpy(one, "abcdef");
  1440. X    bzero(one+2, 2);
  1441. X    equal(one, "ab", 1);            /* Basic test. */
  1442. X    equal(one+3, "", 2);
  1443. X    equal(one+4, "ef", 3);
  1444. X
  1445. X    (void) strcpy(one, "abcdef");
  1446. X    bzero(one+2, 0);
  1447. X    equal(one, "abcdef", 4);        /* Zero-length copy. */
  1448. X
  1449. X    /*
  1450. X     * bcmp - somewhat like memcmp
  1451. X     */
  1452. X    it = "bcmp";
  1453. X    check(bcmp("a", "a", 1) == 0, 1);    /* Identity. */
  1454. X    check(bcmp("abc", "abc", 3) == 0, 2);    /* Multicharacter. */
  1455. X    check(bcmp("abcd", "abce", 4) != 0, 3);    /* Honestly unequal. */
  1456. X    check(bcmp("abce", "abcd", 4) != 0, 4);
  1457. X    check(bcmp("alph", "beta", 4) != 0, 5);
  1458. X    check(bcmp("abce", "abcd", 3) == 0, 6);    /* Count limited. */
  1459. X    check(bcmp("abc", "def", 0) == 0, 8);    /* Zero count. */
  1460. X
  1461. X#ifdef ERR
  1462. X    /*
  1463. X     * strerror - VERY system-dependent
  1464. X     */
  1465. X    it = "strerror";
  1466. X    f = open("/", 1);    /* Should always fail. */
  1467. X    check(f < 0 && errno > 0 && errno < sys_nerr, 1);
  1468. X    equal(strerror(errno), sys_errlist[errno], 2);
  1469. X#ifdef UNIXERR
  1470. X    equal(strerror(errno), "Is a directory", 3);
  1471. X#endif
  1472. X#ifdef BERKERR
  1473. X    equal(strerror(errno), "Permission denied", 3);
  1474. X#endif
  1475. X#endif
  1476. X}
  1477. !
  1478. echo string.h.proto:
  1479. sed 's/^X//' >string.h.proto <<'!'
  1480. X/*
  1481. X * String functions.
  1482. X */
  1483. X
  1484. XVOIDSTAR memcpy(/*VOIDSTAR dst, const VOIDSTAR src, SIZET size*/);
  1485. XVOIDSTAR memccpy(/*VOIDSTAR dst, const VOIDSTAR src, int ucharstop, SIZET size*/);
  1486. Xchar *strcpy(/*char *dst, const char *src*/);
  1487. Xchar *strncpy(/*char *dst, const char *src, SIZET size*/);
  1488. Xchar *strcat(/*char *dst, const char *src*/);
  1489. Xchar *strncat(/*char *dst, const char *src, SIZET size*/);
  1490. Xint memcmp(/*const VOIDSTAR s1, const VOIDSTAR s2, SIZET size*/);
  1491. Xint strcmp(/*const char *s1, const char *s2*/);
  1492. Xint strncmp(/*const char *s1, const char *s2, SIZET size*/);
  1493. XVOIDSTAR memchr(/*const VOIDSTAR s, int ucharwanted, SIZET size*/);
  1494. Xchar *strchr(/*const char *s, int charwanted*/);
  1495. XSIZET strcspn(/*const char *s, const char *reject*/);
  1496. Xchar *strpbrk(/*const char *s, const char *breakat*/);
  1497. Xchar *strrchr(/*const char *s, int charwanted*/);
  1498. XSIZET strspn(/*const char *s, const char *accept*/);
  1499. Xchar *strstr(/*const char *s, const char *wanted*/);
  1500. Xchar *strtok(/*char *s, const char *delim*/);
  1501. XVOIDSTAR memset(/*VOIDSTAR s, int ucharfill, SIZET size*/);
  1502. XSIZET strlen(/*const char *s*/);
  1503. X
  1504. X/*
  1505. X * V7 and Berklix compatibility.
  1506. X */
  1507. Xchar *index(/*const char *s, int charwanted*/);
  1508. Xchar *rindex(/*const char *s, int charwanted*/);
  1509. Xint bcopy(/*const char *src, char *dst, int length*/);
  1510. Xint bcmp(/*const char *s1, const char *s2, int length*/);
  1511. Xint bzero(/*char *dst, int length*/);
  1512. X
  1513. X/*
  1514. X * Putting this in here is really silly, but who am I to argue with X3J11?
  1515. X */
  1516. Xchar *strerror(/*int errnum*/);
  1517. !
  1518. echo done
  1519. ------------------
  1520.  
  1521.