summaryrefslogblamecommitdiffstats
path: root/devtools/list-c-types.c
blob: ec37a53919a58d312d281a83988162493c289e1f (plain) (tree)































































































































































                                                                                                       
/* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>


static char quote = 0;
static int in_name = 0;
static size_t typedef_keyword = 0;
static size_t struct_keyword = 0;
static size_t union_keyword = 0;
static size_t enum_keyword = 0;
static int printing = 0;
static size_t levels = 0;
static size_t brackets = 0;

static size_t
extract(char *text, size_t len, int *outputln)
{
	const char *keyword;
	char *w = text, c;
	size_t off;

	*outputln = 0;

	for (off = 0; off < len; off++) {
		if (!text[off])
			text[off] = ' ';

		if (printing) {
			*w++ = text[off];
			levels += text[off] == '{';
			levels -= text[off] == '}';
			if (!levels && text[off] == ';') {
				if ((size_t)(w - text) == len)
					*outputln = 1;
				else
					*w++ = '\n';
				printing = 0;
			}
			continue;
		}

		switch (text[off]) {
		case '\"':
		case '\'':
			in_name = 0;
			quote = quote == text[off] ? 0 : text[off];
			break;

		case '\\':
			off++;
			break;

		default:
			if (quote)
				break;

			brackets += text[off] == '(' || text[off] == '[' || text[off] == '{';
			brackets -= text[off] == ')' || text[off] == ']' || text[off] == '}';
			if (brackets)
				break;

			if (!"typedef"[typedef_keyword]) {
				keyword = "typedef";
				goto found_keyword;
			} else if (!"struct"[struct_keyword]) {
				keyword = "struct";
				goto found_keyword;
			} else if (!"union"[union_keyword]) {
				keyword = "union";
				goto found_keyword;
			} else if (!"enum"[enum_keyword]) {
				keyword = "enum";
				goto found_keyword;
			} else if (!in_name) {
				if (text[off] != "typedef"[typedef_keyword++])
					typedef_keyword = 0;
				if (text[off] != "struct"[struct_keyword++])
					struct_keyword = 0;
				if (text[off] != "union"[union_keyword++])
					union_keyword = 0;
				if (text[off] != "enum"[enum_keyword++])
					enum_keyword = 0;
				if (typedef_keyword || struct_keyword || union_keyword || enum_keyword)
					break;
			}

			if (isalnum(text[off]) || text[off] == '_')
				in_name = 1;
			else
				goto not_alnum;

			break;
		found_keyword:
			if (isalnum(text[off]) || text[off] == '_') {
				in_name = 1;
				goto reset_keyword;
			}
			c = text[off];
			w = stpcpy(w, keyword);
			*w++ = c;
			printing = 1;
		not_alnum:
			in_name = 0;
		reset_keyword:
			typedef_keyword = 0;
			struct_keyword = 0;
			union_keyword = 0;
			enum_keyword = 0;
			break;
		}
	}

	return (size_t)(w - text);
}

int
main(int argc, char *argv[])
{
	char buf[8 << 10];
	size_t size, off;
	ssize_t r;
	int outputln = 0;

	(void) argc;

	for (;;) {
		r = read(STDIN_FILENO, buf, sizeof(buf));
		if (r <= 0) {
			if (!r)
				break;
			if (errno == EINTR)
				continue;
			perror(argv[0]);
			return 1;
		}
		size = extract(buf, (size_t)r, &outputln);
	write_again:
		for (off = 0; off < size; off += (size_t)r) {
			r = write(STDOUT_FILENO, &buf[off], size - off);
			if (r <= 0) {
				if (errno == EINTR)
					continue;
				perror(argv[0]);
				return 1;
			}
		}
		if (outputln) {
			outputln = 0;
			buf[0] = '\n';
			size = 1;
			goto write_again;
		}
	}

	return 0;
}