Merge branch 'master' into expression-parser
[fio.git] / exp / fixup-buggy-yacc-output.c
1 /*
2  * (C) Copyright 2014, Stephen M. Cameron.
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License version 2 as
6  *  published by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <errno.h>
27
28 static char *programname;
29
30 static char *slurp_file(char *f, off_t *textsize)
31 {
32         int fd;
33         struct stat statbuf;
34         off_t bytesleft, bytesread;
35         char *fileptr = NULL;
36         char *slurped_file = NULL;
37
38         fd = open(f, O_RDONLY);
39         if (fd < 0) {
40                 fprintf(stderr, "%s: Cannot open '%s': %s\n",
41                                 programname, f, strerror(errno));
42                 return NULL;
43         }
44         if (fstat(fd, &statbuf) != 0) {
45                 fprintf(stderr, "%s: Cannot stat '%s': %s\n",
46                                 programname, f, strerror(errno));
47                 close(fd);
48                 return NULL;
49         }
50         bytesleft = statbuf.st_size; 
51         slurped_file = malloc(bytesleft + 1);
52         fileptr = slurped_file;
53         if (!slurped_file) {
54                 fprintf(stderr, "%s: malloc returned NULL, out of memory\n",
55                         programname);
56                 goto bail_out;
57         }
58         memset(slurped_file, 0, bytesleft + 1);
59         do {
60                 bytesread = read(fd, fileptr, bytesleft);
61                 if (bytesread < 0 && errno == EAGAIN)
62                         continue;
63                 if (bytesread < 0) {
64                         fprintf(stderr, "%s: error reading '%s: %s'\n",
65                                 programname, f, strerror(errno));
66                         goto bail_out;
67                 }
68                 if (bytesread == 0) {
69                         fprintf(stderr, "%s: unexpected EOF in %s\n",
70                                 programname, f); 
71                         goto bail_out;
72                 }
73                 fileptr += bytesread;
74                 bytesleft -= bytesread;
75         } while (bytesleft > 0);
76
77         *textsize = statbuf.st_size;
78
79         close(fd);
80         return slurped_file;
81
82 bail_out:
83         if (slurped_file)
84                 free(slurped_file);
85         close(fd);
86         return NULL;
87 }
88
89 static int detect_buggy_yacc(char *text)
90 {
91         char *x;
92
93         x = strstr(text, " #line ");
94         if (!x)
95                 return 0;
96         return 1; 
97 }
98
99 static void fixup_buggy_yacc_file(char *f)
100 {
101         char *slurped_file, *x;
102         off_t textsize;
103         char *newname;
104         int fd;
105         off_t bytesleft, byteswritten;
106
107         newname = alloca(strlen(f) + 10);
108         strcpy(newname, "broken-");
109         strcat(newname, f);
110
111         slurped_file = slurp_file(f, &textsize);
112         if (!slurped_file)
113                 return;
114         if (!detect_buggy_yacc(slurped_file))
115                 return;
116
117         x = slurped_file;
118
119
120         /*
121          * Fixup the '#line' directives which yacc botched.
122          * Note: this is vulnerable to false positives, but
123          * since this program is just a hack to make this particular
124          * program work, it is sufficient for our purposes.
125          * regexp could make this better, but the real fix needs
126          * to be made in yacc/bison.
127          */
128         while ((x = strstr(x, " #line ")) != NULL) {
129                 *x = '\n';
130         }
131
132         if (rename(f, newname) != 0) {
133                 fprintf(stderr, "%s: Failed to rename '%s' to '%s': %s\n",
134                                 programname, f, newname, strerror(errno));
135                 return;
136         }
137         fd = open(f, O_CREAT | O_TRUNC | O_RDWR, 0644);
138         if (fd < 0) {
139                 fprintf(stderr, "%s: failed to create '%s': %s\n",
140                         programname, f, strerror(errno));
141                 return;
142         }
143
144         bytesleft = textsize;
145         x = slurped_file;
146         do {
147                 byteswritten = write(fd, x, bytesleft); 
148                 if (byteswritten < 0) {
149                         fprintf(stderr, "%s: Error writing '%s': %s\n",
150                                 programname, f, strerror(errno)); 
151                         return;
152                 }
153                 if (byteswritten == 0 && errno == EINTR)
154                         continue;
155                 x += byteswritten;
156                 bytesleft -= byteswritten;
157         } while (bytesleft > 0);
158         close(fd);
159 }
160
161 int main(int argc, char *argv[])
162 {
163         int i;
164
165         programname = argv[0];
166
167         for (i = 1; i < argc; i++)
168                 fixup_buggy_yacc_file(argv[i]);
169         return 0;
170 }