1 /* $NetBSD: mystrtok.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* mystrtok 3 6 /* SUMMARY 7 /* safe tokenizer 8 /* SYNOPSIS 9 /* #include <stringops.h> 10 /* 11 /* char *mystrtok(bufp, delimiters) 12 /* char **bufp; 13 /* const char *delimiters; 14 /* 15 /* char *mystrtokq(bufp, delimiters, parens) 16 /* char **bufp; 17 /* const char *delimiters; 18 /* const char *parens; 19 /* DESCRIPTION 20 /* mystrtok() splits a buffer on the specified \fIdelimiters\fR. 21 /* Tokens are delimited by runs of delimiters, so this routine 22 /* cannot return zero-length tokens. 23 /* 24 /* mystrtokq() is like mystrtok() but will not split text 25 /* between balanced parentheses. \fIparens\fR specifies the 26 /* opening and closing parenthesis (one of each). The set of 27 /* \fIparens\fR must be distinct from the set of \fIdelimiters\fR. 28 /* 29 /* The \fIbufp\fR argument specifies the start of the search; it 30 /* is updated with each call. The input is destroyed. 31 /* 32 /* The result value is the next token, or a null pointer when the 33 /* end of the buffer was reached. 34 /* LICENSE 35 /* .ad 36 /* .fi 37 /* The Secure Mailer license must be distributed with this software. 38 /* AUTHOR(S) 39 /* Wietse Venema 40 /* IBM T.J. Watson Research 41 /* P.O. Box 704 42 /* Yorktown Heights, NY 10598, USA 43 /*--*/ 44 45 /* System library. */ 46 47 #include "sys_defs.h" 48 #include <string.h> 49 50 /* Utility library. */ 51 52 #include "stringops.h" 53 54 /* mystrtok - safe tokenizer */ 55 56 char *mystrtok(char **src, const char *sep) 57 { 58 char *start = *src; 59 char *end; 60 61 /* 62 * Skip over leading delimiters. 63 */ 64 start += strspn(start, sep); 65 if (*start == 0) { 66 *src = start; 67 return (0); 68 } 69 70 /* 71 * Separate off one token. 72 */ 73 end = start + strcspn(start, sep); 74 if (*end != 0) 75 *end++ = 0; 76 *src = end; 77 return (start); 78 } 79 80 /* mystrtokq - safe tokenizer with quoting support */ 81 82 char *mystrtokq(char **src, const char *sep, const char *parens) 83 { 84 char *start = *src; 85 static char *cp; 86 int ch; 87 int level; 88 89 /* 90 * Skip over leading delimiters. 91 */ 92 start += strspn(start, sep); 93 if (*start == 0) { 94 *src = start; 95 return (0); 96 } 97 98 /* 99 * Parse out the next token. 100 */ 101 for (level = 0, cp = start; (ch = *(unsigned char *) cp) != 0; cp++) { 102 if (ch == parens[0]) { 103 level++; 104 } else if (level > 0 && ch == parens[1]) { 105 level--; 106 } else if (level == 0 && strchr(sep, ch) != 0) { 107 *cp++ = 0; 108 break; 109 } 110 } 111 *src = cp; 112 return (start); 113 } 114 115 #ifdef TEST 116 117 /* 118 * Test program: read lines from stdin, split on whitespace. 119 */ 120 #include "vstring.h" 121 #include "vstream.h" 122 #include "vstring_vstream.h" 123 124 int main(void) 125 { 126 VSTRING *vp = vstring_alloc(100); 127 char *start; 128 char *str; 129 130 while (vstring_fgets(vp, VSTREAM_IN) && VSTRING_LEN(vp) > 0) { 131 start = vstring_str(vp); 132 if (strchr(start, CHARS_BRACE[0]) == 0) { 133 while ((str = mystrtok(&start, CHARS_SPACE)) != 0) 134 vstream_printf(">%s<\n", str); 135 } else { 136 while ((str = mystrtokq(&start, CHARS_SPACE, CHARS_BRACE)) != 0) 137 vstream_printf(">%s<\n", str); 138 } 139 vstream_fflush(VSTREAM_OUT); 140 } 141 vstring_free(vp); 142 return (0); 143 } 144 145 #endif 146