xref: /illumos-gate/usr/src/tools/smatch/src/char.c (revision c85f09cc)
11f5207b7SJohn Levon #include <string.h>
21f5207b7SJohn Levon #include "target.h"
31f5207b7SJohn Levon #include "lib.h"
41f5207b7SJohn Levon #include "allocate.h"
51f5207b7SJohn Levon #include "token.h"
61f5207b7SJohn Levon #include "expression.h"
71f5207b7SJohn Levon #include "char.h"
81f5207b7SJohn Levon 
parse_escape(const char * p,unsigned * val,const char * end,int bits,struct position pos)91f5207b7SJohn Levon static const char *parse_escape(const char *p, unsigned *val, const char *end, int bits, struct position pos)
101f5207b7SJohn Levon {
111f5207b7SJohn Levon 	unsigned c = *p++;
121f5207b7SJohn Levon 	unsigned d;
131f5207b7SJohn Levon 	if (c != '\\') {
141f5207b7SJohn Levon 		*val = c;
151f5207b7SJohn Levon 		return p;
161f5207b7SJohn Levon 	}
171f5207b7SJohn Levon 
181f5207b7SJohn Levon 	c = *p++;
191f5207b7SJohn Levon 	switch (c) {
201f5207b7SJohn Levon 	case 'a': c = '\a'; break;
211f5207b7SJohn Levon 	case 'b': c = '\b'; break;
221f5207b7SJohn Levon 	case 't': c = '\t'; break;
231f5207b7SJohn Levon 	case 'n': c = '\n'; break;
241f5207b7SJohn Levon 	case 'v': c = '\v'; break;
251f5207b7SJohn Levon 	case 'f': c = '\f'; break;
261f5207b7SJohn Levon 	case 'r': c = '\r'; break;
271f5207b7SJohn Levon 	case 'e': c = '\e'; break;
281f5207b7SJohn Levon 	case 'x': {
291f5207b7SJohn Levon 		unsigned mask = -(1U << (bits - 4));
301f5207b7SJohn Levon 		for (c = 0; p < end; c = (c << 4) + d) {
311f5207b7SJohn Levon 			d = hexval(*p);
321f5207b7SJohn Levon 			if (d > 16)
331f5207b7SJohn Levon 				break;
341f5207b7SJohn Levon 			p++;
351f5207b7SJohn Levon 			if (c & mask) {
361f5207b7SJohn Levon 				warning(pos,
371f5207b7SJohn Levon 					"hex escape sequence out of range");
381f5207b7SJohn Levon 				mask = 0;
391f5207b7SJohn Levon 			}
401f5207b7SJohn Levon 		}
411f5207b7SJohn Levon 		break;
421f5207b7SJohn Levon 	}
431f5207b7SJohn Levon 	case '0'...'7': {
441f5207b7SJohn Levon 		if (p + 2 < end)
451f5207b7SJohn Levon 			end = p + 2;
461f5207b7SJohn Levon 		c -= '0';
471f5207b7SJohn Levon 		while (p < end && (d = *p - '0') < 8) {
481f5207b7SJohn Levon 			c = (c << 3) + d;
491f5207b7SJohn Levon 			p++;
501f5207b7SJohn Levon 		}
511f5207b7SJohn Levon 		if ((c & 0400) && bits < 9)
521f5207b7SJohn Levon 			warning(pos,
531f5207b7SJohn Levon 				"octal escape sequence out of range");
541f5207b7SJohn Levon 		break;
551f5207b7SJohn Levon 	}
561f5207b7SJohn Levon 	default:	/* everything else is left as is */
571f5207b7SJohn Levon 		warning(pos, "unknown escape sequence: '\\%c'", c);
581f5207b7SJohn Levon 		break;
591f5207b7SJohn Levon 	case '\\':
601f5207b7SJohn Levon 	case '\'':
611f5207b7SJohn Levon 	case '"':
621f5207b7SJohn Levon 	case '?':
631f5207b7SJohn Levon 		break;	/* those are legal, so no warnings */
641f5207b7SJohn Levon 	}
651f5207b7SJohn Levon 	*val = c & ~((~0U << (bits - 1)) << 1);
661f5207b7SJohn Levon 	return p;
671f5207b7SJohn Levon }
681f5207b7SJohn Levon 
get_char_constant(struct token * token,unsigned long long * val)691f5207b7SJohn Levon void get_char_constant(struct token *token, unsigned long long *val)
701f5207b7SJohn Levon {
711f5207b7SJohn Levon 	const char *p = token->embedded, *end;
721f5207b7SJohn Levon 	unsigned v;
731f5207b7SJohn Levon 	int type = token_type(token);
741f5207b7SJohn Levon 	switch (type) {
751f5207b7SJohn Levon 	case TOKEN_CHAR:
761f5207b7SJohn Levon 	case TOKEN_WIDE_CHAR:
771f5207b7SJohn Levon 		p = token->string->data;
781f5207b7SJohn Levon 		end = p + token->string->length - 1;
791f5207b7SJohn Levon 		break;
801f5207b7SJohn Levon 	case TOKEN_CHAR_EMBEDDED_0 ... TOKEN_CHAR_EMBEDDED_3:
811f5207b7SJohn Levon 		end = p + type - TOKEN_CHAR;
821f5207b7SJohn Levon 		break;
831f5207b7SJohn Levon 	default:
841f5207b7SJohn Levon 		end = p + type - TOKEN_WIDE_CHAR;
851f5207b7SJohn Levon 	}
861f5207b7SJohn Levon 	p = parse_escape(p, &v, end,
87*c85f09ccSJohn Levon 			type < TOKEN_WIDE_CHAR ? bits_in_char : wchar_ctype->bit_size, token->pos);
881f5207b7SJohn Levon 	if (p != end)
891f5207b7SJohn Levon 		warning(token->pos,
901f5207b7SJohn Levon 			"multi-character character constant");
911f5207b7SJohn Levon 	*val = v;
921f5207b7SJohn Levon }
931f5207b7SJohn Levon 
get_string_constant(struct token * token,struct expression * expr)941f5207b7SJohn Levon struct token *get_string_constant(struct token *token, struct expression *expr)
951f5207b7SJohn Levon {
961f5207b7SJohn Levon 	struct string *string = token->string;
971f5207b7SJohn Levon 	struct token *next = token->next, *done = NULL;
981f5207b7SJohn Levon 	int stringtype = token_type(token);
991f5207b7SJohn Levon 	int is_wide = stringtype == TOKEN_WIDE_STRING;
1001f5207b7SJohn Levon 	static char buffer[MAX_STRING];
1011f5207b7SJohn Levon 	int len = 0;
1021f5207b7SJohn Levon 	int bits;
1031f5207b7SJohn Levon 	int esc_count = 0;
1041f5207b7SJohn Levon 
1051f5207b7SJohn Levon 	while (!done) {
1061f5207b7SJohn Levon 		switch (token_type(next)) {
1071f5207b7SJohn Levon 		case TOKEN_WIDE_STRING:
1081f5207b7SJohn Levon 			is_wide = 1;
1091f5207b7SJohn Levon 		case TOKEN_STRING:
1101f5207b7SJohn Levon 			next = next->next;
1111f5207b7SJohn Levon 			break;
1121f5207b7SJohn Levon 		default:
1131f5207b7SJohn Levon 			done = next;
1141f5207b7SJohn Levon 		}
1151f5207b7SJohn Levon 	}
116*c85f09ccSJohn Levon 	bits = is_wide ? wchar_ctype->bit_size: bits_in_char;
1171f5207b7SJohn Levon 	while (token != done) {
1181f5207b7SJohn Levon 		unsigned v;
1191f5207b7SJohn Levon 		const char *p = token->string->data;
1201f5207b7SJohn Levon 		const char *end = p + token->string->length - 1;
1211f5207b7SJohn Levon 		while (p < end) {
1221f5207b7SJohn Levon 			if (*p == '\\')
1231f5207b7SJohn Levon 				esc_count++;
1241f5207b7SJohn Levon 			p = parse_escape(p, &v, end, bits, token->pos);
1251f5207b7SJohn Levon 			if (len < MAX_STRING)
1261f5207b7SJohn Levon 				buffer[len] = v;
1271f5207b7SJohn Levon 			len++;
1281f5207b7SJohn Levon 		}
1291f5207b7SJohn Levon 		token = token->next;
1301f5207b7SJohn Levon 	}
1311f5207b7SJohn Levon 	if (len > MAX_STRING) {
1321f5207b7SJohn Levon 		warning(token->pos, "trying to concatenate %d-character string (%d bytes max)", len, MAX_STRING);
1331f5207b7SJohn Levon 		len = MAX_STRING;
1341f5207b7SJohn Levon 	}
1351f5207b7SJohn Levon 
1361f5207b7SJohn Levon 	if (esc_count || len >= string->length) {
1371f5207b7SJohn Levon 		if (string->immutable || len >= string->length)	/* can't cannibalize */
1381f5207b7SJohn Levon 			string = __alloc_string(len+1);
1391f5207b7SJohn Levon 		string->length = len+1;
1401f5207b7SJohn Levon 		memcpy(string->data, buffer, len);
1411f5207b7SJohn Levon 		string->data[len] = '\0';
1421f5207b7SJohn Levon 	}
1431f5207b7SJohn Levon 	expr->string = string;
1441f5207b7SJohn Levon 	expr->wide = is_wide;
1451f5207b7SJohn Levon 	return token;
1461f5207b7SJohn Levon }
147