xref: /third_party/ltp/tools/sparse/sparse-src/char.c (revision f08c3bdf)
1#include <string.h>
2#include "target.h"
3#include "lib.h"
4#include "allocate.h"
5#include "token.h"
6#include "expression.h"
7#include "char.h"
8
9static const char *parse_escape(const char *p, unsigned *val, const char *end, int bits, struct position pos)
10{
11	unsigned c = *p++;
12	unsigned d;
13	if (c != '\\') {
14		*val = c;
15		return p;
16	}
17
18	c = *p++;
19	switch (c) {
20	case 'a': c = '\a'; break;
21	case 'b': c = '\b'; break;
22	case 't': c = '\t'; break;
23	case 'n': c = '\n'; break;
24	case 'v': c = '\v'; break;
25	case 'f': c = '\f'; break;
26	case 'r': c = '\r'; break;
27	case 'e': c = '\e'; break;
28	case 'x': {
29		unsigned mask = -(1U << (bits - 4));
30		for (c = 0; p < end; c = (c << 4) + d) {
31			d = hexval(*p);
32			if (d > 16)
33				break;
34			p++;
35			if (c & mask) {
36				warning(pos,
37					"hex escape sequence out of range");
38				mask = 0;
39			}
40		}
41		break;
42	}
43	case '0'...'7': {
44		if (p + 2 < end)
45			end = p + 2;
46		c -= '0';
47		while (p < end && (d = *p - '0') < 8) {
48			c = (c << 3) + d;
49			p++;
50		}
51		if ((c & 0400) && bits < 9)
52			warning(pos,
53				"octal escape sequence out of range");
54		break;
55	}
56	default:	/* everything else is left as is */
57		warning(pos, "unknown escape sequence: '\\%c'", c);
58		break;
59	case '\\':
60	case '\'':
61	case '"':
62	case '?':
63		break;	/* those are legal, so no warnings */
64	}
65	*val = c & ~((~0U << (bits - 1)) << 1);
66	return p;
67}
68
69void get_char_constant(struct token *token, unsigned long long *val)
70{
71	const char *p = token->embedded, *end;
72	unsigned v;
73	int type = token_type(token);
74	switch (type) {
75	case TOKEN_CHAR:
76	case TOKEN_WIDE_CHAR:
77		p = token->string->data;
78		end = p + token->string->length - 1;
79		if (end == p) {
80			sparse_error(token->pos, "empty character constant");
81			*val = 0;
82			return;
83		}
84		break;
85	case TOKEN_CHAR_EMBEDDED_0 ... TOKEN_CHAR_EMBEDDED_3:
86		end = p + type - TOKEN_CHAR;
87		break;
88	default:
89		end = p + type - TOKEN_WIDE_CHAR;
90	}
91	p = parse_escape(p, &v, end,
92			type < TOKEN_WIDE_CHAR ? bits_in_char : wchar_ctype->bit_size, token->pos);
93	if (p != end)
94		warning(token->pos,
95			"multi-character character constant");
96	*val = v;
97}
98
99struct token *get_string_constant(struct token *token, struct expression *expr)
100{
101	struct string *string = token->string;
102	struct token *next = token->next, *done = NULL;
103	int stringtype = token_type(token);
104	int is_wide = stringtype == TOKEN_WIDE_STRING;
105	static char buffer[MAX_STRING];
106	int len = 0;
107	int bits;
108	int esc_count = 0;
109
110	while (!done) {
111		switch (token_type(next)) {
112		case TOKEN_WIDE_STRING:
113			is_wide = 1;
114		case TOKEN_STRING:
115			next = next->next;
116			break;
117		default:
118			done = next;
119		}
120	}
121	bits = is_wide ? wchar_ctype->bit_size: bits_in_char;
122	while (token != done) {
123		unsigned v;
124		const char *p = token->string->data;
125		const char *end = p + token->string->length - 1;
126		while (p < end) {
127			if (*p == '\\')
128				esc_count++;
129			p = parse_escape(p, &v, end, bits, token->pos);
130			if (len < MAX_STRING)
131				buffer[len] = v;
132			len++;
133		}
134		token = token->next;
135	}
136	if (len > MAX_STRING) {
137		warning(token->pos, "trying to concatenate %d-character string (%d bytes max)", len, MAX_STRING);
138		len = MAX_STRING;
139	}
140
141	if (esc_count || len >= string->length) {
142		if (string->immutable || len >= string->length)	/* can't cannibalize */
143			string = __alloc_string(len+1);
144		string->length = len+1;
145		memcpy(string->data, buffer, len);
146		string->data[len] = '\0';
147	}
148	expr->string = string;
149	expr->wide = is_wide;
150	return token;
151}
152