-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse-headers.c
103 lines (98 loc) · 4.18 KB
/
parse-headers.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/* *************DOC***************
* Parse the gcc preprocessor header list (cflag -M) to make a
* list of header paths for ctags to use.
*
* Example
* -------
* Use gcc to output a list of headers in headers-M.txt:
* $(CC) $(CFLAGS) $< -M > headers-M.txt
*
* List all headers in new file headers.txt:
* ./parse-headers.exe
*
* Only list local headers (my libs) in new file headers.txt:
* ./parse-headers.exe M
*
* Arguments
* ---------
* None : include all libs
* M : only include my libs (exclude system libs)
*
* Strings -- how to identify a string in a single pass
* -------
* Spaces are separators. If char is SPACE, this is not a string.
* Backslash is a line break. If char is line break, this is not a string.
* Newlines come after line breaks. If char is newline, this is not a string.
*
* Header paths
* ------------
* Header paths include .h. If string does not have .h, it is not a header path.
*
* Every string is a header path except the first two.
* Instead of testing for header paths, I hardcode ignoring the first two strings.
*******************************/
#include <stdio.h>
#include <stdbool.h>
typedef enum _state__def { STR, SEP } state; // State is STRING or SEPARATOR
state update_state(const char c)
{
state st = ((c == ' ') || (c == '\\') || (c == '\n')) ? SEP : STR;
return st;
}
#define STR_OK ( (cnt>2) && (ignore==false) )
int main(int argc, char *argv[])
{
bool just_tag_my_libs = false;
{ // $ ./parse-headers.exe M <---- just tag my libs
if(argc>1) if(argv[1][0]=='M') just_tag_my_libs = true;
printf("Tagging: %s\n",just_tag_my_libs?"my header libs only":"all libs");
}
FILE *f = fopen("headers-M.txt", "r"); // Read the gcc -M output
FILE *o = fopen("headers.txt", "w"); // Write a list of headers for ctags
{ // Parse headers.txt for header paths
state st = SEP; // Initial state: outside of a STRING
int cnt = 0; // Initial STRING count: 0
int c; // Parse file one character at a time
bool ignore = false; // State: ignore this string or not
while( (c=fgetc(f)) != EOF )
{
switch(st)
{
case SEP: // Outside a STRING
st = update_state(c); // Update state
switch(st) // Do action based on new state
{
case STR: // Start of a new STRING
if(just_tag_my_libs) // Ignore paths that start with C
{
if(c=='C') ignore = true;
else ignore = false;
}
cnt++; // Increment STRING counter
if(STR_OK) putc(c, o); // Print all strings after first two: "blah.o: blah.c"
break;
case SEP: // Still outside a STRING
break; // Do nothing
}
break;
case STR: // Inside a STRING
st = update_state(c); // Update state
switch(st) // Do action based on new state
{
case STR: // Still inside a STRING
if(STR_OK) putc(c, o); // Still printing this STRING
break;
case SEP: // STRING is finished
if(STR_OK) putc('\n', o); // Add a newline after all the strings I keep
break;
default: printf("Unexpected state: %d", st); fclose(f); return 42;
}
break;
default: printf("Unexpected state: %d", st); fclose(f); return 42;
}
}
}
fclose(o);
fclose(f);
return 0;
}