Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 1 | /* |
Gavin Howard | b5904bf | 2018-02-20 13:28:18 -0700 | [diff] [blame] | 2 | * ***************************************************************************** |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 3 | * |
Gavin Howard | 29e00ba | 2020-06-30 09:25:21 -0600 | [diff] [blame] | 4 | * SPDX-License-Identifier: BSD-2-Clause |
| 5 | * |
Gavin Howard | 4feb708 | 2021-01-26 01:19:25 -0700 | [diff] [blame] | 6 | * Copyright (c) 2018-2021 Gavin D. Howard and contributors. |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 7 | * |
Gavin Howard | 7345cb9 | 2019-04-08 14:13:43 -0600 | [diff] [blame] | 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions are met: |
| 10 | * |
| 11 | * * Redistributions of source code must retain the above copyright notice, this |
| 12 | * list of conditions and the following disclaimer. |
| 13 | * |
| 14 | * * Redistributions in binary form must reproduce the above copyright notice, |
| 15 | * this list of conditions and the following disclaimer in the documentation |
| 16 | * and/or other materials provided with the distribution. |
| 17 | * |
| 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 28 | * POSSIBILITY OF SUCH DAMAGE. |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 29 | * |
Gavin Howard | b5904bf | 2018-02-20 13:28:18 -0700 | [diff] [blame] | 30 | * ***************************************************************************** |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 31 | * |
| 32 | * Generates a const array from a bc script. |
| 33 | * |
| 34 | */ |
| 35 | |
Gavin Howard | be3a342 | 2018-09-07 13:29:10 -0600 | [diff] [blame] | 36 | #include <stdbool.h> |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 37 | #include <stdio.h> |
Gavin Howard | 207053c | 2018-02-20 11:12:43 -0700 | [diff] [blame] | 38 | #include <stdlib.h> |
| 39 | #include <string.h> |
| 40 | |
Gavin Howard | be3a342 | 2018-09-07 13:29:10 -0600 | [diff] [blame] | 41 | #include <errno.h> |
| 42 | |
Gavin Howard | 2968e99 | 2021-06-18 23:40:15 -0600 | [diff] [blame] | 43 | // For some reason, Windows needs this header. |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 44 | #ifndef _WIN32 |
Gavin Howard | 207053c | 2018-02-20 11:12:43 -0700 | [diff] [blame] | 45 | #include <libgen.h> |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 46 | #endif // _WIN32 |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 47 | |
Gavin Howard | 2968e99 | 2021-06-18 23:40:15 -0600 | [diff] [blame] | 48 | // This is exactly what it looks like. It just slaps a simple license header on |
| 49 | // the generated C source file. |
Gavin Howard | be3a342 | 2018-09-07 13:29:10 -0600 | [diff] [blame] | 50 | static const char* const bc_gen_header = |
Gavin Howard | 4feb708 | 2021-01-26 01:19:25 -0700 | [diff] [blame] | 51 | "// Copyright (c) 2018-2021 Gavin D. Howard and contributors.\n" |
Gavin Howard | b64e652 | 2019-02-06 15:22:03 -0700 | [diff] [blame] | 52 | "// Licensed under the 2-clause BSD license.\n" |
Gavin Howard | 9f9bef4 | 2020-10-22 21:37:46 -0600 | [diff] [blame] | 53 | "// *** AUTOMATICALLY GENERATED FROM %s. DO NOT MODIFY. ***\n\n"; |
Gavin Howard | be3a342 | 2018-09-07 13:29:10 -0600 | [diff] [blame] | 54 | |
Gavin Howard | 2968e99 | 2021-06-18 23:40:15 -0600 | [diff] [blame] | 55 | // These are just format strings used to generate the C source. |
Gavin Howard | be3a342 | 2018-09-07 13:29:10 -0600 | [diff] [blame] | 56 | static const char* const bc_gen_label = "const char *%s = \"%s\";\n\n"; |
Gavin Howard | 9f9bef4 | 2020-10-22 21:37:46 -0600 | [diff] [blame] | 57 | static const char* const bc_gen_label_extern = "extern const char *%s;\n\n"; |
Gavin Howard | 64ae649 | 2018-12-26 17:47:34 -0700 | [diff] [blame] | 58 | static const char* const bc_gen_ifdef = "#if %s\n"; |
Gavin Howard | eb5c6ab | 2018-10-03 11:47:36 -0600 | [diff] [blame] | 59 | static const char* const bc_gen_endif = "#endif // %s\n"; |
Gavin Howard | be3a342 | 2018-09-07 13:29:10 -0600 | [diff] [blame] | 60 | static const char* const bc_gen_name = "const char %s[] = {\n"; |
Gavin Howard | 9f9bef4 | 2020-10-22 21:37:46 -0600 | [diff] [blame] | 61 | static const char* const bc_gen_name_extern = "extern const char %s[];\n\n"; |
Gavin Howard | fe2351d | 2018-02-19 14:10:15 -0700 | [diff] [blame] | 62 | |
Gavin Howard | 2968e99 | 2021-06-18 23:40:15 -0600 | [diff] [blame] | 63 | // Error codes. We can't use 0 because these are used as exit statuses, and 0 |
| 64 | // as an exit status is not an error. |
Gavin Howard | fb44241 | 2019-02-06 15:28:53 -0700 | [diff] [blame] | 65 | #define IO_ERR (1) |
Gavin Howard | 1cbfe24 | 2019-01-09 17:13:11 -0700 | [diff] [blame] | 66 | #define INVALID_INPUT_FILE (2) |
Gavin Howard | fb44241 | 2019-02-06 15:28:53 -0700 | [diff] [blame] | 67 | #define INVALID_PARAMS (3) |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 68 | |
Gavin Howard | 2968e99 | 2021-06-18 23:40:15 -0600 | [diff] [blame] | 69 | // This is the max width to print characters to the screen. This is to ensure |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 70 | // that lines don't go much over 80 characters. |
| 71 | #define MAX_WIDTH (72) |
Gavin Howard | 7edf829 | 2018-03-09 02:07:59 -0700 | [diff] [blame] | 72 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 73 | /** |
| 74 | * Open a file. This function is to smooth over differences between POSIX and |
| 75 | * Windows. |
| 76 | * @param f A pointer to the FILE pointer that will be initialized. |
| 77 | * @param filename The name of the file. |
| 78 | * @param mode The mode to open the file in. |
| 79 | */ |
Gavin Howard | bcd5ac1 | 2021-04-04 19:56:27 -0600 | [diff] [blame] | 80 | static void open_file(FILE** f, const char* filename, const char* mode) { |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 81 | |
| 82 | #ifndef _WIN32 |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 83 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 84 | *f = fopen(filename, mode); |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 85 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 86 | #else // _WIN32 |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 87 | |
| 88 | // We want the file pointer to be NULL on failure, but fopen_s() is not |
| 89 | // guaranteed to set it. |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 90 | *f = NULL; |
| 91 | fopen_s(f, filename, mode); |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 92 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 93 | #endif // _WIN32 |
| 94 | } |
| 95 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 96 | /** |
| 97 | * Outputs a label, which is a string literal that the code can use as a name |
| 98 | * for the file that is being turned into a string. This is important for the |
| 99 | * math libraries because the parse and lex code expects a filename. The label |
| 100 | * becomes the filename for the purposes of lexing and parsing. |
| 101 | * |
| 102 | * The label is generated from bc_gen_label (above). It has the form: |
| 103 | * |
| 104 | * const char *<label_name> = <label>; |
| 105 | * |
| 106 | * This function is also needed to smooth out differences between POSIX and |
| 107 | * Windows, specifically, the fact that Windows uses backslashes for filenames |
| 108 | * and that backslashes have to be escaped in a string literal. |
| 109 | * |
| 110 | * @param out The file to output to. |
| 111 | * @param label The label name. |
| 112 | * @param name The actual label text, which is a filename. |
| 113 | * @return Positive if no error, negative on error, just like *printf(). |
| 114 | */ |
Gavin Howard | bcd5ac1 | 2021-04-04 19:56:27 -0600 | [diff] [blame] | 115 | static int output_label(FILE* out, const char* label, const char* name) { |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 116 | |
| 117 | #ifndef _WIN32 |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 118 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 119 | return fprintf(out, bc_gen_label, label, name); |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 120 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 121 | #else // _WIN32 |
| 122 | |
| 123 | size_t i, count = 0, len = strlen(name); |
| 124 | char* buf; |
| 125 | int ret; |
| 126 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 127 | // This loop counts how many backslashes there are in the label. |
| 128 | for (i = 0; i < len; ++i) count += (name[i] == '\\'); |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 129 | |
| 130 | buf = (char*) malloc(len + 1 + count); |
| 131 | if (buf == NULL) return -1; |
| 132 | |
| 133 | count = 0; |
| 134 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 135 | // This loop is the meat of the Windows version. What it does is copy the |
| 136 | // label byte-for-byte, unless it encounters a backslash, in which case, it |
| 137 | // copies the backslash twice to have it escaped properly in the string |
| 138 | // literal. |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 139 | for (i = 0; i < len; ++i) { |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 140 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 141 | buf[i + count] = name[i]; |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 142 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 143 | if (name[i] == '\\') { |
| 144 | count += 1; |
| 145 | buf[i + count] = name[i]; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | buf[i + count] = '\0'; |
| 150 | |
| 151 | ret = fprintf(out, bc_gen_label, label, buf); |
| 152 | |
| 153 | free(buf); |
| 154 | |
| 155 | return ret; |
| 156 | |
| 157 | #endif // _WIN32 |
| 158 | } |
| 159 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 160 | /** |
| 161 | * This program generates C strings (well, actually, C char arrays) from text |
| 162 | * files. It generates 1 C source file. The resulting file has this structure: |
| 163 | * |
| 164 | * <Copyright Header> |
| 165 | * |
| 166 | * [<Label Extern>] |
| 167 | * |
| 168 | * <Char Array Extern> |
| 169 | * |
| 170 | * [<Preprocessor Guard Begin>] |
| 171 | * [<Label Definition>] |
| 172 | * |
| 173 | * <Char Array Definition> |
| 174 | * [<Preprocessor Guard End>] |
| 175 | * |
| 176 | * Anything surrounded by square brackets may not be in the final generated |
| 177 | * source file. |
| 178 | * |
Gavin Howard | dbe6854 | 2021-06-19 17:20:08 -0600 | [diff] [blame] | 179 | * The required command-line parameters are: |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 180 | * |
Gavin Howard | dbe6854 | 2021-06-19 17:20:08 -0600 | [diff] [blame] | 181 | * input Input filename. |
| 182 | * output Output filename. |
| 183 | * name The name of the char array. |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 184 | * |
| 185 | * The optional parameters are: |
| 186 | * |
Gavin Howard | dbe6854 | 2021-06-19 17:20:08 -0600 | [diff] [blame] | 187 | * label If given, a label for the char array. See the comment for the |
| 188 | * output_label() function. It is meant as a "filename" for the |
| 189 | * text when processed by bc and dc. If label is given, then the |
| 190 | * <Label Extern> and <Label Definition> will exist in the |
| 191 | * generated source file. |
| 192 | * define If given, a preprocessor macro that should be used as a guard |
| 193 | * for the char array and its label. If define is given, then |
| 194 | * <Preprocessor Guard Begin> will exist in the form |
| 195 | * "#if <define>" as part of the generated source file, and |
| 196 | * <Preprocessor Guard End> will exist in the form |
| 197 | * "endif // <define>". |
| 198 | * remove_tabs If this parameter exists, it must be an integer. If it is |
| 199 | * non-zero, then tabs are removed from the input file text before |
| 200 | * outputting to the output char array. |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 201 | * |
| 202 | * All text files that are transformed have license comments. This program finds |
| 203 | * the end of that comment and strips it out as well. |
| 204 | */ |
Gavin Howard | 8d1f1db | 2018-02-23 11:29:41 -0700 | [diff] [blame] | 205 | int main(int argc, char *argv[]) { |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 206 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 207 | FILE *in, *out; |
Gavin Howard | 82bb870 | 2020-11-25 22:17:02 -0700 | [diff] [blame] | 208 | char *label, *define, *name; |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 209 | int c, count, slashes, err = IO_ERR; |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 210 | bool has_label, has_define, remove_tabs; |
Gavin Howard | d571acf | 2018-02-20 17:13:07 -0700 | [diff] [blame] | 211 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 212 | if (argc < 4) { |
Gavin Howard | dbe6854 | 2021-06-19 17:20:08 -0600 | [diff] [blame] | 213 | printf("usage: %s input output name [label [define [remove_tabs]]]\n", |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 214 | argv[0]); |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 215 | return INVALID_PARAMS; |
| 216 | } |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 217 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 218 | name = argv[3]; |
Gavin Howard | be3a342 | 2018-09-07 13:29:10 -0600 | [diff] [blame] | 219 | |
Gavin Howard | 82bb870 | 2020-11-25 22:17:02 -0700 | [diff] [blame] | 220 | has_label = (argc > 4 && strcmp("", argv[4]) != 0); |
| 221 | label = has_label ? argv[4] : ""; |
Gavin Howard | eb5c6ab | 2018-10-03 11:47:36 -0600 | [diff] [blame] | 222 | |
Gavin Howard | 82bb870 | 2020-11-25 22:17:02 -0700 | [diff] [blame] | 223 | has_define = (argc > 5 && strcmp("", argv[5]) != 0); |
| 224 | define = has_define ? argv[5] : ""; |
Gavin Howard | 1cbfe24 | 2019-01-09 17:13:11 -0700 | [diff] [blame] | 225 | |
Gavin Howard | 82bb870 | 2020-11-25 22:17:02 -0700 | [diff] [blame] | 226 | remove_tabs = (argc > 6); |
Gavin Howard | 3f9b574 | 2018-12-13 17:31:00 -0700 | [diff] [blame] | 227 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 228 | open_file(&in, argv[1], "r"); |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 229 | if (!in) return INVALID_INPUT_FILE; |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 230 | |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 231 | open_file(&out, argv[2], "w"); |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 232 | if (!out) goto out_err; |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 233 | |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 234 | if (fprintf(out, bc_gen_header, argv[1]) < 0) goto err; |
Gavin Howard | 9f9bef4 | 2020-10-22 21:37:46 -0600 | [diff] [blame] | 235 | if (has_label && fprintf(out, bc_gen_label_extern, label) < 0) goto err; |
| 236 | if (fprintf(out, bc_gen_name_extern, name) < 0) goto err; |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 237 | if (has_define && fprintf(out, bc_gen_ifdef, define) < 0) goto err; |
Gavin Howard | f7a6430 | 2021-04-04 19:13:24 -0600 | [diff] [blame] | 238 | if (has_label && output_label(out, label, argv[1]) < 0) goto err; |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 239 | if (fprintf(out, bc_gen_name, name) < 0) goto err; |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 240 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 241 | c = count = slashes = 0; |
Gavin Howard | 7edf829 | 2018-03-09 02:07:59 -0700 | [diff] [blame] | 242 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 243 | // This is where the end of the license comment is found. |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 244 | while (slashes < 2 && (c = fgetc(in)) >= 0) { |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 245 | slashes += (slashes == 1 && c == '/' && fgetc(in) == '\n'); |
| 246 | slashes += (!slashes && c == '/' && fgetc(in) == '*'); |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 247 | } |
Gavin Howard | 7edf829 | 2018-03-09 02:07:59 -0700 | [diff] [blame] | 248 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 249 | // The file is invalid if the end of the license comment could not be found. |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 250 | if (c < 0) { |
| 251 | err = INVALID_INPUT_FILE; |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 252 | goto err; |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 253 | } |
Gavin Howard | 7edf829 | 2018-03-09 02:07:59 -0700 | [diff] [blame] | 254 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 255 | // Do not put extra newlines at the beginning of the char array. |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 256 | while ((c = fgetc(in)) == '\n'); |
Gavin Howard | db28f43 | 2018-09-25 15:55:35 -0600 | [diff] [blame] | 257 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 258 | // This loop is what generates the actual char array. It counts how many |
| 259 | // chars it has printed per line in order to insert newlines at appropriate |
| 260 | // places. It also skips tabs if they should be removed. |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 261 | while (c >= 0) { |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 262 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 263 | int val; |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 264 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 265 | if (!remove_tabs || c != '\t') { |
Gavin Howard | 3f9b574 | 2018-12-13 17:31:00 -0700 | [diff] [blame] | 266 | |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 267 | if (!count && fputc('\t', out) == EOF) goto err; |
Gavin Howard | 3f9b574 | 2018-12-13 17:31:00 -0700 | [diff] [blame] | 268 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 269 | val = fprintf(out, "%d,", c); |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 270 | if (val < 0) goto err; |
Gavin Howard | fe2351d | 2018-02-19 14:10:15 -0700 | [diff] [blame] | 271 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 272 | count += val; |
Gavin Howard | fe2351d | 2018-02-19 14:10:15 -0700 | [diff] [blame] | 273 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 274 | if (count > MAX_WIDTH) { |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 275 | count = 0; |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 276 | if (fputc('\n', out) == EOF) goto err; |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 277 | } |
| 278 | } |
Gavin Howard | db28f43 | 2018-09-25 15:55:35 -0600 | [diff] [blame] | 279 | |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 280 | c = fgetc(in); |
| 281 | } |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 282 | |
Gavin Howard | d72062c | 2021-06-19 15:45:31 -0600 | [diff] [blame] | 283 | // Make sure the end looks nice and insert the NUL byte at the end. |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 284 | if (!count && (fputc(' ', out) == EOF || fputc(' ', out) == EOF)) goto err; |
| 285 | if (fprintf(out, "0\n};\n") < 0) goto err; |
Gavin Howard | eb5c6ab | 2018-10-03 11:47:36 -0600 | [diff] [blame] | 286 | |
Gavin Howard | fb44241 | 2019-02-06 15:28:53 -0700 | [diff] [blame] | 287 | err = (has_define && fprintf(out, bc_gen_endif, define) < 0); |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 288 | |
Gavin Howard | 31065f5 | 2019-02-06 15:22:45 -0700 | [diff] [blame] | 289 | err: |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 290 | fclose(out); |
Gavin Howard | d571acf | 2018-02-20 17:13:07 -0700 | [diff] [blame] | 291 | out_err: |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 292 | fclose(in); |
Gavin Howard | 2b6631f | 2018-12-13 17:35:08 -0700 | [diff] [blame] | 293 | return err; |
Gavin Howard | f833399 | 2018-02-19 13:55:25 -0700 | [diff] [blame] | 294 | } |