2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1997-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: token.c,v 1.29 2006/01/14 04:37:19 paddy_s Exp $
29 * token bashing routines
33 ** The quoting method used here was selected because it has the
34 ** property that quoting a string that doesn't contain funny
35 ** characters results in an unchanged string and it was easy to code.
36 ** There are probably other algorithms that are just as effective.
43 /* Split a string up into tokens.
44 ** There is exactly one separator character between tokens.
45 ** XXX Won't work too well if separator is '\'!
47 ** Inspired by awk and a routine called splitter() that I snarfed from
48 ** the net ages ago (original author long forgotten).
50 int split(str, token, toklen, sep)
51 char *str; /* String to split */
52 char **token; /* Array of token pointers */
53 int toklen; /* Size of token[] */
54 char *sep; /* Token separators - usually " " */
56 register char *pi, *po;
59 static char *buf = (char *)0; /* XXX - static buffer */
62 assert(str && token && toklen > 0 && sep);
66 for (fld = 1; fld < toklen; fld++) token[fld] = (char *)0;
70 if (*sep == '\0' || *str == '\0' || toklen == 1) return fld;
72 /* Calculate the length of the unquoted string. */
75 for (pi = str; *pi && *pi != '\n'; pi++) {
77 case '\\': /* had better not be trailing... */
79 if (*pi >= '0' && *pi <= '3') pi = pi + 2;
82 case '"': /* just ignore "'s */
89 /* Allocate some space */
91 buf = newalloc(buf, len+1);
93 /* Copy it across and tokenise it */
98 for (pi = str; *pi && *pi != '\n'; pi++) {
99 if (*pi == '\\') { /* escape */
101 if (*pi >= '0' && *pi <= '3') {
102 *po = ((*pi++ - '0') << 6);
103 *po = *po + ((*pi++ - '0') << 3);
104 *po = *po + ((*pi - '0') );
109 else if (*pi == '"') { /* quotes */
110 in_quotes = !in_quotes;
112 else if (!in_quotes && strchr(sep, *pi)) { /* separator */
113 *po = '\0'; /* end of token */
114 if (fld+1 >= toklen) return fld; /* too many tokens */
115 token[++fld] = po + 1;
119 *po++ = *pi; /* normal */
124 assert(po == buf + len); /* Just checking! */
130 ** Quote all the funny characters in one token.
131 ** - squotef - formatted string with space separator
132 ** - quotef - formatted string with specified separators
133 ** - squote - fixed string with space separator
134 ** - quote - fixed strings with specified separators
136 printf_arglist_function(char *squotef, char *, format)
141 /* Format the token */
143 arglist_start(argp, format);
144 vsnprintf(linebuf, sizeof(linebuf), format, argp);
147 return quote(" ", linebuf);
150 printf_arglist_function1(char *quotef, char *, sep, char *, format)
155 /* Format the token */
157 arglist_start(argp, format);
158 vsnprintf(linebuf, sizeof(linebuf), format, argp);
161 return quote(sep, linebuf);
165 char *str; /* the string to quote */
167 return quote(" ", str);
170 char *quote(sepchr, str)
171 char *sepchr; /* separators that also need quoting */
172 char *str; /* the string to quote */
174 register char *pi, *po;
177 int sep, need_quotes;
179 /* Calculate the length of the quoted token. */
182 for (pi = str; *pi; pi++) {
183 if (*pi < ' ' || *pi > '~')
185 else if (*pi == '\\' || *pi == '"')
187 else if (*sepchr && strchr(sepchr, *pi)) {
195 need_quotes = (sep != 0);
197 if (need_quotes) len = len + 2;
199 /* Allocate some space */
201 buf = alloc(len+1); /* trailing null */
207 if (need_quotes) *po++ = '"';
209 for (pi = str; *pi; pi++) {
210 if (*pi < ' ' || *pi > '~') {
212 *po++ = ((*pi >> 6) & 07) + '0';
213 *po++ = ((*pi >> 3) & 07) + '0';
214 *po++ = ((*pi ) & 07) + '0';
216 else if (*pi == '\\' || *pi == '"') {
223 if (need_quotes) *po++ = '"';
227 assert(po - buf == len); /* Just checking! */
232 /* Quote a string so that it can be used as a regular expression */
234 char *str; /* the string to quote */
240 /* Calculate the length of the quoted token. */
243 for (pi = str; *pi; pi++) {
245 /* regular expression meta-characters: */
260 case '}' /* no colon */
270 /* Allocate some space */
272 buf = alloc(len+1); /* trailing null */
278 for (pi = str; *pi; pi++) {
292 assert(po - buf == len); /* Just checking! */
298 /* Quote a string so that it can be safely passed to a shell */
300 char *str; /* the string to quote */
306 /* Calculate the length of the quoted token. */
309 for (pi = str; *pi; pi++) {
311 /* shell meta-characters: */
335 case '}' /* no colon */
345 /* Allocate some space */
347 buf = alloc(len+1); /* trailing null */
353 for (pi = str; *pi; pi++) {
367 assert(po - buf == len); /* Just checking! */
375 int table_lookup(table, str)
379 while(table->word != (char *)0) {
380 if (*table->word == *str &&
381 strcmp(table->word, str) == 0) return table->value;
388 /* Reverse table lookup.
390 char *table_lookup_r(table, val)
394 while(table->word != (char *)0) {
395 if (table->value == val) return table->word;
414 set_pname("token test");
416 /* Don't die when child closes pipe */
417 signal(SIGPIPE, SIG_IGN);
419 erroutput_type = ERR_INTERACTIVE;
421 printf("Testing split() with \" \" token separator\n");
423 printf("Input string: ");
425 if ((str = agets(stdin)) == NULL) {
429 r = split(str, t, 20, " ");
430 printf("%d token%s:\n", r, (r == 1) ? "" : "s");
431 for (i=0; i <= r; i++) printf("tok[%d] = \"%s\"\n", i, t[i]);
436 printf("Testing quote()\n");
438 printf("Input string: ");
440 if ((str = agets(stdin)) == NULL) {
445 printf("Quoted = \"%s\"\n", sr);
446 strncpy(str,sr,sizeof(str)-1);
447 str[sizeof(str)-1] = '\0';
448 r = split(str, t, 20, " ");
449 if (r != 1) printf("split()=%d!\n", r);
450 printf("Unquoted = \"%s\"\n", t[1]);