Merge commit 'a058d1cc571af5fbcfe7f1d719df1abbfdb722f3' into merges
[unleashed.git] / usr / src / cmd / listen / nstoa.c
blob39a031d49a43e1cf735987d5ee4c11de742de28b
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 #pragma ident "%Z%%M% %I% %E% SMI"
35 stoa - convert string to address
37 If a string begins in \o or \O, the following address is octal
38 " " " " " \x or \X, the following address is hex
39 Otherwise, a string is considered text. Text may be quoted
40 with double quotes and the C-like escapes \n, \b, \t, \v, \r, and \nnn
41 (nnn = octal char) are recognized.
42 A \ followed by a newline causes the newline
43 to vanish. A \ followed by any other char causes any "magic" of
44 any other char to disappear.
46 Other escape sequences recognized are:
47 \!cmd args [ \! || EOL ]
48 which is replaced by the raw output of the execution of cmd.
49 This may only be used in a string.
51 \$cmd args [ \$ || EOL ]
52 which is replaced by the output of the execution of cmd and
53 is then reprocessed.
55 A NULL is returned on any error(s).
58 #include <stdio.h>
59 #include <memory.h>
60 #include <ctype.h>
61 #include "nsaddr.h"
64 #define toupper(c) (islower(c) ? _toupper(c) : (c))
65 #define todigit(c) ((int)((c) - '0')) /* char to digit */
66 #define toxdigit(c) ((isdigit(c))?todigit(c):(toupper(c)-(int)'A'+10))
67 #define isodigit(c) (isdigit(c) && ((c) != '9') && ((c) != '8'))
68 #define itoac(i) (((i) > 9) ? ((char)((i)-10) + 'A'):((char)(i) + '0'))
69 #define MASK(n) ((1 << (n)) - 1)
71 #define MAXRLEVEL 10 /* maximum recursion level */
73 #define TRUE 1;
74 #define FALSE 0;
76 char scanbuf[SBUFSIZE];
77 int sbp = 0;
78 int rec = 0; /* Recursion level */
80 char sbuf[SBUFSIZE];
82 extern void free();
84 struct netbuf *
85 stoa(str, addr) /* Return 0 for success, -1 for error */
86 char *str;
87 struct netbuf *addr;
89 char *xfer(), *prescan();
91 int myadr; /* was netbuf struct allocated here ? */
92 int quote; /* quoted string ? */
94 myadr = FALSE;
96 if (!str)
97 return NULL;
98 while (*str && isspace(*str)) /* leading whites are OK */
99 ++str;
101 str = prescan(str); /* Do all \$ ... \$ */
103 if (!str || !*str) return NULL; /* Nothing to convert */
105 if (!addr) {
106 if ((addr = (struct netbuf *)malloc(sizeof(struct netbuf))) == NULL)
107 return NULL;
108 myadr = TRUE;
109 addr->buf = NULL;
110 addr->maxlen = 0;
111 addr->len = 0;
114 /* Now process the address */
115 quote = 0;
117 if (*str == '\\') {
118 ++str;
119 switch (*str) {
121 case 'X': /* hex */
122 case 'x':
123 addr->len = dobase(++str, sbuf, HEX);
124 break;
126 case 'o': /* octal */
127 case 'O':
128 addr->len = dobase(++str, sbuf, OCT);
129 break;
131 case '\0': /* No address given!, length is 0 */
132 addr->len = dostring(str, sbuf, 0);
133 break;
135 default: /* \ is handled by dostring */
136 addr->len = dostring(--str, sbuf, quote);
137 break;
140 else {
141 if (*str == '"') { /* quoted string */
142 quote = 1;
143 ++str;
145 addr->len = dostring(str, sbuf, quote);
148 if (addr->len == 0) { /* Error in conversion */
149 if (myadr)
150 free(addr);
151 return NULL;
153 if ((addr->buf = xfer(addr->buf, sbuf, addr->len, addr->maxlen)) == NULL)
154 return NULL;
155 else
156 return addr;
161 dostring: Copy string at s to buf translating
162 escaped characters and shell escapes.
163 return length of string.
167 dostring(s, buf, quote) /* read in a raw address */
168 char *s, *buf;
169 int quote;
171 char *xcmd();
173 int oc, ch, len = 0;
174 int l = 0;
175 char *rout;
177 while (*s) {
178 if (len >= SBUFSIZE) {
179 fprintf(stderr, "dostring: string too long\n");
180 break;
182 else if (*s == '\\')
183 switch(*++s) {
185 case '!': /* raw shell escape */
186 if (rout = xcmd(s+1, '!', &s, &l)) {
187 if (len + l < SBUFSIZE)
188 memcpy(buf+len, rout, l);
189 len += l;
190 free(rout);
192 break;
194 case '\n': /* ignore newline */
195 ++s;
196 break;
198 case 'b': /* backspace */
199 buf[len++] = '\b'; s++;
200 break;
202 case 'n': /* newline */
203 buf[len++] = '\n'; s++;
204 break;
206 case 'r': /* return */
207 buf[len++] = '\r'; s++;
208 break;
210 case 't': /* horiz. tab */
211 buf[len++] = '\t'; s++;
212 break;
214 case 'v': /* vert. tab */
215 buf[len++] = '\v'; s++;
217 case '0':
218 case '1':
219 case '2':
220 case '3':
221 for(oc=ch=0; (*s >= '0' && *s <= '7') && oc++ < 3; ++s)
222 ch = (ch << 3) | (*s - '0');
223 buf[len++] = ch;
224 break;
226 case 0: /* end of string -- terminate */
227 break;
229 default: /* take the character blindly */
230 buf[len++] = *s++;
231 break;
233 else if ((quote && (*s == '"')) || (!quote && isspace(*s)))
234 break;
236 else
237 buf[len++] = *s++;
239 return (len >= SBUFSIZE) ? 0 : len;
244 dobase : converts a hex or octal ASCII string
245 to a binary address. Only HEX or OCT may be used
246 for type.
247 return length of binary string (in bytes), 0 if error.
248 The binary result is placed at buf.
252 dobase(s, buf, type) /* read in an address */
253 char *s, *buf; /* source ASCII, result binary string */
254 int type;
256 void memcp();
257 int bp = SBUFSIZE - 1;
258 int shift = 0;
259 char *end;
261 for (end = s; *end && ((type == OCT) ? isodigit(*end) :
262 isxdigit(*end)); ++end) ;
264 /* any non-white, non-digits cause address to be rejected,
265 other fields are ignored */
267 if ((*s == 0) || (end == s) || (!isspace(*end) && *end)) {
268 fprintf(stderr, "dobase: Illegal trailer on address string\n");
269 buf[0] = '\0';
270 return 0;
272 --end;
274 buf[bp] = '\0';
276 while (bp > 0 && end >= s) {
277 buf[bp] |= toxdigit(*end) << shift;
278 if (type == OCT) {
279 if (shift > 5) {
280 buf[--bp] = (todigit(*end) >> (8 - shift))
281 & MASK(shift-5);
283 if ((shift = (shift + 3) % 8) == 0)
284 buf[--bp] = 0;
286 else /* hex */
287 if ((shift = (shift) ? 0 : 4) == 0)
288 buf[--bp] = 0;;
289 --end;
291 if (bp == 0) {
292 fprintf(stderr, "stoa: dobase: number to long\n");
293 return 0;
296 /* need to catch end case to avoid extra 0's in front */
297 if (!shift)
298 bp++;
299 memcp(buf, &buf[bp], (SBUFSIZE - bp));
300 return (SBUFSIZE - bp);
303 #ifdef NOTUSED
308 atos(str, addr, type)
310 convert address to ASCII form with address in hex, octal,
311 or character form.
312 return pointer to buffer (NULL on failure).
316 char *
317 atos(str, addr, type)
318 char *str;
319 struct netbuf *addr;
320 int type;
322 char *xfer();
323 int mystr = 0; /* was str allocated here ? */
324 unsigned x_atos(), o_atos();
325 void memcp();
327 char *base;
329 if (addr == NULL)
330 return NULL;
332 if (str == NULL)
333 if ((str = malloc(SBUFSIZE)) == NULL)
334 return NULL;
335 else
336 mystr = 1;
338 switch (type) {
340 case OCT:
341 /* first add \o */
342 sbuf[0] = '\\';
343 sbuf[1] = 'o';
345 return xfer(str, sbuf, o_atos(sbuf+2, addr->buf, addr->len) + 2,
346 mystr ? SBUFSIZE : 0);
348 case HEX:
349 /* first add \x */
350 sbuf[0] = '\\';
351 sbuf[1] = 'x';
353 return xfer(str, sbuf, x_atos(sbuf+2, addr->buf, addr->len) + 2,
354 mystr ? SBUFSIZE : 0);
356 case RAW:
357 base = xfer(str, addr->buf,
358 addr->len + 1, mystr ? SBUFSIZE : 0);
359 if (base)
360 base[addr->len] = '\0'; /* terminate*/
361 return base;
363 default:
364 return NULL;
370 x_atos, o_atos
371 return the number of bytes occupied by string + NULL*/
374 x_atos : convert an address string a, length s
375 to hex ASCII in s */
378 unsigned
379 x_atos(s, a, l)
380 char *s, *a;
381 unsigned l;
383 char *b;
385 b = s;
386 while (l--) {
387 *s++ = itoac(((*a >> 4) & MASK (4)));
388 *s++ = itoac((*a & MASK(4)));
389 ++a;
391 *s = '\0';
392 return (s - b + 1);
397 o_atos : convert an address a, length l
398 to octal ASCII in s */
401 unsigned
402 o_atos(s, a, l)
403 char *s, *a;
404 unsigned l;
406 int i, shift;
407 char *b;
409 b = s;
410 if (l == 0) {
411 *s = '\0';
412 return 0;
415 /* take care of partial bits and set shift factor for next 3 */
417 i = l % 3;
418 *s++ = itoac((*a>>(i+5)) & MASK(3-i));
419 shift = 2 + i;
421 while (l)
422 if (shift <= 5) {
423 *s++ = itoac((*a >> shift) & MASK(3));
424 if (shift == 0) {
425 ++a;
426 --l;
428 shift += (shift < 3) ? 5 : -3;
430 else {
431 i = (*a & MASK(shift-5)) << (8-shift);
432 i |= (*++a >> shift) & MASK(8-shift);
433 *s++ = itoac(i);
434 shift -= 3;
435 --l;
437 *s++ = '\0';
438 return (s - b + 1);
441 #endif /* NOTUSED */
443 void
444 memcp(d, s, n) /* safe memcpy for overlapping regions */
445 char *d, *s;
446 int n;
448 while (n--)
449 *d++ = *s++;
453 /* transfer block to a given destination or allocate one of the
454 right size
455 if max = 0 : ignore max
458 char *
459 xfer(dest, src, len, max)
460 char *dest, *src;
461 unsigned len, max;
463 if (max && dest && max < len) { /* No room */
464 fprintf(stderr, "xfer: destination not long enough\n");
465 return NULL;
467 if (!dest)
468 if ((dest = (char *)malloc(len)) == NULL) {
469 fprintf(stderr, "xfer: malloc failed\n");
470 return NULL;
473 memcpy(dest, src, (int)len);
474 return dest;
478 prescan: scan through string s, expanding all \$...\$
479 as shell escapes.
480 Return pointer to string of expanded text.
483 char *
484 prescan(s)
485 char *s;
487 int scan();
489 rec = sbp = 0;
490 if (!s || !*s || !scan(s))
491 return NULL;
492 scanbuf[sbp] = '\0';
493 return scanbuf;
498 scan: scan through string s, expanding all \$...\$.
499 (Part II of prescan)
500 Return 0 if anything failed, else 1.
504 scan(s)
505 char *s;
507 char *xcmd();
508 char *cmd;
509 int len;
510 int esc = 0; /* Keep lookout for \\$ */
512 while (*s) {
513 if (!esc && (*s == '\\' && *(s+1) == '$')) {
514 if (rec++ == MAXRLEVEL) {
515 fprintf(stderr, "scan: Recursion \
516 level past %d on shell escape\n", rec);
517 return 0;
519 if ((cmd = xcmd(s+2, '$', &s, &len)) != NULL) {
520 cmd[len] = '\0';
521 if (*cmd != '\0')
522 scan(cmd);
523 free(cmd);
525 else
526 return 0;
529 else if (sbp == SBUFSIZE) {
530 fprintf(stderr, "Overflow on shell esc expansion\n");
531 return 0;
533 else if (sbp < SBUFSIZE)
534 esc = ((scanbuf[sbp++] = *s++) == '\\');
536 return 1;
541 xcmd : extract command line for shell escape and execute it
542 return pointer to output of command
545 char *
546 xcmd(s, ec, ps, len)
547 char *s; /* input string */
548 char ec; /* escape char ( $ or ! ) */
549 char **ps; /* address of input string pointer */
550 int *len; /* Number of bytes of output from command */
552 FILE *popen();
553 int pclose();
555 FILE *pfp; /* pipe for process */
556 char *cmd; /* command buffer */
557 char *cmdp; /* pointer along cmd */
558 char *ocmd; /* output of command buffer */
559 int esc = 0; /* escaped escape shell */
561 *len = 0;
563 if ((cmd = cmdp = (char *)malloc(SBUFSIZE)) == NULL) {
564 fprintf(stderr, "xcmd: malloc failed\n");
565 return NULL;
568 if ((ocmd = (char *)malloc(SBUFSIZE)) == NULL) {
569 fprintf(stderr, "xcmd: malloc failed\n");
570 free(cmd);
571 return NULL;
573 while (*s) {
574 if (!esc && *s == '\\' && *(s+1) == ec) {
575 s += 2;
576 break;
578 else
579 esc = (*cmdp++ = *s++) == '\\';
581 *cmdp = '\0';
582 *ps = s;
584 if ((pfp = popen(cmd, "r")) == NULL)
585 fprintf(stderr, "xcmd: popen failed\n");
586 while (fread(&ocmd[*len], 1, 1, pfp))
587 if ((*len += 1) >= SBUFSIZE) {
588 fprintf(stderr, "xcmd: command output too long\n");
589 break;
591 pclose(pfp);
592 free(cmd);
594 return ocmd;