13aa99676SStefan Eßer /* 23aa99676SStefan Eßer * ***************************************************************************** 33aa99676SStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 53aa99676SStefan Eßer * 6*a970610aSStefan Eßer * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 73aa99676SStefan Eßer * 83aa99676SStefan Eßer * Redistribution and use in source and binary forms, with or without 93aa99676SStefan Eßer * modification, are permitted provided that the following conditions are met: 103aa99676SStefan Eßer * 113aa99676SStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 123aa99676SStefan Eßer * list of conditions and the following disclaimer. 133aa99676SStefan Eßer * 143aa99676SStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 153aa99676SStefan Eßer * this list of conditions and the following disclaimer in the documentation 163aa99676SStefan Eßer * and/or other materials provided with the distribution. 173aa99676SStefan Eßer * 183aa99676SStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 193aa99676SStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 203aa99676SStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 213aa99676SStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 223aa99676SStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 233aa99676SStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 243aa99676SStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 253aa99676SStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 263aa99676SStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 273aa99676SStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 283aa99676SStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 293aa99676SStefan Eßer * 303aa99676SStefan Eßer * ***************************************************************************** 313aa99676SStefan Eßer * 323aa99676SStefan Eßer * Generates a const array from a bc script. 333aa99676SStefan Eßer * 343aa99676SStefan Eßer */ 353aa99676SStefan Eßer 3678bc019dSStefan Eßer #include <assert.h> 373aa99676SStefan Eßer #include <stdbool.h> 383aa99676SStefan Eßer #include <stdio.h> 393aa99676SStefan Eßer #include <stdlib.h> 403aa99676SStefan Eßer #include <string.h> 413aa99676SStefan Eßer 423aa99676SStefan Eßer #include <errno.h> 433aa99676SStefan Eßer 4478bc019dSStefan Eßer #include <fcntl.h> 4578bc019dSStefan Eßer #include <sys/stat.h> 4678bc019dSStefan Eßer 4778bc019dSStefan Eßer #ifndef _WIN32 4878bc019dSStefan Eßer #include <unistd.h> 4978bc019dSStefan Eßer #endif // _WIN32 5078bc019dSStefan Eßer 5178bc019dSStefan Eßer // For some reason, Windows can't have this header. 527e5c51e5SStefan Eßer #ifndef _WIN32 533aa99676SStefan Eßer #include <libgen.h> 547e5c51e5SStefan Eßer #endif // _WIN32 553aa99676SStefan Eßer 5678bc019dSStefan Eßer // This pulls in cross-platform stuff. 57d101cdd6SStefan Eßer #include <status.h> 5878bc019dSStefan Eßer 5978bc019dSStefan Eßer // clang-format off 6078bc019dSStefan Eßer 6178bc019dSStefan Eßer // The usage help. 6278bc019dSStefan Eßer static const char* const bc_gen_usage = 6378bc019dSStefan Eßer "usage: %s input output exclude name [label [define [remove_tabs]]]\n"; 6478bc019dSStefan Eßer 6578bc019dSStefan Eßer static const char* const bc_gen_ex_start = "{{ A H N HN }}"; 6678bc019dSStefan Eßer static const char* const bc_gen_ex_end = "{{ end }}"; 6778bc019dSStefan Eßer 6844d4804dSStefan Eßer // This is exactly what it looks like. It just slaps a simple license header on 6944d4804dSStefan Eßer // the generated C source file. 703aa99676SStefan Eßer static const char* const bc_gen_header = 71*a970610aSStefan Eßer "// Copyright (c) 2018-2024 Gavin D. Howard and contributors.\n" 723aa99676SStefan Eßer "// Licensed under the 2-clause BSD license.\n" 7350696a6eSStefan Eßer "// *** AUTOMATICALLY GENERATED FROM %s. DO NOT MODIFY. ***\n\n"; 7478bc019dSStefan Eßer // clang-format on 753aa99676SStefan Eßer 7644d4804dSStefan Eßer // These are just format strings used to generate the C source. 773aa99676SStefan Eßer static const char* const bc_gen_label = "const char *%s = \"%s\";\n\n"; 7850696a6eSStefan Eßer static const char* const bc_gen_label_extern = "extern const char *%s;\n\n"; 793aa99676SStefan Eßer static const char* const bc_gen_ifdef = "#if %s\n"; 803aa99676SStefan Eßer static const char* const bc_gen_endif = "#endif // %s\n"; 813aa99676SStefan Eßer static const char* const bc_gen_name = "const char %s[] = {\n"; 8250696a6eSStefan Eßer static const char* const bc_gen_name_extern = "extern const char %s[];\n\n"; 833aa99676SStefan Eßer 8444d4804dSStefan Eßer // Error codes. We can't use 0 because these are used as exit statuses, and 0 8544d4804dSStefan Eßer // as an exit status is not an error. 863aa99676SStefan Eßer #define IO_ERR (1) 873aa99676SStefan Eßer #define INVALID_INPUT_FILE (2) 883aa99676SStefan Eßer #define INVALID_PARAMS (3) 893aa99676SStefan Eßer 9044d4804dSStefan Eßer // This is the max width to print characters to the screen. This is to ensure 9144d4804dSStefan Eßer // that lines don't go much over 80 characters. 9244d4804dSStefan Eßer #define MAX_WIDTH (72) 933aa99676SStefan Eßer 9444d4804dSStefan Eßer /** 9544d4804dSStefan Eßer * Open a file. This function is to smooth over differences between POSIX and 9644d4804dSStefan Eßer * Windows. 9744d4804dSStefan Eßer * @param f A pointer to the FILE pointer that will be initialized. 9844d4804dSStefan Eßer * @param filename The name of the file. 9944d4804dSStefan Eßer * @param mode The mode to open the file in. 10044d4804dSStefan Eßer */ 10178bc019dSStefan Eßer static void 10278bc019dSStefan Eßer open_file(FILE** f, const char* filename, const char* mode) 10378bc019dSStefan Eßer { 1047e5c51e5SStefan Eßer #ifndef _WIN32 10544d4804dSStefan Eßer 1067e5c51e5SStefan Eßer *f = fopen(filename, mode); 10744d4804dSStefan Eßer 1087e5c51e5SStefan Eßer #else // _WIN32 10944d4804dSStefan Eßer 11044d4804dSStefan Eßer // We want the file pointer to be NULL on failure, but fopen_s() is not 11144d4804dSStefan Eßer // guaranteed to set it. 1127e5c51e5SStefan Eßer *f = NULL; 1137e5c51e5SStefan Eßer fopen_s(f, filename, mode); 11444d4804dSStefan Eßer 1157e5c51e5SStefan Eßer #endif // _WIN32 1167e5c51e5SStefan Eßer } 1177e5c51e5SStefan Eßer 11844d4804dSStefan Eßer /** 11978bc019dSStefan Eßer * A portability file open function. This is copied from src/read.c. Make sure 12078bc019dSStefan Eßer * to update that if this changes. 12178bc019dSStefan Eßer * @param path The path to the file to open. 12278bc019dSStefan Eßer * @param mode The mode to open in. 12378bc019dSStefan Eßer */ 12478bc019dSStefan Eßer static int 12578bc019dSStefan Eßer bc_read_open(const char* path, int mode) 12678bc019dSStefan Eßer { 12778bc019dSStefan Eßer int fd; 12878bc019dSStefan Eßer 12978bc019dSStefan Eßer #ifndef _WIN32 13078bc019dSStefan Eßer fd = open(path, mode); 13178bc019dSStefan Eßer #else // _WIN32 13278bc019dSStefan Eßer fd = -1; 13378bc019dSStefan Eßer open(&fd, path, mode); 13478bc019dSStefan Eßer #endif 13578bc019dSStefan Eßer 13678bc019dSStefan Eßer return fd; 13778bc019dSStefan Eßer } 13878bc019dSStefan Eßer 13978bc019dSStefan Eßer /** 14078bc019dSStefan Eßer * Reads a file and returns the file as a string. This has been copied from 14178bc019dSStefan Eßer * src/read.c. Make sure to change that if this changes. 14278bc019dSStefan Eßer * @param path The path to the file. 14378bc019dSStefan Eßer * @return The contents of the file as a string. 14478bc019dSStefan Eßer */ 14578bc019dSStefan Eßer static char* 14678bc019dSStefan Eßer bc_read_file(const char* path) 14778bc019dSStefan Eßer { 14878bc019dSStefan Eßer int e = IO_ERR; 14978bc019dSStefan Eßer size_t size, to_read; 15078bc019dSStefan Eßer struct stat pstat; 15178bc019dSStefan Eßer int fd; 15278bc019dSStefan Eßer char* buf; 15378bc019dSStefan Eßer char* buf2; 15478bc019dSStefan Eßer 15578bc019dSStefan Eßer // This has been copied from src/read.c. Make sure to change that if this 15678bc019dSStefan Eßer // changes. 15778bc019dSStefan Eßer 15878bc019dSStefan Eßer assert(path != NULL); 15978bc019dSStefan Eßer 160103d7cdfSStefan Eßer #if BC_DEBUG 16178bc019dSStefan Eßer // Need this to quiet MSan. 16278bc019dSStefan Eßer // NOLINTNEXTLINE 16378bc019dSStefan Eßer memset(&pstat, 0, sizeof(struct stat)); 164103d7cdfSStefan Eßer #endif // BC_DEBUG 16578bc019dSStefan Eßer 16678bc019dSStefan Eßer fd = bc_read_open(path, O_RDONLY); 16778bc019dSStefan Eßer 16878bc019dSStefan Eßer // If we can't read a file, we just barf. 16978bc019dSStefan Eßer if (BC_ERR(fd < 0)) 17078bc019dSStefan Eßer { 17178bc019dSStefan Eßer fprintf(stderr, "Could not open file: %s\n", path); 17278bc019dSStefan Eßer exit(INVALID_INPUT_FILE); 17378bc019dSStefan Eßer } 17478bc019dSStefan Eßer 17578bc019dSStefan Eßer // The reason we call fstat is to eliminate TOCTOU race conditions. This 17678bc019dSStefan Eßer // way, we have an open file, so it's not going anywhere. 17778bc019dSStefan Eßer if (BC_ERR(fstat(fd, &pstat) == -1)) 17878bc019dSStefan Eßer { 17978bc019dSStefan Eßer fprintf(stderr, "Could not stat file: %s\n", path); 18078bc019dSStefan Eßer exit(INVALID_INPUT_FILE); 18178bc019dSStefan Eßer } 18278bc019dSStefan Eßer 18378bc019dSStefan Eßer // Make sure it's not a directory. 18478bc019dSStefan Eßer if (BC_ERR(S_ISDIR(pstat.st_mode))) 18578bc019dSStefan Eßer { 18678bc019dSStefan Eßer fprintf(stderr, "Path is directory: %s\n", path); 18778bc019dSStefan Eßer exit(INVALID_INPUT_FILE); 18878bc019dSStefan Eßer } 18978bc019dSStefan Eßer 19078bc019dSStefan Eßer // Get the size of the file and allocate that much. 19178bc019dSStefan Eßer size = (size_t) pstat.st_size; 19278bc019dSStefan Eßer buf = (char*) malloc(size + 1); 19378bc019dSStefan Eßer if (buf == NULL) 19478bc019dSStefan Eßer { 19578bc019dSStefan Eßer fprintf(stderr, "Could not malloc\n"); 19678bc019dSStefan Eßer exit(INVALID_INPUT_FILE); 19778bc019dSStefan Eßer } 19878bc019dSStefan Eßer buf2 = buf; 19978bc019dSStefan Eßer to_read = size; 20078bc019dSStefan Eßer 20178bc019dSStefan Eßer do 20278bc019dSStefan Eßer { 20378bc019dSStefan Eßer // Read the file. We just bail if a signal interrupts. This is so that 20478bc019dSStefan Eßer // users can interrupt the reading of big files if they want. 20578bc019dSStefan Eßer ssize_t r = read(fd, buf2, to_read); 20678bc019dSStefan Eßer if (BC_ERR(r < 0)) exit(e); 20778bc019dSStefan Eßer to_read -= (size_t) r; 20878bc019dSStefan Eßer buf2 += (size_t) r; 20978bc019dSStefan Eßer } 21078bc019dSStefan Eßer while (to_read); 21178bc019dSStefan Eßer 21278bc019dSStefan Eßer // Got to have a nul byte. 21378bc019dSStefan Eßer buf[size] = '\0'; 21478bc019dSStefan Eßer 21578bc019dSStefan Eßer close(fd); 21678bc019dSStefan Eßer 21778bc019dSStefan Eßer return buf; 21878bc019dSStefan Eßer } 21978bc019dSStefan Eßer 22078bc019dSStefan Eßer /** 22144d4804dSStefan Eßer * Outputs a label, which is a string literal that the code can use as a name 22244d4804dSStefan Eßer * for the file that is being turned into a string. This is important for the 22344d4804dSStefan Eßer * math libraries because the parse and lex code expects a filename. The label 22444d4804dSStefan Eßer * becomes the filename for the purposes of lexing and parsing. 22544d4804dSStefan Eßer * 22644d4804dSStefan Eßer * The label is generated from bc_gen_label (above). It has the form: 22744d4804dSStefan Eßer * 22844d4804dSStefan Eßer * const char *<label_name> = <label>; 22944d4804dSStefan Eßer * 23044d4804dSStefan Eßer * This function is also needed to smooth out differences between POSIX and 23144d4804dSStefan Eßer * Windows, specifically, the fact that Windows uses backslashes for filenames 23244d4804dSStefan Eßer * and that backslashes have to be escaped in a string literal. 23344d4804dSStefan Eßer * 23444d4804dSStefan Eßer * @param out The file to output to. 23544d4804dSStefan Eßer * @param label The label name. 23644d4804dSStefan Eßer * @param name The actual label text, which is a filename. 23744d4804dSStefan Eßer * @return Positive if no error, negative on error, just like *printf(). 23844d4804dSStefan Eßer */ 23978bc019dSStefan Eßer static int 24078bc019dSStefan Eßer output_label(FILE* out, const char* label, const char* name) 24178bc019dSStefan Eßer { 2427e5c51e5SStefan Eßer #ifndef _WIN32 24344d4804dSStefan Eßer 2447e5c51e5SStefan Eßer return fprintf(out, bc_gen_label, label, name); 24544d4804dSStefan Eßer 2467e5c51e5SStefan Eßer #else // _WIN32 2477e5c51e5SStefan Eßer 2487e5c51e5SStefan Eßer size_t i, count = 0, len = strlen(name); 2497e5c51e5SStefan Eßer char* buf; 2507e5c51e5SStefan Eßer int ret; 2517e5c51e5SStefan Eßer 25244d4804dSStefan Eßer // This loop counts how many backslashes there are in the label. 25378bc019dSStefan Eßer for (i = 0; i < len; ++i) 25478bc019dSStefan Eßer { 25578bc019dSStefan Eßer count += (name[i] == '\\'); 25678bc019dSStefan Eßer } 2577e5c51e5SStefan Eßer 2587e5c51e5SStefan Eßer buf = (char*) malloc(len + 1 + count); 2597e5c51e5SStefan Eßer if (buf == NULL) return -1; 2607e5c51e5SStefan Eßer 2617e5c51e5SStefan Eßer count = 0; 2627e5c51e5SStefan Eßer 26344d4804dSStefan Eßer // This loop is the meat of the Windows version. What it does is copy the 26444d4804dSStefan Eßer // label byte-for-byte, unless it encounters a backslash, in which case, it 26544d4804dSStefan Eßer // copies the backslash twice to have it escaped properly in the string 26644d4804dSStefan Eßer // literal. 26778bc019dSStefan Eßer for (i = 0; i < len; ++i) 26878bc019dSStefan Eßer { 2697e5c51e5SStefan Eßer buf[i + count] = name[i]; 27044d4804dSStefan Eßer 27178bc019dSStefan Eßer if (name[i] == '\\') 27278bc019dSStefan Eßer { 2737e5c51e5SStefan Eßer count += 1; 2747e5c51e5SStefan Eßer buf[i + count] = name[i]; 2757e5c51e5SStefan Eßer } 2767e5c51e5SStefan Eßer } 2777e5c51e5SStefan Eßer 2787e5c51e5SStefan Eßer buf[i + count] = '\0'; 2797e5c51e5SStefan Eßer 2807e5c51e5SStefan Eßer ret = fprintf(out, bc_gen_label, label, buf); 2817e5c51e5SStefan Eßer 2827e5c51e5SStefan Eßer free(buf); 2837e5c51e5SStefan Eßer 2847e5c51e5SStefan Eßer return ret; 2857e5c51e5SStefan Eßer 2867e5c51e5SStefan Eßer #endif // _WIN32 2877e5c51e5SStefan Eßer } 2887e5c51e5SStefan Eßer 28944d4804dSStefan Eßer /** 29044d4804dSStefan Eßer * This program generates C strings (well, actually, C char arrays) from text 29144d4804dSStefan Eßer * files. It generates 1 C source file. The resulting file has this structure: 29244d4804dSStefan Eßer * 29344d4804dSStefan Eßer * <Copyright Header> 29444d4804dSStefan Eßer * 29544d4804dSStefan Eßer * [<Label Extern>] 29644d4804dSStefan Eßer * 29744d4804dSStefan Eßer * <Char Array Extern> 29844d4804dSStefan Eßer * 29944d4804dSStefan Eßer * [<Preprocessor Guard Begin>] 30044d4804dSStefan Eßer * [<Label Definition>] 30144d4804dSStefan Eßer * 30244d4804dSStefan Eßer * <Char Array Definition> 30344d4804dSStefan Eßer * [<Preprocessor Guard End>] 30444d4804dSStefan Eßer * 30544d4804dSStefan Eßer * Anything surrounded by square brackets may not be in the final generated 30644d4804dSStefan Eßer * source file. 30744d4804dSStefan Eßer * 30844d4804dSStefan Eßer * The required command-line parameters are: 30944d4804dSStefan Eßer * 31044d4804dSStefan Eßer * input Input filename. 31144d4804dSStefan Eßer * output Output filename. 31278bc019dSStefan Eßer * exclude Whether to exclude extra math-only stuff. 31344d4804dSStefan Eßer * name The name of the char array. 31444d4804dSStefan Eßer * 31544d4804dSStefan Eßer * The optional parameters are: 31644d4804dSStefan Eßer * 31744d4804dSStefan Eßer * label If given, a label for the char array. See the comment for the 31844d4804dSStefan Eßer * output_label() function. It is meant as a "filename" for the 31944d4804dSStefan Eßer * text when processed by bc and dc. If label is given, then the 32044d4804dSStefan Eßer * <Label Extern> and <Label Definition> will exist in the 32144d4804dSStefan Eßer * generated source file. 32244d4804dSStefan Eßer * define If given, a preprocessor macro that should be used as a guard 32344d4804dSStefan Eßer * for the char array and its label. If define is given, then 32444d4804dSStefan Eßer * <Preprocessor Guard Begin> will exist in the form 32544d4804dSStefan Eßer * "#if <define>" as part of the generated source file, and 32644d4804dSStefan Eßer * <Preprocessor Guard End> will exist in the form 32744d4804dSStefan Eßer * "endif // <define>". 32844d4804dSStefan Eßer * remove_tabs If this parameter exists, it must be an integer. If it is 32944d4804dSStefan Eßer * non-zero, then tabs are removed from the input file text before 33044d4804dSStefan Eßer * outputting to the output char array. 33144d4804dSStefan Eßer * 33244d4804dSStefan Eßer * All text files that are transformed have license comments. This program finds 33344d4804dSStefan Eßer * the end of that comment and strips it out as well. 33444d4804dSStefan Eßer */ 33578bc019dSStefan Eßer int 33678bc019dSStefan Eßer main(int argc, char* argv[]) 33778bc019dSStefan Eßer { 33878bc019dSStefan Eßer char* in; 33978bc019dSStefan Eßer FILE* out; 34078bc019dSStefan Eßer const char* label; 34178bc019dSStefan Eßer const char* define; 34278bc019dSStefan Eßer char* name; 34378bc019dSStefan Eßer unsigned int count, slashes, err = IO_ERR; 34478bc019dSStefan Eßer bool has_label, has_define, remove_tabs, exclude_extra_math; 34578bc019dSStefan Eßer size_t i; 3463aa99676SStefan Eßer 34778bc019dSStefan Eßer if (argc < 5) 34878bc019dSStefan Eßer { 34978bc019dSStefan Eßer printf(bc_gen_usage, argv[0]); 3503aa99676SStefan Eßer return INVALID_PARAMS; 3513aa99676SStefan Eßer } 3523aa99676SStefan Eßer 35378bc019dSStefan Eßer exclude_extra_math = (strtoul(argv[3], NULL, 10) != 0); 3543aa99676SStefan Eßer 35578bc019dSStefan Eßer name = argv[4]; 3563aa99676SStefan Eßer 35778bc019dSStefan Eßer has_label = (argc > 5 && strcmp("", argv[5]) != 0); 35878bc019dSStefan Eßer label = has_label ? argv[5] : ""; 3593aa99676SStefan Eßer 36078bc019dSStefan Eßer has_define = (argc > 6 && strcmp("", argv[6]) != 0); 36178bc019dSStefan Eßer define = has_define ? argv[6] : ""; 3623aa99676SStefan Eßer 363103d7cdfSStefan Eßer remove_tabs = (argc > 7 && atoi(argv[7]) != 0); 36478bc019dSStefan Eßer 36578bc019dSStefan Eßer in = bc_read_file(argv[1]); 36678bc019dSStefan Eßer if (in == NULL) return INVALID_INPUT_FILE; 3673aa99676SStefan Eßer 3687e5c51e5SStefan Eßer open_file(&out, argv[2], "w"); 36978bc019dSStefan Eßer if (out == NULL) goto out_err; 3703aa99676SStefan Eßer 3713aa99676SStefan Eßer if (fprintf(out, bc_gen_header, argv[1]) < 0) goto err; 37250696a6eSStefan Eßer if (has_label && fprintf(out, bc_gen_label_extern, label) < 0) goto err; 37350696a6eSStefan Eßer if (fprintf(out, bc_gen_name_extern, name) < 0) goto err; 3743aa99676SStefan Eßer if (has_define && fprintf(out, bc_gen_ifdef, define) < 0) goto err; 3757e5c51e5SStefan Eßer if (has_label && output_label(out, label, argv[1]) < 0) goto err; 3763aa99676SStefan Eßer if (fprintf(out, bc_gen_name, name) < 0) goto err; 3773aa99676SStefan Eßer 37878bc019dSStefan Eßer i = count = slashes = 0; 3793aa99676SStefan Eßer 38044d4804dSStefan Eßer // This is where the end of the license comment is found. 38178bc019dSStefan Eßer while (slashes < 2 && in[i] > 0) 38278bc019dSStefan Eßer { 38378bc019dSStefan Eßer if (slashes == 1 && in[i] == '*' && in[i + 1] == '/' && 38478bc019dSStefan Eßer (in[i + 2] == '\n' || in[i + 2] == '\r')) 38578bc019dSStefan Eßer { 38678bc019dSStefan Eßer slashes += 1; 38778bc019dSStefan Eßer i += 2; 38878bc019dSStefan Eßer } 38978bc019dSStefan Eßer else if (!slashes && in[i] == '/' && in[i + 1] == '*') 39078bc019dSStefan Eßer { 39178bc019dSStefan Eßer slashes += 1; 39278bc019dSStefan Eßer i += 1; 39378bc019dSStefan Eßer } 39478bc019dSStefan Eßer 39578bc019dSStefan Eßer i += 1; 3963aa99676SStefan Eßer } 3973aa99676SStefan Eßer 39844d4804dSStefan Eßer // The file is invalid if the end of the license comment could not be found. 39978bc019dSStefan Eßer if (in[i] == 0) 40078bc019dSStefan Eßer { 40178bc019dSStefan Eßer fprintf(stderr, "Could not find end of license comment\n"); 4023aa99676SStefan Eßer err = INVALID_INPUT_FILE; 4033aa99676SStefan Eßer goto err; 4043aa99676SStefan Eßer } 4053aa99676SStefan Eßer 40678bc019dSStefan Eßer i += 1; 40778bc019dSStefan Eßer 40844d4804dSStefan Eßer // Do not put extra newlines at the beginning of the char array. 40978bc019dSStefan Eßer while (in[i] == '\n' || in[i] == '\r') 41078bc019dSStefan Eßer { 41178bc019dSStefan Eßer i += 1; 41278bc019dSStefan Eßer } 4133aa99676SStefan Eßer 41444d4804dSStefan Eßer // This loop is what generates the actual char array. It counts how many 41544d4804dSStefan Eßer // chars it has printed per line in order to insert newlines at appropriate 41644d4804dSStefan Eßer // places. It also skips tabs if they should be removed. 41778bc019dSStefan Eßer while (in[i] != 0) 41878bc019dSStefan Eßer { 4193aa99676SStefan Eßer int val; 4203aa99676SStefan Eßer 42178bc019dSStefan Eßer if (in[i] == '\r') 42278bc019dSStefan Eßer { 42378bc019dSStefan Eßer i += 1; 42478bc019dSStefan Eßer continue; 42578bc019dSStefan Eßer } 4263aa99676SStefan Eßer 42778bc019dSStefan Eßer if (!remove_tabs || in[i] != '\t') 42878bc019dSStefan Eßer { 42978bc019dSStefan Eßer // Check for excluding something for extra math. 43078bc019dSStefan Eßer if (in[i] == '{') 43178bc019dSStefan Eßer { 43278bc019dSStefan Eßer // If we found the start... 43378bc019dSStefan Eßer if (!strncmp(in + i, bc_gen_ex_start, strlen(bc_gen_ex_start))) 43478bc019dSStefan Eßer { 43578bc019dSStefan Eßer if (exclude_extra_math) 43678bc019dSStefan Eßer { 43778bc019dSStefan Eßer // Get past the braces. 43878bc019dSStefan Eßer i += 2; 43978bc019dSStefan Eßer 44078bc019dSStefan Eßer // Find the end of the end. 44178bc019dSStefan Eßer while (in[i] != '{' && strncmp(in + i, bc_gen_ex_end, 44278bc019dSStefan Eßer strlen(bc_gen_ex_end))) 44378bc019dSStefan Eßer { 44478bc019dSStefan Eßer i += 1; 44578bc019dSStefan Eßer } 44678bc019dSStefan Eßer 44778bc019dSStefan Eßer i += strlen(bc_gen_ex_end); 44878bc019dSStefan Eßer 44978bc019dSStefan Eßer // Skip the last newline. 45078bc019dSStefan Eßer if (in[i] == '\r') i += 1; 45178bc019dSStefan Eßer i += 1; 45278bc019dSStefan Eßer continue; 45378bc019dSStefan Eßer } 45478bc019dSStefan Eßer else 45578bc019dSStefan Eßer { 45678bc019dSStefan Eßer i += strlen(bc_gen_ex_start); 45778bc019dSStefan Eßer 45878bc019dSStefan Eßer // Skip the last newline. 45978bc019dSStefan Eßer if (in[i] == '\r') i += 1; 46078bc019dSStefan Eßer i += 1; 46178bc019dSStefan Eßer continue; 46278bc019dSStefan Eßer } 46378bc019dSStefan Eßer } 46478bc019dSStefan Eßer else if (!exclude_extra_math && 46578bc019dSStefan Eßer !strncmp(in + i, bc_gen_ex_end, strlen(bc_gen_ex_end))) 46678bc019dSStefan Eßer { 46778bc019dSStefan Eßer i += strlen(bc_gen_ex_end); 46878bc019dSStefan Eßer 46978bc019dSStefan Eßer // Skip the last newline. 47078bc019dSStefan Eßer if (in[i] == '\r') i += 1; 47178bc019dSStefan Eßer i += 1; 47278bc019dSStefan Eßer continue; 47378bc019dSStefan Eßer } 47478bc019dSStefan Eßer } 47578bc019dSStefan Eßer 47678bc019dSStefan Eßer // Print a tab if we are at the beginning of a line. 4773aa99676SStefan Eßer if (!count && fputc('\t', out) == EOF) goto err; 4783aa99676SStefan Eßer 47978bc019dSStefan Eßer // Print the character. 48078bc019dSStefan Eßer val = fprintf(out, "%d,", in[i]); 4813aa99676SStefan Eßer if (val < 0) goto err; 4823aa99676SStefan Eßer 48378bc019dSStefan Eßer // Adjust the count. 48478bc019dSStefan Eßer count += (unsigned int) val; 48578bc019dSStefan Eßer if (count > MAX_WIDTH) 48678bc019dSStefan Eßer { 4873aa99676SStefan Eßer count = 0; 4883aa99676SStefan Eßer if (fputc('\n', out) == EOF) goto err; 4893aa99676SStefan Eßer } 4903aa99676SStefan Eßer } 4913aa99676SStefan Eßer 49278bc019dSStefan Eßer i += 1; 4933aa99676SStefan Eßer } 4943aa99676SStefan Eßer 49544d4804dSStefan Eßer // Make sure the end looks nice and insert the NUL byte at the end. 4963aa99676SStefan Eßer if (!count && (fputc(' ', out) == EOF || fputc(' ', out) == EOF)) goto err; 4973aa99676SStefan Eßer if (fprintf(out, "0\n};\n") < 0) goto err; 4983aa99676SStefan Eßer 4993aa99676SStefan Eßer err = (has_define && fprintf(out, bc_gen_endif, define) < 0); 5003aa99676SStefan Eßer 5013aa99676SStefan Eßer err: 5023aa99676SStefan Eßer fclose(out); 5033aa99676SStefan Eßer out_err: 50478bc019dSStefan Eßer free(in); 50578bc019dSStefan Eßer return (int) err; 5063aa99676SStefan Eßer } 507