xref: /titanic_52/usr/src/cmd/mdb/common/mdb/mdb_string.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
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.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <netinet/in.h>
30 #include <limits.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 
34 #include <mdb/mdb_string.h>
35 #include <mdb/mdb_modapi.h>
36 #include <mdb/mdb_lex.h>
37 #include <mdb/mdb_debug.h>
38 #include <mdb/mdb.h>
39 
40 /*
41  * Convert the specified integer value to a string represented in the given
42  * base.  The flags parameter is a bitfield of the formatting flags defined in
43  * mdb_string.h.  A pointer to a static conversion buffer is returned.
44  */
45 const char *
46 numtostr(uintmax_t uvalue, int base, uint_t flags)
47 {
48 	static const char ldigits[] = "0123456789abcdef";
49 	static const char udigits[] = "0123456789ABCDEF";
50 
51 	static char buf[68]; /* Enough for ULLONG_MAX in binary plus prefixes */
52 
53 	const char *digits = (flags & NTOS_UPCASE) ? udigits : ldigits;
54 	int i = sizeof (buf);
55 
56 	intmax_t value = (intmax_t)uvalue;
57 	int neg = (flags & NTOS_UNSIGNED) == 0 && value < 0;
58 	uintmax_t rem = neg ? -value : value;
59 
60 	buf[--i] = 0;
61 
62 	do {
63 		buf[--i] = digits[rem % base];
64 		rem /= base;
65 	} while (rem != 0);
66 
67 	if (flags & NTOS_SHOWBASE) {
68 		uintmax_t lim;
69 		char c = 0;
70 
71 		switch (base) {
72 		case 2:
73 			lim = 1;
74 			c = 'i';
75 			break;
76 		case 8:
77 			lim = 7;
78 			c = 'o';
79 			break;
80 		case 10:
81 			lim = 9;
82 			c = 't';
83 			break;
84 		case 16:
85 			lim = 9;
86 			c = 'x';
87 			break;
88 		}
89 
90 		if (c != 0 && uvalue > lim) {
91 			buf[--i] = c;
92 			buf[--i] = '0';
93 		}
94 	}
95 
96 	if (neg)
97 		buf[--i] = '-';
98 	else if (flags & NTOS_SIGNPOS)
99 		buf[--i] = '+';
100 
101 	return ((const char *)(&buf[i]));
102 }
103 
104 #define	CTOI(x)	(((x) >= '0' && (x) <= '9') ? (x) - '0' : \
105 	((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A')
106 
107 /*
108  * Convert a string to an unsigned integer value using the specified base.
109  * In the event of overflow or an invalid character, we generate an
110  * error message and longjmp back to the main loop using yyerror().
111  */
112 uintmax_t
113 strtonum(const char *s, int base)
114 {
115 	uintmax_t multmax = (uintmax_t)ULLONG_MAX / (uintmax_t)(uint_t)base;
116 	uintmax_t val = 0;
117 	int c, i, neg = 0;
118 
119 	switch (c = *s) {
120 	case '-':
121 		neg++;
122 		/*FALLTHRU*/
123 	case '+':
124 		c = *++s;
125 	}
126 
127 	if (c == '\0')
128 		goto done;
129 
130 	if ((val = CTOI(c)) >= base)
131 		yyerror("digit '%c' is invalid in current base\n", c);
132 
133 	for (c = *++s; c != '\0'; c = *++s) {
134 		if (val > multmax)
135 			goto oflow;
136 
137 		if ((i = CTOI(c)) >= base)
138 			yyerror("digit '%c' is invalid in current base\n", c);
139 
140 		val *= base;
141 
142 		if ((uintmax_t)ULLONG_MAX - val < (uintmax_t)i)
143 			goto oflow;
144 
145 		val += i;
146 	}
147 done:
148 	return (neg ? -val : val);
149 oflow:
150 	yyerror("specified value exceeds maximum immediate value\n");
151 	return ((uintmax_t)ULLONG_MAX);
152 }
153 
154 /*
155  * Quick string to unsigned long conversion function.  This function performs
156  * no overflow checking and is only meant for internal mdb use.  It allows
157  * the caller to specify the length of the string in bytes and a base.
158  */
159 ulong_t
160 strntoul(const char *s, size_t nbytes, int base)
161 {
162 	ulong_t n;
163 	int c;
164 
165 	for (n = 0; nbytes != 0 && (c = *s) != '\0'; s++, nbytes--)
166 		n = n * base + CTOI(c);
167 
168 	return (n);
169 }
170 
171 /*
172  * Return a boolean value indicating whether or not a string consists
173  * solely of characters which are digits 0..9.
174  */
175 int
176 strisnum(const char *s)
177 {
178 	for (; *s != '\0'; s++) {
179 		if (*s < '0' || *s > '9')
180 			return (0);
181 	}
182 
183 	return (1);
184 }
185 
186 /*
187  * Return a boolean value indicating whether or not a string contains a
188  * number.  The number may be in the current radix, or it may have an
189  * explicit radix qualifier.  The number will be validated against the
190  * legal characters for the given radix.
191  */
192 int
193 strisbasenum(const char *s)
194 {
195 	char valid[] = "0123456789aAbBcCdDeEfF";
196 	int radix = mdb.m_radix;
197 
198 	if (s[0] == '0') {
199 		switch (s[1]) {
200 		case 'I':
201 		case 'i':
202 			radix = 2;
203 			s += 2;
204 			break;
205 		case 'O':
206 		case 'o':
207 			radix = 8;
208 			s += 2;
209 			break;
210 		case 'T':
211 		case 't':
212 			radix = 10;
213 			s += 2;
214 			break;
215 		case 'x':
216 		case 'X':
217 			radix = 16;
218 			s += 2;
219 			break;
220 		}
221 	}
222 
223 	/* limit `valid' to the digits valid for this base */
224 	valid[radix > 10 ? 10 + (radix - 10) * 2 : radix] = '\0';
225 
226 	do {
227 		if (!strchr(valid, *s))
228 			return (0);
229 	} while (*++s != '\0');
230 
231 	return (1);
232 }
233 
234 /*
235  * Quick string to integer (base 10) conversion function.  This performs
236  * no overflow checking and is only meant for internal mdb use.
237  */
238 int
239 strtoi(const char *s)
240 {
241 	int c, n;
242 
243 	for (n = 0; (c = *s) >= '0' && c <= '9'; s++)
244 		n = n * 10 + c - '0';
245 
246 	return (n);
247 }
248 
249 /*
250  * Create a copy of string s using the mdb allocator interface.
251  */
252 char *
253 strdup(const char *s)
254 {
255 	char *s1 = mdb_alloc(strlen(s) + 1, UM_SLEEP);
256 
257 	(void) strcpy(s1, s);
258 	return (s1);
259 }
260 
261 /*
262  * Create a copy of string s, but only duplicate the first n bytes.
263  */
264 char *
265 strndup(const char *s, size_t n)
266 {
267 	char *s2 = mdb_alloc(n + 1, UM_SLEEP);
268 
269 	(void) strncpy(s2, s, n);
270 	s2[n] = '\0';
271 	return (s2);
272 }
273 
274 /*
275  * Convenience routine for freeing strings.
276  */
277 void
278 strfree(char *s)
279 {
280 	mdb_free(s, strlen(s) + 1);
281 }
282 
283 /*
284  * Transform string s inline, converting each embedded C escape sequence string
285  * to the corresponding character.  For example, the substring "\n" is replaced
286  * by an inline '\n' character.  The length of the resulting string is returned.
287  */
288 size_t
289 stresc2chr(char *s)
290 {
291 	char *p, *q, c;
292 	int esc = 0;
293 
294 	for (p = q = s; (c = *p) != '\0'; p++) {
295 		if (esc) {
296 			switch (c) {
297 				case '0':
298 				case '1':
299 				case '2':
300 				case '3':
301 				case '4':
302 				case '5':
303 				case '6':
304 				case '7':
305 					c -= '0';
306 					p++;
307 
308 					if (*p >= '0' && *p <= '7') {
309 						c = c * 8 + *p++ - '0';
310 
311 						if (*p >= '0' && *p <= '7')
312 							c = c * 8 + *p - '0';
313 						else
314 							p--;
315 					} else
316 						p--;
317 
318 					*q++ = c;
319 					break;
320 
321 				case 'a':
322 					*q++ = '\a';
323 					break;
324 				case 'b':
325 					*q++ = '\b';
326 					break;
327 				case 'f':
328 					*q++ = '\f';
329 					break;
330 				case 'n':
331 					*q++ = '\n';
332 					break;
333 				case 'r':
334 					*q++ = '\r';
335 					break;
336 				case 't':
337 					*q++ = '\t';
338 					break;
339 				case 'v':
340 					*q++ = '\v';
341 					break;
342 				case '"':
343 				case '\\':
344 					*q++ = c;
345 					break;
346 				default:
347 					*q++ = '\\';
348 					*q++ = c;
349 			}
350 
351 			esc = 0;
352 
353 		} else {
354 			if ((esc = c == '\\') == 0)
355 				*q++ = c;
356 		}
357 	}
358 
359 	*q = '\0';
360 	return ((size_t)(q - s));
361 }
362 
363 /*
364  * Create a copy of string s in which certain unprintable or special characters
365  * have been converted to the string representation of their C escape sequence.
366  * For example, the newline character is expanded to the string "\n".
367  */
368 char *
369 strchr2esc(const char *s, size_t n)
370 {
371 	const char *p;
372 	char *q, *s2, c;
373 	size_t addl = 0;
374 
375 	for (p = s; p < s + n; p++) {
376 		switch (c = *p) {
377 		case '\0':
378 		case '\a':
379 		case '\b':
380 		case '\f':
381 		case '\n':
382 		case '\r':
383 		case '\t':
384 		case '\v':
385 		case '"':
386 		case '\\':
387 			addl++;		/* 1 add'l char needed to follow \ */
388 			break;
389 		case ' ':
390 			break;
391 		default:
392 			if (c < '!' || c > '~')
393 				addl += 3; /* 3 add'l chars following \ */
394 		}
395 	}
396 
397 	s2 = mdb_alloc(n + addl + 1, UM_SLEEP);
398 
399 	for (p = s, q = s2; p < s + n; p++) {
400 		switch (c = *p) {
401 		case '\0':
402 			*q++ = '\\';
403 			*q++ = '0';
404 			break;
405 		case '\a':
406 			*q++ = '\\';
407 			*q++ = 'a';
408 			break;
409 		case '\b':
410 			*q++ = '\\';
411 			*q++ = 'b';
412 			break;
413 		case '\f':
414 			*q++ = '\\';
415 			*q++ = 'f';
416 			break;
417 		case '\n':
418 			*q++ = '\\';
419 			*q++ = 'n';
420 			break;
421 		case '\r':
422 			*q++ = '\\';
423 			*q++ = 'r';
424 			break;
425 		case '\t':
426 			*q++ = '\\';
427 			*q++ = 't';
428 			break;
429 		case '\v':
430 			*q++ = '\\';
431 			*q++ = 'v';
432 			break;
433 		case '"':
434 			*q++ = '\\';
435 			*q++ = '"';
436 			break;
437 		case '\\':
438 			*q++ = '\\';
439 			*q++ = '\\';
440 			break;
441 		case ' ':
442 			*q++ = c;
443 			break;
444 		default:
445 			if (c < '!' || c > '~') {
446 				*q++ = '\\';
447 				*q++ = ((c >> 6) & 3) + '0';
448 				*q++ = ((c >> 3) & 7) + '0';
449 				*q++ = (c & 7) + '0';
450 			} else
451 				*q++ = c;
452 		}
453 	}
454 
455 	*q = '\0';
456 	return (s2);
457 }
458 
459 /*
460  * Create a copy of string s in which certain unprintable or special characters
461  * have been converted to an odd representation of their escape sequence.
462  * This algorithm is the old adb convention for representing such sequences.
463  */
464 char *
465 strchr2adb(const char *s, size_t n)
466 {
467 	size_t addl = 0;
468 	const char *p;
469 	char *q, *s2;
470 
471 	for (p = s; p < s + n; p++) {
472 		char c = *p & CHAR_MAX;
473 
474 		if (c < ' ' || c == CHAR_MAX)
475 			addl++; /* 1 add'l char needed for "^" */
476 	}
477 
478 	s2 = mdb_alloc(n + addl + 1, UM_SLEEP);
479 
480 	for (p = s, q = s2; p < s + n; p++) {
481 		char c = *p & CHAR_MAX;
482 
483 		if (c == CHAR_MAX) {
484 			*q++ = '^';
485 			*q++ = '?';
486 		} else if (c < ' ') {
487 			*q++ = '^';
488 			*q++ = c + '@';
489 		} else
490 			*q++ = c;
491 	}
492 
493 	*q = '\0';
494 	return (s2);
495 }
496 
497 /*
498  * Same as strchr, but we only search the first n characters
499  */
500 char *
501 strnchr(const char *s, int c, size_t n)
502 {
503 	int i = 0;
504 
505 	for (i = 0; i < n; i++) {
506 		if (*(s + i) == (char)c)
507 			return ((char *)(s + i));
508 	}
509 
510 	return (NULL);
511 }
512 
513 /*
514  * Split the string s at the first occurrence of character c.  This character
515  * is replaced by \0, and a pointer to the remainder of the string is returned.
516  */
517 char *
518 strsplit(char *s, char c)
519 {
520 	char *p;
521 
522 	if ((p = strchr(s, c)) == NULL)
523 		return (NULL);
524 
525 	*p++ = '\0';
526 	return (p);
527 }
528 
529 /*
530  * Same as strsplit, but split from the last occurrence of character c.
531  */
532 char *
533 strrsplit(char *s, char c)
534 {
535 	char *p;
536 
537 	if ((p = strrchr(s, c)) == NULL)
538 		return (NULL);
539 
540 	*p++ = '\0';
541 	return (p);
542 }
543 
544 /*
545  * Return the address of the first occurrence of any character from s2
546  * in the string s1, or NULL if none exists.  This is similar to libc's
547  * strpbrk, but we add a third parameter to limit the search to the
548  * specified number of bytes in s1, or a \0 character, whichever is
549  * encountered first.
550  */
551 const char *
552 strnpbrk(const char *s1, const char *s2, size_t nbytes)
553 {
554 	const char *p;
555 
556 	if (nbytes == 0)
557 		return (NULL);
558 
559 	do {
560 		for (p = s2; *p != '\0' && *p != *s1; p++)
561 			continue;
562 
563 		if (*p != '\0')
564 			return (s1);
565 
566 	} while (--nbytes != 0 && *s1++ != '\0');
567 
568 	return (NULL);
569 }
570 
571 /*
572  * Abbreviate a string if it meets or exceeds the specified length, including
573  * the terminating null character.  The string is abbreviated by replacing the
574  * last four characters with " ...".  strabbr is useful in constructs such as
575  * this one, where nbytes = sizeof (buf):
576  *
577  * if (mdb_snprintf(buf, nbytes, "%s %d %c", ...) >= nbytes)
578  *         (void) strabbr(buf, nbytes);
579  *
580  * No modifications are made if nbytes is too small to hold the suffix itself.
581  */
582 char *
583 strabbr(char *s, size_t nbytes)
584 {
585 	static const char suffix[] = " ...";
586 
587 	if (nbytes > sizeof (suffix) && strlen(s) >= nbytes - 1)
588 		(void) strcpy(&s[nbytes - sizeof (suffix)], suffix);
589 
590 	return (s);
591 }
592 
593 /*
594  * Return the basename (name after final /) of the given string.  We use
595  * strbasename rather than basename to avoid conflicting with libgen.h's
596  * non-const function prototype.
597  */
598 const char *
599 strbasename(const char *s)
600 {
601 	const char *p = strrchr(s, '/');
602 
603 	if (p == NULL)
604 		return (s);
605 
606 	return (++p);
607 }
608 
609 /*
610  * Return the directory name (name prior to the final /) of the given string.
611  * The string itself is modified.
612  */
613 char *
614 strdirname(char *s)
615 {
616 	static char slash[] = "/";
617 	static char dot[] = ".";
618 	char *p;
619 
620 	if (s == NULL || *s == '\0')
621 		return (dot);
622 
623 	for (p = s + strlen(s); p != s && *--p == '/'; )
624 		continue;
625 
626 	if (p == s && *p == '/')
627 		return (slash);
628 
629 	while (p != s) {
630 		if (*--p == '/') {
631 			while (*p == '/' && p != s)
632 				p--;
633 			*++p = '\0';
634 			return (s);
635 		}
636 	}
637 
638 	return (dot);
639 }
640 
641 /*
642  * Return a pointer to the first character in the string that makes it an
643  * invalid identifer (i.e. incompatible with the mdb syntax), or NULL if
644  * the string is a valid identifier.
645  */
646 const char *
647 strbadid(const char *s)
648 {
649 	return (strpbrk(s, "#%^&*-+=,:$/\\?<>;|!`'\"[]\n\t() {}"));
650 }
651 
652 /*
653  * Return a boolean value indicating if the given string consists solely
654  * of printable ASCII characters terminated by \0.
655  */
656 int
657 strisprint(const char *s)
658 {
659 	for (; *s != '\0'; s++) {
660 		if (*s < ' ' || *s > '~')
661 			return (0);
662 	}
663 
664 	return (1);
665 }
666 
667 /*
668  * This is a near direct copy of the inet_ntop() code in
669  * uts/common/inet/ip/ipv6.c, duplicated here for kmdb's sake.
670  */
671 static void
672 convert2ascii(char *buf, const in6_addr_t *addr)
673 {
674 	int		hexdigits;
675 	int		head_zero = 0;
676 	int		tail_zero = 0;
677 	/* tempbuf must be big enough to hold ffff:\0 */
678 	char		tempbuf[6];
679 	char		*ptr;
680 	uint16_t	*addr_component, host_component;
681 	size_t		len;
682 	int		first = FALSE;
683 	int		med_zero = FALSE;
684 	int		end_zero = FALSE;
685 
686 	addr_component = (uint16_t *)addr;
687 	ptr = buf;
688 
689 	/* First count if trailing zeroes higher in number */
690 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
691 		if (*addr_component == 0) {
692 			if (hexdigits < 4)
693 				head_zero++;
694 			else
695 				tail_zero++;
696 		}
697 		addr_component++;
698 	}
699 	addr_component = (uint16_t *)addr;
700 	if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
701 		end_zero = TRUE;
702 
703 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
704 		/* if entry is a 0 */
705 		if (*addr_component == 0) {
706 			if (!first && *(addr_component + 1) == 0) {
707 				if (end_zero && (hexdigits < 4)) {
708 					*ptr++ = '0';
709 					*ptr++ = ':';
710 				} else {
711 					if (hexdigits == 0)
712 						*ptr++ = ':';
713 					/* add another */
714 					*ptr++ = ':';
715 					first = TRUE;
716 					med_zero = TRUE;
717 				}
718 			} else if (first && med_zero) {
719 				if (hexdigits == 7)
720 					*ptr++ = ':';
721 				addr_component++;
722 				continue;
723 			} else {
724 				*ptr++ = '0';
725 				*ptr++ = ':';
726 			}
727 			addr_component++;
728 			continue;
729 		}
730 		if (med_zero)
731 			med_zero = FALSE;
732 
733 		tempbuf[0] = '\0';
734 		mdb_nhconvert(&host_component, addr_component,
735 		    sizeof (uint16_t));
736 		(void) mdb_snprintf(tempbuf, sizeof (tempbuf), "%x:",
737 		    host_component & 0xffff);
738 		len = strlen(tempbuf);
739 		bcopy(tempbuf, ptr, len);
740 		ptr = ptr + len;
741 		addr_component++;
742 	}
743 	*--ptr = '\0';
744 }
745 
746 char *
747 mdb_inet_ntop(int af, const void *addr, char *buf, size_t buflen)
748 {
749 	in6_addr_t	*v6addr;
750 	uchar_t		*v4addr;
751 	char		*caddr;
752 
753 #define	UC(b)	(((int)b) & 0xff)
754 	switch (af) {
755 	case AF_INET:
756 		ASSERT(buflen >= INET_ADDRSTRLEN);
757 		v4addr = (uchar_t *)addr;
758 		(void) mdb_snprintf(buf, buflen, "%d.%d.%d.%d",
759 		    UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
760 		return (buf);
761 
762 	case AF_INET6:
763 		ASSERT(buflen >= INET6_ADDRSTRLEN);
764 		v6addr = (in6_addr_t *)addr;
765 		if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
766 			caddr = (char *)addr;
767 			(void) mdb_snprintf(buf, buflen, "::ffff:%d.%d.%d.%d",
768 			    UC(caddr[12]), UC(caddr[13]),
769 			    UC(caddr[14]), UC(caddr[15]));
770 		} else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
771 			caddr = (char *)addr;
772 			(void) mdb_snprintf(buf, buflen, "::%d.%d.%d.%d",
773 			    UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
774 			    UC(caddr[15]));
775 		} else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
776 			(void) mdb_snprintf(buf, buflen, "::");
777 		} else {
778 			convert2ascii(buf, v6addr);
779 		}
780 		return (buf);
781 	}
782 #undef UC
783 
784 	return (NULL);
785 }
786