1 /* Support for fixing grammar files.
3 Copyright (C) 2019-2021 Free Software Foundation, Inc.
5 This file is part of Bison, the GNU Compiler Compiler.
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
25 #include <get-errno.h>
26 #include <gl_array_list.h>
31 #include <vasnprintf.h>
44 gl_list_t fixits
= NULL
;
47 fixit_new (location
const *loc
, char const* fix
)
49 fixit
*res
= xmalloc (sizeof *res
);
51 res
->fix
= xstrdup (fix
);
56 fixit_cmp (const fixit
*a
, const fixit
*b
)
58 return location_cmp (a
->location
, b
->location
);
69 /* GCC and Clang follow the same pattern.
70 https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Message-Formatting-Options.html
71 https://clang.llvm.org/docs/UsersManual.html#cmdoption-fdiagnostics-parseable-fixits */
73 fixit_print (fixit
const *f
, FILE *out
)
75 fprintf (out
, "fix-it:%s:{%d:%d-%d:%d}:%s\n",
76 quotearg_n_style (1, c_quoting_style
, f
->location
.start
.file
),
77 f
->location
.start
.line
, f
->location
.start
.byte
,
78 f
->location
.end
.line
, f
->location
.end
.byte
,
79 quotearg_n_style (2, c_quoting_style
, f
->fix
));
84 fixits_register (location
const *loc
, char const* fix
)
87 fixits
= gl_list_create_empty (GL_ARRAY_LIST
,
90 (gl_listelement_dispose_fn
) fixit_free
,
92 fixit
*f
= fixit_new (loc
, fix
);
93 gl_sortedlist_add (fixits
, (gl_listelement_compar_fn
) fixit_cmp
, f
);
94 if (feature_flag
& feature_fixit
)
95 fixit_print (f
, stderr
);
112 /* This is not unlike what is done in location_caret. */
113 uniqstr input
= ((fixit
*) gl_list_get_at (fixits
, 0))->location
.start
.file
;
114 /* Backup the file. */
116 size_t len
= sizeof (buf
);
117 char *backup
= asnprintf (buf
, &len
, "%s~", input
);
120 if (rename (input
, backup
))
121 error (EXIT_FAILURE
, get_errno (),
122 _("%s: cannot backup"), quotearg_colon (input
));
123 FILE *in
= xfopen (backup
, "r");
124 FILE *out
= xfopen (input
, "w");
127 void const *p
= NULL
;
128 gl_list_iterator_t iter
= gl_list_iterator (fixits
);
129 while (gl_list_iterator_next (&iter
, &p
, NULL
))
132 /* Look for the correct line. */
133 while (line
< f
->location
.start
.line
)
146 /* Look for the right offset. */
147 bool need_eol
= false;
148 while (offset
< f
->location
.start
.byte
)
155 /* The position we are asked for is beyond the actual
156 line: pad with spaces, and remember we need a \n. */
158 putc (need_eol
? ' ' : c
, out
);
161 /* Paste the fix instead. */
164 /* Maybe install the eol afterwards. */
168 /* Skip the bad input. */
169 while (line
< f
->location
.end
.line
)
180 while (offset
< f
->location
.end
.byte
)
188 /* If erasing the content of a full line, also remove the
190 if (f
->fix
[0] == 0 && f
->location
.start
.byte
== 1)
204 /* Paste the rest of the file. */
207 while ((c
= getc (in
)) != EOF
)
211 gl_list_iterator_free (&iter
);
214 fprintf (stderr
, "%s: file %s was updated (backup: %s)\n",
215 program_name
, quote_n (0, input
), quote_n (1, backup
));
221 /* Free the registered fixits. */
222 void fixits_free (void)
226 gl_list_free (fixits
);