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