1 /* $NetBSD: subr.c,v 1.19 2009/08/13 06:59:37 dholland 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.19 2009/08/13 06:59:37 dholland 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; 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 int i; 104 105 if (string) 106 for (i=1; *string; string++, i++) { 107 if (*string == ch) 108 return (i); 109 } 110 return (-1); 111 } 112 113 /* 114 * clobber the first occurance of ch in string by the new character 115 */ 116 char * 117 substitute(char *string, char chold, char chnew) 118 { 119 char *cp = string; 120 121 if (cp) 122 while (*cp) { 123 if (*cp == chold) { 124 *cp = chnew; 125 break; 126 } 127 cp++; 128 } 129 return (string); 130 } 131 132 char 133 lastchar(const char *string) 134 { 135 int length; 136 137 if (string == NULL) 138 return ('\0'); 139 length = strlen(string); 140 if (length >= 1) 141 return (string[length-1]); 142 else 143 return ('\0'); 144 } 145 146 char 147 firstchar(const char *string) 148 { 149 if (string) 150 return (string[0]); 151 else 152 return ('\0'); 153 } 154 155 char 156 next_lastchar(const char *string) 157 { 158 int length; 159 160 if (string == NULL) 161 return ('\0'); 162 length = strlen(string); 163 if (length >= 2) 164 return (string[length - 2]); 165 else 166 return ('\0'); 167 } 168 169 void 170 clob_last(char *string, char newstuff) 171 { 172 int length = 0; 173 174 if (string) 175 length = strlen(string); 176 if (length >= 1) 177 string[length - 1] = newstuff; 178 } 179 180 /* 181 * parse a string that is the result of a format %s(%d) 182 * return TRUE if this is of the proper format 183 */ 184 bool 185 persperdexplode(char *string, char **r_perd, char **r_pers) 186 { 187 char *cp; 188 int length = 0; 189 190 if (string) 191 length = strlen(string); 192 if (length >= 4 && string[length - 1] == ')') { 193 for (cp = &string[length - 2]; 194 isdigit((unsigned char)*cp) && *cp != '('; 195 --cp) 196 continue; 197 if (*cp == '(') { 198 string[length - 1] = '\0'; /* clobber the ) */ 199 *r_perd = strdup(cp+1); 200 string[length - 1] = ')'; 201 *cp = '\0'; /* clobber the ( */ 202 *r_pers = strdup(string); 203 *cp = '('; 204 return true; 205 } 206 } 207 return false; 208 } 209 210 #if 0 /* unused */ 211 /* 212 * parse a quoted string that is the result of a format \"%s\"(%d) 213 * return TRUE if this is of the proper format 214 */ 215 static boolean 216 qpersperdexplode(char *string, char **r_perd, char **r_pers) 217 { 218 char *cp; 219 int length = 0; 220 221 if (string) 222 length = strlen(string); 223 if (length >= 4 && string[length - 1] == ')') { 224 for (cp = &string[length - 2]; 225 isdigit((unsigned char)*cp) && *cp != '('; 226 --cp) 227 continue; 228 if (*cp == '(' && *(cp - 1) == '"') { 229 string[length - 1] = '\0'; 230 *r_perd = strdup(cp+1); 231 string[length - 1] = ')'; 232 *(cp - 1) = '\0'; /* clobber the " */ 233 *r_pers = strdup(string + 1); 234 *(cp - 1) = '"'; 235 return true; 236 } 237 } 238 return false; 239 } 240 #endif /* 0 - unused */ 241 242 static char cincomment[] = CINCOMMENT; 243 static char coutcomment[] = COUTCOMMENT; 244 static char fincomment[] = FINCOMMENT; 245 static char foutcomment[] = FOUTCOMMENT; 246 static char newline[] = NEWLINE; 247 static char piincomment[] = PIINCOMMENT; 248 static char pioutcomment[] = PIOUTCOMMENT; 249 static char lispincomment[] = LISPINCOMMENT; 250 static char riincomment[] = RIINCOMMENT; 251 static char rioutcomment[] = RIOUTCOMMENT; 252 static char troffincomment[] = TROFFINCOMMENT; 253 static char troffoutcomment[] = TROFFOUTCOMMENT; 254 static char mod2incomment[] = MOD2INCOMMENT; 255 static char mod2outcomment[] = MOD2OUTCOMMENT; 256 257 struct lang_desc lang_table[] = { 258 { /*INUNKNOWN 0*/ "unknown", cincomment, coutcomment }, 259 { /*INCPP 1*/ "cpp", cincomment, coutcomment }, 260 { /*INCC 2*/ "cc", cincomment, coutcomment }, 261 { /*INAS 3*/ "as", ASINCOMMENT, newline }, 262 { /*INLD 4*/ "ld", cincomment, coutcomment }, 263 { /*INLINT 5*/ "lint", cincomment, coutcomment }, 264 { /*INF77 6*/ "f77", fincomment, foutcomment }, 265 { /*INPI 7*/ "pi", piincomment, pioutcomment }, 266 { /*INPC 8*/ "pc", piincomment, pioutcomment }, 267 { /*INFRANZ 9*/ "franz", lispincomment, newline }, 268 { /*INLISP 10*/ "lisp", lispincomment, newline }, 269 { /*INVAXIMA 11*/ "vaxima", lispincomment, newline }, 270 { /*INRATFOR 12*/ "ratfor", fincomment, foutcomment }, 271 { /*INLEX 13*/ "lex", cincomment, coutcomment }, 272 { /*INYACC 14*/ "yacc", cincomment, coutcomment }, 273 { /*INAPL 15*/ "apl", ".lm", newline }, 274 { /*INMAKE 16*/ "make", ASINCOMMENT, newline }, 275 { /*INRI 17*/ "ri", riincomment, rioutcomment }, 276 { /*INTROFF 18*/ "troff", troffincomment, troffoutcomment }, 277 { /*INMOD2 19*/ "mod2", mod2incomment, mod2outcomment }, 278 { 0, 0, 0 } 279 }; 280 281 void 282 printerrors(bool look_at_subclass, int errorc, Eptr errorv[]) 283 { 284 int i; 285 Eptr errorp; 286 287 for (errorp = errorv[i = 0]; i < errorc; errorp = errorv[++i]) { 288 if (errorp->error_e_class == C_IGNORE) 289 continue; 290 if (look_at_subclass && errorp->error_s_class == C_DUPL) 291 continue; 292 printf("Error %d, (%s error) [%s], text = \"", 293 i, 294 class_table[errorp->error_e_class], 295 lang_table[errorp->error_language].lang_name); 296 wordvprint(stdout,errorp->error_lgtext,errorp->error_text); 297 printf("\"\n"); 298 } 299 } 300 301 void 302 wordvprint(FILE *fyle, int wordc, char **wordv) 303 { 304 int i; 305 const char *sep = ""; 306 307 for (i = 0; i < wordc; i++) 308 if (wordv[i]) { 309 fprintf(fyle, "%s%s",sep,wordv[i]); 310 sep = " "; 311 } 312 } 313 314 /* 315 * Given a string, parse it into a number of words, and build 316 * a wordc wordv combination pointing into it. 317 */ 318 void 319 wordvbuild(char *string, int *r_wordc, char ***r_wordv) 320 { 321 char *cp; 322 char **wordv; 323 int wordcount; 324 int wordindex; 325 326 for (wordcount = 0, cp = string; *cp; wordcount++) { 327 while (*cp && isspace((unsigned char)*cp)) 328 cp++; 329 if (*cp == '\0') 330 break; 331 while (*cp && !isspace((unsigned char)*cp)) 332 cp++; 333 } 334 wordv = Calloc(wordcount + 1, sizeof (char *)); 335 for (cp=string, wordindex=0; wordcount; wordindex++, --wordcount) { 336 while (*cp && isspace((unsigned char)*cp)) 337 cp++; 338 if (*cp == '\0') 339 break; 340 wordv[wordindex] = cp; 341 while (*cp && !isspace((unsigned char)*cp)) 342 cp++; 343 *cp++ = '\0'; 344 } 345 if (wordcount != 0) 346 errx(6, "Initial miscount of the number of words in a line"); 347 wordv[wordindex] = NULL; 348 #ifdef FULLDEBUG 349 for (wordcount = 0; wordcount < wordindex; wordcount++) 350 printf("Word %d = \"%s\"\n", wordcount, wordv[wordcount]); 351 printf("\n"); 352 #endif 353 *r_wordc = wordindex; 354 *r_wordv = wordv; 355 } 356 357 /* 358 * Compare two 0 based wordvectors 359 */ 360 int 361 wordvcmp(char **wordv1, int wordc, char **wordv2) 362 { 363 int i; 364 int back; 365 366 for (i = 0; i < wordc; i++) { 367 if (wordv1[i] == NULL || wordv2[i] == NULL) 368 return (-1); 369 if ((back = strcmp(wordv1[i], wordv2[i])) != 0) 370 return (back); 371 } 372 return (0); /* they are equal */ 373 } 374 375 /* 376 * splice a 0 basedword vector onto the tail of a 377 * new wordv, allowing the first emptyhead slots to be empty 378 */ 379 char ** 380 wordvsplice(int emptyhead, int wordc, char **wordv) 381 { 382 char **nwordv; 383 int nwordc = emptyhead + wordc; 384 int i; 385 386 nwordv = Calloc(nwordc, sizeof (char *)); 387 for (i = 0; i < emptyhead; i++) 388 nwordv[i] = NULL; 389 for (i = emptyhead; i < nwordc; i++) { 390 nwordv[i] = wordv[i-emptyhead]; 391 } 392 return (nwordv); 393 } 394 395 /* 396 * plural and verb forms 397 */ 398 static const char *S = "s"; 399 static const char *N = ""; 400 401 const char * 402 plural(int n) 403 { 404 return (n > 1 ? S : N); 405 } 406 407 const char * 408 verbform(int n) 409 { 410 return (n > 1 ? N : S); 411 } 412