/* * Copyright (C) 2026 Peter Mikkelsen * * This file is part of aplwc. * * Aplwc is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Aplwc is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with aplwc. If not, see . */ #define _POSIX_C_SOURCE 200809L #include #include #include #include "aplwc_repl.h" static void * my_alloc(size_t size, size_t *actual) { size_t target = size; void *p; int fail2; if(actual){ if(NEVER(target == 0)) target = 1; else{ target--; target |= target >> 1; target |= target >> 2; target |= target >> 4; target |= target >> 8; target |= target >> 16; target |= target >> 32; target++; } } fail2 = aplwc_simulate_failure(); p = FAILCASE(malloc(target), NULL); if((p == NULL) && (size < target)){ target = size; p = FAILCASE_X(malloc(target), NULL, fail2); } if(actual) *actual = target; return p; } static void my_dealloc(void *p) { free(p); } int main(int argc, char *argv[]) { struct aplwc_fns fns; struct aplwc *aplwc; enum aplwc_rc ret; AplwcLine line; AplwcValue value; char *input, *src; int exit_code, line_number; size_t input_size, src_size, i; int opt, xflag, input_file; long tmp; unsigned long print_failsims; FILE *f; aplwc_clear_line(&line); aplwc_clear_value(&value); input = NULL; xflag = 0; input_file = 0; exit_code = 0; line_number = 0; aplwc = NULL; aplwc_simulate_failure_at = getenv_ulong("APLWC_SIMULATE_FAILURE_AT", 0); print_failsims = getenv_ulong("APLWC_SIMULATE_FAILURE_PRINT_COUNT", 0); memset(&fns, 0, sizeof(fns)); fns.alloc = my_alloc; fns.dealloc = my_dealloc; while((opt = getopt(argc, argv, "x")) != -1){ switch(opt){ case 'x': xflag = 1; break; default: usage: fprintf(stderr, "Usage: %s [-x] [file]\n", argv[0]); exit_code = 1; goto end; } } if((optind+1) == argc){ input_file = 1; f = fopen(argv[optind], "r"); if(f == NULL){ fprintf(stderr, "Could not open file: %s: %s\n", argv[optind], strerror(errno)); exit_code = 1; goto end; } }else if(optind == argc) f = stdin; else goto usage; aplwc = aplwc_new(fns, &ret); if(ret){ fprintf(stderr, "Couldn't create new aplwc instance: %s\n", aplwc_errstr_rc(ret)); exit_code = 1; goto end; } if(input_file){ if(FAILCASE(fseek(f, 0, SEEK_END), -1)){ file_size: fprintf(stderr, "Failed to determine file size\n"); exit_code = 1; goto end; } tmp = FAILCASE(ftell(f), -1); if(tmp < 0) goto file_size; input_size = tmp; rewind(f); input = FAILCASE(malloc(input_size), NULL); if(input == NULL){ fprintf(stderr, "Failed to allocate space for file contents\n"); exit_code = 1; goto end; } if(FAILCASE(fread(input, 1, input_size, f), 0) < input_size){ fprintf(stderr, "Failed to read file contents\n"); exit_code = 1; goto end; } fclose(f); src = input; src_size = input_size; if((input_size > 2) && (input[0] == '#') && (input[1] == '!')){ for(i = 0; i < input_size; i++){ if(input[i] == '\n'){ src += i; src_size -= i; xflag = 1; break; } } } ret = aplwc_load_module(aplwc, "Main", src, src_size); if(ret){ fprintf(stderr, "Couldn't load Main module from file %s: %s\n", argv[optind], aplwc_errstr_rc(ret)); exit_code = 1; goto end; } free(input); input = NULL; } if(xflag) goto end; for(;;){ if(input) free(input); if(aplwc_valid_line(&line)) aplwc_free_line(&line); if(aplwc_valid_value(&value)) aplwc_free_value(&value); input = NULL; if(getline(&input, &input_size, stdin) < 0){ free(input); input = NULL; break; }else{ line_number++; aplwc_read(aplwc, input, &line); if(!aplwc_valid_line(&line)){ line_error: fprintf(stderr, "error on line %d: %s: %s\n", line_number, aplwc_errstr(aplwc), input); continue; } aplwc_eval(&line, &value); if(!aplwc_valid_value(&value)) goto line_error; fprintf(stdout, "%s\n", aplwc_value_string(&value)); } } end: if(input) free(input); if(NEVER(aplwc_valid_line(&line))) aplwc_free_line(&line); if(NEVER(aplwc_valid_value(&value))) aplwc_free_value(&value); if(aplwc) aplwc_destroy(aplwc); if(print_failsims){ f = fdopen(3, "w"); if(f == NULL){ fprintf(stderr, "Failed to open fd 3\n"); exit_code = 1; }else{ fprintf(f, "%ld\n", aplwc_simulate_failure_count); fclose(f); } } if((exit_code != 0) && aplwc_simulate_failure_at && (aplwc_simulate_failure_count >= aplwc_simulate_failure_at)) exit_code = 0; return exit_code; }