1 /* $NetBSD: subr.c,v 1.26 2023/08/26 15:18:27 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93"; 36 #endif 37 __RCSID("$NetBSD: subr.c,v 1.26 2023/08/26 15:18:27 rillig Exp $"); 38 #endif /* not lint */ 39 40 #include <ctype.h> 41 #include <err.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include "error.h" 46 47 /* 48 * Arrayify a list of rules 49 */ 50 void 51 arrayify(int *e_length, Eptr **e_array, Eptr header) 52 { 53 Eptr errorp; 54 Eptr *array; 55 int listlength; 56 int listindex; 57 58 for (errorp = header, listlength = 0; 59 errorp != NULL; errorp = errorp->error_next, listlength++) 60 continue; 61 array = Calloc(listlength+1, sizeof (Eptr)); 62 for (listindex = 0, errorp = header; 63 listindex < listlength; 64 listindex++, errorp = errorp->error_next) { 65 array[listindex] = errorp; 66 errorp->error_position = listindex; 67 } 68 array[listindex] = NULL; 69 *e_length = listlength; 70 *e_array = array; 71 } 72 73 void * 74 Calloc(size_t nelements, size_t size) 75 { 76 void *back; 77 78 back = calloc(nelements, size); 79 if (back == NULL) 80 errx(1, "Ran out of memory."); 81 return back; 82 } 83 84 char * 85 Strdup(const char *s) 86 { 87 char *ret; 88 89 ret = strdup(s); 90 if (ret == NULL) { 91 errx(1, "Ran out of memory."); 92 } 93 return ret; 94 } 95 96 /* 97 * find the position of a given character in a string 98 * (one based) 99 */ 100 int 101 position(const char *string, char ch) 102 { 103 if (string != NULL) 104 for (int i = 1; *string != '\0'; string++, i++) 105 if (*string == ch) 106 return i; 107 return -1; 108 } 109 110 /* 111 * clobber the first occurrence of ch in string by the new character 112 */ 113 char * 114 substitute(char *string, char chold, char chnew) 115 { 116 char *cp = string; 117 118 if (cp != NULL) 119 while (*cp != '\0') { 120 if (*cp == chold) { 121 *cp = chnew; 122 break; 123 } 124 cp++; 125 } 126 return string; 127 } 128 129 char 130 lastchar(const char *string) 131 { 132 size_t length; 133 134 if (string == NULL) 135 return '\0'; 136 length = strlen(string); 137 if (length >= 1) 138 return string[length-1]; 139 else 140 return '\0'; 141 } 142 143 char 144 firstchar(const char *string) 145 { 146 if (string != NULL) 147 return string[0]; 148 else 149 return '\0'; 150 } 151 152 char 153 next_lastchar(const char *string) 154 { 155 size_t length; 156 157 if (string == NULL) 158 return '\0'; 159 length = strlen(string); 160 if (length >= 2) 161 return string[length - 2]; 162 else 163 return '\0'; 164 } 165 166 void 167 clob_last(char *string, char newstuff) 168 { 169 if (string != NULL && string[0] != '\0') 170 string[strlen(string) - 1] = newstuff; 171 } 172 173 /* 174 * parse a string that is the result of a format %s(%d) 175 * return TRUE if this is of the proper format 176 */ 177 bool 178 persperdexplode(char *string, char **r_perd, char **r_pers) 179 { 180 char *cp; 181 size_t length = string != NULL ? strlen(string) : 0; 182 183 if (length >= 4 && string[length - 1] == ')') { 184 for (cp = &string[length - 2]; 185 isdigit((unsigned char)*cp) && *cp != '('; 186 --cp) 187 continue; 188 if (*cp == '(') { 189 string[length - 1] = '\0'; /* clobber the ) */ 190 *r_perd = strdup(cp+1); 191 string[length - 1] = ')'; 192 *cp = '\0'; /* clobber the ( */ 193 *r_pers = strdup(string); 194 *cp = '('; 195 return true; 196 } 197 } 198 return false; 199 } 200 201 #if 0 /* unused */ 202 /* 203 * parse a quoted string that is the result of a format \"%s\"(%d) 204 * return TRUE if this is of the proper format 205 */ 206 static bool 207 qpersperdexplode(char *string, char **r_perd, char **r_pers) 208 { 209 char *cp; 210 int length = 0; 211 212 if (string) 213 length = strlen(string); 214 if (length >= 4 && string[length - 1] == ')') { 215 for (cp = &string[length - 2]; 216 isdigit((unsigned char)*cp) && *cp != '('; 217 --cp) 218 continue; 219 if (*cp == '(' && *(cp - 1) == '"') { 220 string[length - 1] = '\0'; 221 *r_perd = strdup(cp+1); 222 string[length - 1] = ')'; 223 *(cp - 1) = '\0'; /* clobber the " */ 224 *r_pers = strdup(string + 1); 225 *(cp - 1) = '"'; 226 return true; 227 } 228 } 229 return false; 230 } 231 #endif /* 0 - unused */ 232 233 static char cincomment[] = CINCOMMENT; 234 static char coutcomment[] = COUTCOMMENT; 235 static char fincomment[] = FINCOMMENT; 236 static char foutcomment[] = FOUTCOMMENT; 237 static char newline[] = NEWLINE; 238 static char piincomment[] = PIINCOMMENT; 239 static char pioutcomment[] = PIOUTCOMMENT; 240 static char lispincomment[] = LISPINCOMMENT; 241 static char riincomment[] = RIINCOMMENT; 242 static char rioutcomment[] = RIOUTCOMMENT; 243 static char troffincomment[] = TROFFINCOMMENT; 244 static char troffoutcomment[] = TROFFOUTCOMMENT; 245 static char mod2incomment[] = MOD2INCOMMENT; 246 static char mod2outcomment[] = MOD2OUTCOMMENT; 247 248 struct lang_desc lang_table[] = { 249 { /*INUNKNOWN 0*/ "unknown", cincomment, coutcomment }, 250 { /*INCPP 1*/ "cpp", cincomment, coutcomment }, 251 { /*INCC 2*/ "cc", cincomment, coutcomment }, 252 { /*INAS 3*/ "as", ASINCOMMENT, newline }, 253 { /*INLD 4*/ "ld", cincomment, coutcomment }, 254 { /*INLINT 5*/ "lint", cincomment, coutcomment }, 255 { /*INF77 6*/ "f77", fincomment, foutcomment }, 256 { /*INPI 7*/ "pi", piincomment, pioutcomment }, 257 { /*INPC 8*/ "pc", piincomment, pioutcomment }, 258 { /*INFRANZ 9*/ "franz", lispincomment, newline }, 259 { /*INLISP 10*/ "lisp", lispincomment, newline }, 260 { /*INVAXIMA 11*/ "vaxima", lispincomment, newline }, 261 { /*INRATFOR 12*/ "ratfor", fincomment, foutcomment }, 262 { /*INLEX 13*/ "lex", cincomment, coutcomment }, 263 { /*INYACC 14*/ "yacc", cincomment, coutcomment }, 264 { /*INAPL 15*/ "apl", ".lm", newline }, 265 { /*INMAKE 16*/ "make", ASINCOMMENT, newline }, 266 { /*INRI 17*/ "ri", riincomment, rioutcomment }, 267 { /*INTROFF 18*/ "troff", troffincomment, troffoutcomment }, 268 { /*INMOD2 19*/ "mod2", mod2incomment, mod2outcomment }, 269 { NULL, NULL, NULL } 270 }; 271 272 void 273 printerrors(bool look_at_subclass, int errorc, Eptr errorv[]) 274 { 275 int i; 276 Eptr errorp; 277 278 for (errorp = errorv[i = 0]; i < errorc; errorp = errorv[++i]) { 279 if (errorp->error_e_class == C_IGNORE) 280 continue; 281 if (look_at_subclass && errorp->error_s_class == C_DUPL) 282 continue; 283 printf("Error %d, (%s error) [%s], text = \"", 284 i, 285 class_table[errorp->error_e_class], 286 lang_table[errorp->error_language].lang_name); 287 wordvprint(stdout,errorp->error_lgtext,errorp->error_text); 288 printf("\"\n"); 289 } 290 } 291 292 void 293 wordvprint(FILE *fyle, int wordc, char **wordv) 294 { 295 const char *sep = ""; 296 297 for (int i = 0; i < wordc; i++) 298 if (wordv[i] != NULL) { 299 fprintf(fyle, "%s%s",sep,wordv[i]); 300 sep = " "; 301 } 302 } 303 304 /* 305 * Given a string, parse it into a number of words, and build 306 * a wordc wordv combination pointing into it. 307 */ 308 void 309 wordvbuild(char *string, int *r_wordc, char ***r_wordv) 310 { 311 char *cp; 312 char **wordv; 313 int wordcount; 314 int wordindex; 315 316 for (wordcount = 0, cp = string; *cp != '\0'; wordcount++) { 317 while (isspace((unsigned char)*cp)) 318 cp++; 319 if (*cp == '\0') 320 break; 321 while (*cp != '\0' && !isspace((unsigned char)*cp)) 322 cp++; 323 } 324 wordv = Calloc(wordcount + 1, sizeof (char *)); 325 for (cp=string, wordindex=0; wordcount > 0; wordindex++, --wordcount) { 326 while (isspace((unsigned char)*cp)) 327 cp++; 328 if (*cp == '\0') 329 break; 330 wordv[wordindex] = cp; 331 while (*cp != '\0' && !isspace((unsigned char)*cp)) 332 cp++; 333 *cp++ = '\0'; 334 } 335 if (wordcount != 0) 336 errx(6, "Initial miscount of the number of words in a line"); 337 wordv[wordindex] = NULL; 338 #ifdef FULLDEBUG 339 for (wordcount = 0; wordcount < wordindex; wordcount++) 340 printf("Word %d = \"%s\"\n", wordcount, wordv[wordcount]); 341 printf("\n"); 342 #endif 343 *r_wordc = wordindex; 344 *r_wordv = wordv; 345 } 346 347 /* 348 * Compare two 0 based wordvectors 349 */ 350 bool 351 wordv_eq(char **wordv1, int wordc, char **wordv2) 352 { 353 for (int i = 0; i < wordc; i++) 354 if (wordv1[i] == NULL || wordv2[i] == NULL 355 || strcmp(wordv1[i], wordv2[i]) != 0) 356 return false; 357 return true; 358 } 359 360 /* 361 * splice a 0 based word vector onto the tail of a 362 * new wordv, allowing the first emptyhead slots to be empty 363 */ 364 char ** 365 wordvsplice(int emptyhead, int wordc, char **wordv) 366 { 367 char **nwordv; 368 int nwordc = emptyhead + wordc; 369 int i; 370 371 nwordv = Calloc(nwordc, sizeof (char *)); 372 for (i = 0; i < emptyhead; i++) 373 nwordv[i] = NULL; 374 for (i = emptyhead; i < nwordc; i++) 375 nwordv[i] = wordv[i-emptyhead]; 376 return nwordv; 377 } 378 379 const char * 380 plural(int n) 381 { 382 return n > 1 ? "s" : ""; 383 } 384 385 const char * 386 verbform(int n) 387 { 388 return n > 1 ? "" : "s"; 389 } 390