Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / cmd / listen / nstoa.c
blob072b38d492e7d0bca48cb360faaf9602dbe32319
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
32 stoa - convert string to address
34 If a string begins in \o or \O, the following address is octal
35 " " " " " \x or \X, the following address is hex
36 Otherwise, a string is considered text. Text may be quoted
37 with double quotes and the C-like escapes \n, \b, \t, \v, \r, and \nnn
38 (nnn = octal char) are recognized.
39 A \ followed by a newline causes the newline
40 to vanish. A \ followed by any other char causes any "magic" of
41 any other char to disappear.
43 Other escape sequences recognized are:
44 \!cmd args [ \! || EOL ]
45 which is replaced by the raw output of the execution of cmd.
46 This may only be used in a string.
48 \$cmd args [ \$ || EOL ]
49 which is replaced by the output of the execution of cmd and
50 is then reprocessed.
52 A NULL is returned on any error(s).
55 #include <stdio.h>
56 #include <memory.h>
57 #include <ctype.h>
58 #include "nsaddr.h"
61 #define toupper(c) (islower(c) ? _toupper(c) : (c))
62 #define todigit(c) ((int)((c) - '0')) /* char to digit */
63 #define toxdigit(c) ((isdigit(c))?todigit(c):(toupper(c)-(int)'A'+10))
64 #define isodigit(c) (isdigit(c) && ((c) != '9') && ((c) != '8'))
65 #define itoac(i) (((i) > 9) ? ((char)((i)-10) + 'A'):((char)(i) + '0'))
66 #define MASK(n) ((1 << (n)) - 1)
68 #define MAXRLEVEL 10 /* maximum recursion level */
70 #define TRUE 1;
71 #define FALSE 0;
73 char scanbuf[SBUFSIZE];
74 int sbp = 0;
75 int rec = 0; /* Recursion level */
77 char sbuf[SBUFSIZE];
79 extern void free();
81 struct netbuf *
82 stoa(str, addr) /* Return 0 for success, -1 for error */
83 char *str;
84 struct netbuf *addr;
86 char *xfer(), *prescan();
88 int myadr; /* was netbuf struct allocated here ? */
89 int quote; /* quoted string ? */
91 myadr = FALSE;
93 if (!str)
94 return NULL;
95 while (*str && isspace(*str)) /* leading whites are OK */
96 ++str;
98 str = prescan(str); /* Do all \$ ... \$ */
100 if (!str || !*str) return NULL; /* Nothing to convert */
102 if (!addr) {
103 if ((addr = (struct netbuf *)malloc(sizeof(struct netbuf))) == NULL)
104 return NULL;
105 myadr = TRUE;
106 addr->buf = NULL;
107 addr->maxlen = 0;
108 addr->len = 0;
111 /* Now process the address */
112 quote = 0;
114 if (*str == '\\') {
115 ++str;
116 switch (*str) {
118 case 'X': /* hex */
119 case 'x':
120 addr->len = dobase(++str, sbuf, HEX);
121 break;
123 case 'o': /* octal */
124 case 'O':
125 addr->len = dobase(++str, sbuf, OCT);
126 break;
128 case '\0': /* No address given!, length is 0 */
129 addr->len = dostring(str, sbuf, 0);
130 break;
132 default: /* \ is handled by dostring */
133 addr->len = dostring(--str, sbuf, quote);
134 break;
137 else {
138 if (*str == '"') { /* quoted string */
139 quote = 1;
140 ++str;
142 addr->len = dostring(str, sbuf, quote);
145 if (addr->len == 0) { /* Error in conversion */
146 if (myadr)
147 free(addr);
148 return NULL;
150 if ((addr->buf = xfer(addr->buf, sbuf, addr->len, addr->maxlen)) == NULL)
151 return NULL;
152 else
153 return addr;
158 dostring: Copy string at s to buf translating
159 escaped characters and shell escapes.
160 return length of string.
164 dostring(s, buf, quote) /* read in a raw address */
165 char *s, *buf;
166 int quote;
168 char *xcmd();
170 int oc, ch, len = 0;
171 int l = 0;
172 char *rout;
174 while (*s) {
175 if (len >= SBUFSIZE) {
176 fprintf(stderr, "dostring: string too long\n");
177 break;
179 else if (*s == '\\')
180 switch(*++s) {
182 case '!': /* raw shell escape */
183 if (rout = xcmd(s+1, '!', &s, &l)) {
184 if (len + l < SBUFSIZE)
185 memcpy(buf+len, rout, l);
186 len += l;
187 free(rout);
189 break;
191 case '\n': /* ignore newline */
192 ++s;
193 break;
195 case 'b': /* backspace */
196 buf[len++] = '\b'; s++;
197 break;
199 case 'n': /* newline */
200 buf[len++] = '\n'; s++;
201 break;
203 case 'r': /* return */
204 buf[len++] = '\r'; s++;
205 break;
207 case 't': /* horiz. tab */
208 buf[len++] = '\t'; s++;
209 break;
211 case 'v': /* vert. tab */
212 buf[len++] = '\v'; s++;
213 /* FALLTHROUGH */
215 case '0':
216 case '1':
217 case '2':
218 case '3':
219 for(oc=ch=0; (*s >= '0' && *s <= '7') && oc++ < 3; ++s)
220 ch = (ch << 3) | (*s - '0');
221 buf[len++] = ch;
222 break;
224 case 0: /* end of string -- terminate */
225 break;
227 default: /* take the character blindly */
228 buf[len++] = *s++;
229 break;
231 else if ((quote && (*s == '"')) || (!quote && isspace(*s)))
232 break;
234 else
235 buf[len++] = *s++;
237 return (len >= SBUFSIZE) ? 0 : len;
242 dobase : converts a hex or octal ASCII string
243 to a binary address. Only HEX or OCT may be used
244 for type.
245 return length of binary string (in bytes), 0 if error.
246 The binary result is placed at buf.
250 dobase(s, buf, type) /* read in an address */
251 char *s, *buf; /* source ASCII, result binary string */
252 int type;
254 void memcp();
255 int bp = SBUFSIZE - 1;
256 int shift = 0;
257 char *end;
259 for (end = s; *end && ((type == OCT) ? isodigit(*end) :
260 isxdigit(*end)); ++end) ;
262 /* any non-white, non-digits cause address to be rejected,
263 other fields are ignored */
265 if ((*s == 0) || (end == s) || (!isspace(*end) && *end)) {
266 fprintf(stderr, "dobase: Illegal trailer on address string\n");
267 buf[0] = '\0';
268 return 0;
270 --end;
272 buf[bp] = '\0';
274 while (bp > 0 && end >= s) {
275 buf[bp] |= toxdigit(*end) << shift;
276 if (type == OCT) {
277 if (shift > 5) {
278 buf[--bp] = (todigit(*end) >> (8 - shift))
279 & MASK(shift-5);
281 if ((shift = (shift + 3) % 8) == 0)
282 buf[--bp] = 0;
284 else /* hex */
285 if ((shift = (shift) ? 0 : 4) == 0)
286 buf[--bp] = 0;;
287 --end;
289 if (bp == 0) {
290 fprintf(stderr, "stoa: dobase: number to long\n");
291 return 0;
294 /* need to catch end case to avoid extra 0's in front */
295 if (!shift)
296 bp++;
297 memcp(buf, &buf[bp], (SBUFSIZE - bp));
298 return (SBUFSIZE - bp);
301 #ifdef NOTUSED
306 atos(str, addr, type)
308 convert address to ASCII form with address in hex, octal,
309 or character form.
310 return pointer to buffer (NULL on failure).
314 char *
315 atos(str, addr, type)
316 char *str;
317 struct netbuf *addr;
318 int type;
320 char *xfer();
321 int mystr = 0; /* was str allocated here ? */
322 unsigned x_atos(), o_atos();
323 void memcp();
325 char *base;
327 if (addr == NULL)
328 return NULL;
330 if (str == NULL)
331 if ((str = malloc(SBUFSIZE)) == NULL)
332 return NULL;
333 else
334 mystr = 1;
336 switch (type) {
338 case OCT:
339 /* first add \o */
340 sbuf[0] = '\\';
341 sbuf[1] = 'o';
343 return xfer(str, sbuf, o_atos(sbuf+2, addr->buf, addr->len) + 2,
344 mystr ? SBUFSIZE : 0);
346 case HEX:
347 /* first add \x */
348 sbuf[0] = '\\';
349 sbuf[1] = 'x';
351 return xfer(str, sbuf, x_atos(sbuf+2, addr->buf, addr->len) + 2,
352 mystr ? SBUFSIZE : 0);
354 case RAW:
355 base = xfer(str, addr->buf,
356 addr->len + 1, mystr ? SBUFSIZE : 0);
357 if (base)
358 base[addr->len] = '\0'; /* terminate*/
359 return base;
361 default:
362 return NULL;
368 x_atos, o_atos
369 return the number of bytes occupied by string + NULL*/
372 x_atos : convert an address string a, length s
373 to hex ASCII in s */
376 unsigned
377 x_atos(s, a, l)
378 char *s, *a;
379 unsigned l;
381 char *b;
383 b = s;
384 while (l--) {
385 *s++ = itoac(((*a >> 4) & MASK (4)));
386 *s++ = itoac((*a & MASK(4)));
387 ++a;
389 *s = '\0';
390 return (s - b + 1);
395 o_atos : convert an address a, length l
396 to octal ASCII in s */
399 unsigned
400 o_atos(s, a, l)
401 char *s, *a;
402 unsigned l;
404 int i, shift;
405 char *b;
407 b = s;
408 if (l == 0) {
409 *s = '\0';
410 return 0;
413 /* take care of partial bits and set shift factor for next 3 */
415 i = l % 3;
416 *s++ = itoac((*a>>(i+5)) & MASK(3-i));
417 shift = 2 + i;
419 while (l)
420 if (shift <= 5) {
421 *s++ = itoac((*a >> shift) & MASK(3));
422 if (shift == 0) {
423 ++a;
424 --l;
426 shift += (shift < 3) ? 5 : -3;
428 else {
429 i = (*a & MASK(shift-5)) << (8-shift);
430 i |= (*++a >> shift) & MASK(8-shift);
431 *s++ = itoac(i);
432 shift -= 3;
433 --l;
435 *s++ = '\0';
436 return (s - b + 1);
439 #endif /* NOTUSED */
441 void
442 memcp(d, s, n) /* safe memcpy for overlapping regions */
443 char *d, *s;
444 int n;
446 while (n--)
447 *d++ = *s++;
451 /* transfer block to a given destination or allocate one of the
452 right size
453 if max = 0 : ignore max
456 char *
457 xfer(dest, src, len, max)
458 char *dest, *src;
459 unsigned len, max;
461 if (max && dest && max < len) { /* No room */
462 fprintf(stderr, "xfer: destination not long enough\n");
463 return NULL;
465 if (!dest)
466 if ((dest = (char *)malloc(len)) == NULL) {
467 fprintf(stderr, "xfer: malloc failed\n");
468 return NULL;
471 memcpy(dest, src, (int)len);
472 return dest;
476 prescan: scan through string s, expanding all \$...\$
477 as shell escapes.
478 Return pointer to string of expanded text.
481 char *
482 prescan(s)
483 char *s;
485 int scan();
487 rec = sbp = 0;
488 if (!s || !*s || !scan(s))
489 return NULL;
490 scanbuf[sbp] = '\0';
491 return scanbuf;
496 scan: scan through string s, expanding all \$...\$.
497 (Part II of prescan)
498 Return 0 if anything failed, else 1.
502 scan(s)
503 char *s;
505 char *xcmd();
506 char *cmd;
507 int len;
508 int esc = 0; /* Keep lookout for \\$ */
510 while (*s) {
511 if (!esc && (*s == '\\' && *(s+1) == '$')) {
512 if (rec++ == MAXRLEVEL) {
513 fprintf(stderr, "scan: Recursion \
514 level past %d on shell escape\n", rec);
515 return 0;
517 if ((cmd = xcmd(s+2, '$', &s, &len)) != NULL) {
518 cmd[len] = '\0';
519 if (*cmd != '\0')
520 scan(cmd);
521 free(cmd);
523 else
524 return 0;
527 else if (sbp == SBUFSIZE) {
528 fprintf(stderr, "Overflow on shell esc expansion\n");
529 return 0;
531 else if (sbp < SBUFSIZE)
532 esc = ((scanbuf[sbp++] = *s++) == '\\');
534 return 1;
539 xcmd : extract command line for shell escape and execute it
540 return pointer to output of command
543 char *
544 xcmd(s, ec, ps, len)
545 char *s; /* input string */
546 char ec; /* escape char ( $ or ! ) */
547 char **ps; /* address of input string pointer */
548 int *len; /* Number of bytes of output from command */
550 FILE *popen();
551 int pclose();
553 FILE *pfp; /* pipe for process */
554 char *cmd; /* command buffer */
555 char *cmdp; /* pointer along cmd */
556 char *ocmd; /* output of command buffer */
557 int esc = 0; /* escaped escape shell */
559 *len = 0;
561 if ((cmd = cmdp = (char *)malloc(SBUFSIZE)) == NULL) {
562 fprintf(stderr, "xcmd: malloc failed\n");
563 return NULL;
566 if ((ocmd = (char *)malloc(SBUFSIZE)) == NULL) {
567 fprintf(stderr, "xcmd: malloc failed\n");
568 free(cmd);
569 return NULL;
571 while (*s) {
572 if (!esc && *s == '\\' && *(s+1) == ec) {
573 s += 2;
574 break;
576 else
577 esc = (*cmdp++ = *s++) == '\\';
579 *cmdp = '\0';
580 *ps = s;
582 if ((pfp = popen(cmd, "r")) == NULL)
583 fprintf(stderr, "xcmd: popen failed\n");
584 while (fread(&ocmd[*len], 1, 1, pfp))
585 if ((*len += 1) >= SBUFSIZE) {
586 fprintf(stderr, "xcmd: command output too long\n");
587 break;
589 pclose(pfp);
590 free(cmd);
592 return ocmd;