/* * 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 uint64_t alloc_count; static long memdbg; static int hook_alloc(void) { alloc_count++; if((memdbg >= 0) && (alloc_count > ((uint64_t)memdbg))) return 0; else return 1; } static void * my_malloc(size_t size) { if(!hook_alloc()) return NULL; return malloc(size); } static void * my_alloc(size_t min, size_t max, size_t *actual) { size_t target = min; void *p; 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++; } if(max && (target > max)) target = max; p = my_malloc(target); if((p == NULL) && (min < target)){ target = min; p = my_malloc(target); } *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; FILE *f; aplwc_clear_line(&line); aplwc_clear_value(&value); input = NULL; xflag = 0; input_file = 0; exit_code = 0; line_number = 0; memdbg = getenv_long("APLWC_ALLOC_FAIL_AFTER", -2); memset(&fns, 0, sizeof(fns)); fns.alloc = my_alloc; fns.dealloc = my_dealloc; fns.hook_alloc = hook_alloc; 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(fseek(f, 0, SEEK_END)){ file_size: fprintf(stderr, "Failed to determine file size\n"); exit_code = 1; goto end; } tmp = ftell(f); if(tmp < 0) goto file_size; input_size = tmp; rewind(f); input = malloc(input_size); if(input == NULL){ fprintf(stderr, "Failed to allocate space for file contents\n"); exit_code = 1; goto end; } if(fread(input, 1, input_size, f) < 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: ret = aplwc_last_error(aplwc); fprintf(stderr, "error on line %d: %s: %s\n", line_number, aplwc_errstr(aplwc), input); if(input_file){ exit_code = 1; goto end; } 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(aplwc_valid_line(&line)) aplwc_free_line(&line); if(aplwc_valid_value(&value)) aplwc_free_value(&value); if(aplwc) aplwc_destroy(aplwc); if(memdbg == -1){ f = fdopen(3, "w"); if(f == NULL){ fprintf(stderr, "Failed to open fd 3\n"); exit_code = 1; }else{ fprintf(f, "%ld\n", alloc_count); fclose(f); } } if((exit_code != 0) && (memdbg >= 0) && (ret == APLWC_OUT_OF_MEMORY)) exit_code = 0; return exit_code; }