Add a test for '##' handling from the kernel sources,
[smatch.git] / check.c
blob70fa4f91160563faf47119b88aee6536b3443f38
1 /*
2 * Example trivial client program that uses the sparse library
3 * to tokenize, pre-process and parse a C file, and prints out
4 * the results.
6 * Copyright (C) 2003 Transmeta Corp.
8 * Licensed under the Open Software License version 1.1
9 */
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <unistd.h>
16 #include <fcntl.h>
18 #include "lib.h"
19 #include "token.h"
20 #include "parse.h"
21 #include "symbol.h"
22 #include "expression.h"
24 static unsigned int pre_buffer_size = 0;
25 static unsigned char pre_buffer[8192];
27 static int preprocess_only;
28 static char *include = NULL;
29 static int include_fd = -1;
31 static void add_pre_buffer(const char *fmt, ...)
33 va_list args;
34 unsigned int size;
36 va_start(args, fmt);
37 size = pre_buffer_size;
38 size += vsnprintf(pre_buffer + size,
39 sizeof(pre_buffer) - size,
40 fmt, args);
41 pre_buffer_size = size;
42 va_end(args);
45 static char ** handle_switch(char *arg, char **next)
47 switch (*arg) {
48 case 'D': {
49 const char *name = arg+1;
50 const char *value = "";
51 for (;;) {
52 char c;
53 c = *++arg;
54 if (!c)
55 break;
56 if (isspace(c) || c == '=') {
57 *arg = '\0';
58 value = arg+1;
59 break;
62 add_pre_buffer("#define %s %s\n", name, value);
63 return next;
66 case 'E':
67 preprocess_only = 1;
68 return next;
69 case 'v':
70 verbose = 1;
71 return next;
72 case 'I':
73 add_pre_buffer("#add_include \"%s/\"\n", arg+1);
74 return next;
75 case 'i':
76 if (*next && !strcmp(arg, "include")) {
77 char *name = *++next;
78 int fd = open(name, O_RDONLY);
79 include_fd = fd;
80 include = name;
81 if (fd < 0)
82 perror(name);
83 return next;
85 /* Fallthrough */
86 default:
87 /* Ignore unknown command line options - they're probably gcc switches */
88 break;
90 return next;
93 static void clean_up_symbol(struct symbol *sym, void *_parent, int flags)
95 check_duplicates(sym);
96 evaluate_symbol(sym);
97 expand_symbol(sym);
100 int main(int argc, char **argv)
102 int fd;
103 char *filename = NULL, **args;
104 struct token *token;
106 // Initialize symbol stream first, so that we can add defines etc
107 init_symbols();
109 add_pre_buffer("#define __i386__ 1\n");
110 add_pre_buffer("#define __linux__ 1\n");
111 add_pre_buffer("#define __STDC__ 1\n");
112 add_pre_buffer("#define linux linux\n");
113 add_pre_buffer("#define __CHECKER__ 1\n");
114 add_pre_buffer("#define cond_syscall(x)\n");
115 add_pre_buffer("#define __GNUC__ 2\n");
116 add_pre_buffer("#define __GNUC_MINOR__ 95\n");
117 add_pre_buffer("#define __func__ \"function\"\n");
118 add_pre_buffer("#define __extension__\n");
119 add_pre_buffer("#define __pragma__\n");
120 add_pre_buffer("extern void *__builtin_memcpy(void *, const void *, unsigned long);\n");
121 add_pre_buffer("extern void * __builtin_return_address(int);\n");
122 add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
123 add_pre_buffer("#define __builtin_va_arg(arg,type) ((type)0)\n");
124 add_pre_buffer("#define __builtin_va_end(arg)\n");
126 args = argv;
127 for (;;) {
128 char *arg = *++args;
129 if (!arg)
130 break;
131 if (arg[0] == '-') {
132 args = handle_switch(arg+1, args);
133 continue;
135 filename = arg;
139 fd = open(filename, O_RDONLY);
140 if (fd < 0)
141 die("No such file: %s", filename);
143 // Tokenize the input stream
144 token = tokenize(filename, fd, NULL);
145 close(fd);
147 // Prepend any "include" file to the stream.
148 if (include_fd >= 0)
149 token = tokenize(include, include_fd, token);
151 // Prepend the initial built-in stream
152 token = tokenize_buffer(pre_buffer, pre_buffer_size, token);
154 // Pre-process the stream
155 token = preprocess(token);
157 if (preprocess_only) {
158 while (!eof_token(token)) {
159 int prec = 1;
160 struct token *next = token->next;
161 char * separator = "";
162 if (next->pos.whitespace)
163 separator = " ";
164 if (next->pos.newline) {
165 separator = "\n\t\t\t\t\t";
166 prec = next->pos.pos;
167 if (prec > 4)
168 prec = 4;
170 printf("%s%.*s", show_token(token), prec, separator);
171 token = next;
173 putchar('\n');
175 return 0;
178 // Parse the resulting C code
179 translation_unit(token, &used_list);
181 // Do type evaluation and simplify
182 symbol_iterate(used_list, clean_up_symbol, NULL);
183 return 0;