1 /* 2 * parser.c 3 * rfc822 message parser 4 * 5 * SPDX-License-Identifier: pkgconf 6 * 7 * Copyright (c) 2018, 2025 pkgconf authors (see AUTHORS). 8 * 9 * Permission to use, copy, modify, and/or distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * This software is provided 'as is' and without any warranty, express or 14 * implied. In no event shall the authors be liable for any damages arising 15 * from the use of this software. 16 */ 17 18 #include <libpkgconf/config.h> 19 #include <libpkgconf/stdinc.h> 20 #include <libpkgconf/libpkgconf.h> 21 22 static void 23 pkgconf_parser_canonicalize_line(pkgconf_buffer_t *buffer) 24 { 25 bool escaped = false; 26 char *buf = buffer->base; 27 char *src = buf, *dst = buf; 28 29 if (buf == NULL) 30 return; 31 32 for (; *src != '\0'; src++) 33 { 34 if (*src == '\\' && !escaped) 35 { 36 escaped = true; 37 continue; 38 } 39 40 if (*src == '#' && !escaped) 41 break; 42 43 if (escaped) 44 { 45 if (*src == '#') 46 { 47 *dst++ = '#'; 48 escaped = false; 49 continue; 50 } 51 52 *dst++ = '\\'; 53 escaped = false; 54 } 55 56 *dst++ = *src; 57 } 58 59 if (escaped) 60 *dst++ = '\\'; 61 62 *dst = '\0'; 63 buffer->end = dst; 64 } 65 66 void 67 pkgconf_parser_parse_buffer(void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, pkgconf_buffer_t *buffer, const char *warnprefix) 68 { 69 char op, *p, *key, *value; 70 size_t vallen; 71 72 pkgconf_parser_canonicalize_line(buffer); 73 74 p = buffer->base; 75 if (p == NULL) 76 return; 77 while (*p && isspace((unsigned char)*p)) 78 p++; 79 if (*p && p != buffer->base) 80 { 81 warnfunc(data, "%s: warning: whitespace encountered while parsing key section\n", 82 warnprefix); 83 } 84 key = p; 85 while (*p && (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || *p == '_' || *p == '.')) 86 p++; 87 88 if (!isalpha((unsigned char)*key) && !isdigit((unsigned char)*key)) 89 return; 90 91 while (*p && isspace((unsigned char)*p)) 92 { 93 warnfunc(data, "%s: warning: whitespace encountered while parsing key section\n", 94 warnprefix); 95 96 /* set to null to avoid trailing spaces in key */ 97 *p = '\0'; 98 p++; 99 } 100 101 op = *p; 102 if (*p != '\0') 103 { 104 *p = '\0'; 105 p++; 106 } 107 108 while (*p && isspace((unsigned char)*p)) 109 p++; 110 111 value = p; 112 vallen = strlen(value); 113 if (vallen) 114 p = value + (vallen - 1); 115 116 while (*p && isspace((unsigned char) *p) && p > value) 117 { 118 if (op == '=') 119 { 120 warnfunc(data, "%s: warning: trailing whitespace encountered while parsing value section\n", 121 warnprefix); 122 } 123 124 *p = '\0'; 125 p--; 126 } 127 128 if (ops[(unsigned char) op]) 129 ops[(unsigned char) op](data, warnprefix, key, value); 130 } 131 132 void 133 pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename) 134 { 135 pkgconf_buffer_t readbuf = PKGCONF_BUFFER_INITIALIZER; 136 size_t lineno = 0; 137 bool continue_reading = true; 138 139 while (continue_reading) 140 { 141 char warnprefix[PKGCONF_ITEM_SIZE]; 142 143 continue_reading = pkgconf_fgetline(&readbuf, f); 144 lineno++; 145 146 snprintf(warnprefix, sizeof warnprefix, "%s:" SIZE_FMT_SPECIFIER, filename, lineno); 147 pkgconf_parser_parse_buffer(data, ops, warnfunc, &readbuf, warnprefix); 148 pkgconf_buffer_reset(&readbuf); 149 } 150 151 pkgconf_buffer_finalize(&readbuf); 152 } 153