1 /* File : misc.c 2 Author : Ozan Yigit 3 Updated: 26-Mar-1993 4 Purpose: Miscellaneous support code for PD M4. 5 */ 6 7 #ifndef lint 8 static char rcsid[] = "$Id: misc.c,v 1.3 1993/08/02 17:54:45 mycroft Exp $"; 9 #endif /* not lint */ 10 11 #include "mdef.h" 12 #include "extr.h" 13 #include "ourlims.h" 14 15 #ifdef DUFFCP 16 17 /* This version of the ANSI standard function memcpy() 18 uses Duff's Device (tm Tom Duff) to unroll the copying loop: 19 while (count-- > 0) *to++ = *from++; 20 */ 21 void memcpy(to, from, count) 22 register char *from, *to; 23 register int count; 24 { 25 if (count > 0) { 26 register int loops = (count+8-1) >> 3; /* div 8 round up */ 27 28 switch (count & (8-1)) { /* mod 8 */ 29 case 0: do { *to++ = *from++; 30 case 7: *to++ = *from++; 31 case 6: *to++ = *from++; 32 case 5: *to++ = *from++; 33 case 4: *to++ = *from++; 34 case 3: *to++ = *from++; 35 case 2: *to++ = *from++; 36 case 1: *to++ = *from++; 37 } while (--loops > 0); 38 } 39 } 40 } 41 42 #endif 43 44 45 /* strsave(s) 46 return a new malloc()ed copy of s -- same as V.3's strdup(). 47 */ 48 char *strsave(s) 49 char *s; 50 { 51 register int n = strlen(s)+1; 52 char *p = malloc(n); 53 54 if (p) memcpy(p, s, n); 55 return p; 56 } 57 58 59 /* indx(s1, s2) 60 if s1 can be decomposed as alpha || s2 || omega, return the length 61 of the shortest such alpha, otherwise return -1. 62 */ 63 int indx(s1, s2) 64 char *s1; 65 char *s2; 66 { 67 register char *t; 68 register char *m; 69 register char *p; 70 71 for (p = s1; *p; p++) { 72 for (t = p, m = s2; *m && *m == *t; m++, t++); 73 if (!*m) return p-s1; 74 } 75 return -1; 76 } 77 78 79 char pbmsg[] = "m4: too many characters pushed back"; 80 81 /* Xputback(c) 82 push character c back onto the input stream. 83 This is now macro putback() in misc.h 84 */ 85 void Xputback(c) 86 char c; 87 { 88 if (bp < endpbb) *bp++ = c; else error(pbmsg); 89 } 90 91 92 /* pbstr(s) 93 push string s back onto the input stream. 94 putback() has been unfolded here to improve performance. 95 Example: 96 s = <ABC> 97 bp = <more stuff> 98 After the call: 99 bp = <more stuffCBA> 100 It would be more efficient if we ran the pushback buffer in the 101 opposite direction 102 */ 103 void pbstr(s) 104 register char *s; 105 { 106 register char *es; 107 register char *zp; 108 109 zp = bp; 110 for (es = s; *es; ) es++; /* now es points to terminating NUL */ 111 bp += es-s; /* advance bp as far as it should go */ 112 if (bp >= endpbb) error("m4: too many characters to push back"); 113 while (es > s) *zp++ = *--es; 114 } 115 116 117 /* pbqtd(s) 118 pushes string s back "quoted", doing whatever has to be done to it to 119 make sure that the result will evaluate to the original value. As it 120 happens, we have only to add lquote and rquote. 121 */ 122 void pbqtd(s) 123 register char *s; 124 { 125 register char *es; 126 register char *zp; 127 128 zp = bp; 129 for (es = s; *es; ) es++; /* now es points to terminating NUL */ 130 bp += 2+es-s; /* advance bp as far as it should go */ 131 if (bp >= endpbb) error("m4: too many characters to push back"); 132 *zp++ = rquote; 133 while (es > s) *zp++ = *--es; 134 *zp++ = lquote; 135 } 136 137 138 /* pbnum(n) 139 convert a number to a (decimal) string and push it back. 140 The original definition did not work for MININT; this does. 141 */ 142 void pbnum(n) 143 int n; 144 { 145 register int num; 146 147 num = n > 0 ? -n : n; /* MININT <= num <= 0 */ 148 do { 149 putback('0' - (num % 10)); 150 } while ((num /= 10) < 0); 151 if (n < 0) putback('-'); 152 } 153 154 155 /* pbrad(n, r, m) 156 converts a number n to base r ([-36..-2] U [2..36]), with at least 157 m digits. If r == 10 and m == 1, this is exactly the same as pbnum. 158 However, this uses the function int2str() from R.A.O'Keefe's public 159 domain string library, and puts the results of that back. 160 The Unix System V Release 3 version of m4 accepts radix 1; 161 THIS VERSION OF M4 DOES NOT ACCEPT RADIX 1 OR -1, 162 nor do we accept radix < -36 or radix > 36. At the moment such bad 163 radices quietly produce nothing. The V.3 treatment of radix 1 is 164 push back abs(n) "1"s, then 165 if n < 0, push back one "-". 166 Until I come across something which uses it, I can't bring myself to 167 implement this. 168 169 I have, however, found a use for radix 0. Unsurprisingly, it is 170 related to radix 0 in Edinburgh Prolog. 171 eval('c1c2...cn', 0, m) 172 pushes back max(m-n,0) blanks and the characters c1...cn. This can 173 adjust to any byte size as long as UCHAR_MAX = (1 << CHAR_BIT) - 1. 174 In particular, eval(c, 0) where 0 < c <= UCHAR_MAX, pushes back the 175 character with code c. Note that this has to agree with eval(); so 176 both of them have to use the same byte ordering. 177 */ 178 void pbrad(n, r, m) 179 long int n; 180 int r, m; 181 { 182 char buffer[34]; 183 char *p; 184 int L; 185 186 if (r == 0) { 187 unsigned long int x = (unsigned long)n; 188 int n; 189 190 for (n = 0; x; x >>= CHAR_BIT, n++) buffer[n] = x & UCHAR_MAX; 191 for (L = n; --L >= 0; ) putback(buffer[L]); 192 for (L = m-n; --L >= 0; ) putback(' '); 193 return; 194 } 195 L = m - (int2str(p = buffer, -r, n)-buffer); 196 if (buffer[0] == '-') L++, p++; 197 if (L > 0) { 198 pbstr(p); 199 while (--L >= 0) putback('0'); 200 if (p != buffer) putback('-'); 201 } else { 202 pbstr(buffer); 203 } 204 } 205 206 207 char csmsg[] = "m4: string space overflow"; 208 209 /* chrsave(c) 210 put the character c in the string space. 211 */ 212 void Xchrsave(c) 213 char c; 214 { 215 #if 0 216 if (sp < 0) putc(c, active); else 217 #endif 218 if (ep < endest) *ep++ = c; else 219 error(csmsg); 220 } 221 222 223 /* getdiv(ind) 224 read in a diversion file and then delete it. 225 */ 226 void getdiv(ind) 227 int ind; 228 { 229 register int c; 230 register FILE *dfil; 231 register FILE *afil; 232 233 afil = active; 234 if (outfile[ind] == afil) 235 error("m4: undivert: diversion still active."); 236 (void) fclose(outfile[ind]); 237 outfile[ind] = NULL; 238 m4temp[UNIQUE] = '0' + ind; 239 if ((dfil = fopen(m4temp, "r")) == NULL) 240 error("m4: cannot undivert."); 241 while ((c = getc(dfil)) != EOF) putc(c, afil); 242 (void) fclose(dfil); 243 244 #if vms 245 if (remove(m4temp)) error("m4: cannot unlink."); 246 #else 247 if (unlink(m4temp) == -1) error("m4: cannot unlink."); 248 #endif 249 } 250 251 252 /* killdiv() 253 delete all the diversion files which have been created. 254 */ 255 void killdiv() 256 { 257 register int n; 258 259 for (n = 0; n < MAXOUT; n++) { 260 if (outfile[n] != NULL) { 261 (void) fclose(outfile[n]); 262 m4temp[UNIQUE] = '0' + n; 263 #if unix 264 (void) unlink(m4temp); 265 #else 266 (void) remove(m4temp); 267 #endif 268 } 269 } 270 } 271 272 273 /* error(s) 274 close all files, report a fatal error, and quit, letting the caller know. 275 */ 276 void error(s) 277 char *s; 278 { 279 killdiv(); 280 fprintf(stderr, "%s\n", s); 281 exit(1); 282 } 283 284 285 /* Interrupt handling 286 */ 287 static char *msg = "\ninterrupted."; 288 289 #ifdef __STDC__ 290 void onintr(int signo) 291 #else 292 onintr() 293 #endif 294 { 295 error(msg); 296 } 297 298 299 void usage() 300 { 301 fprintf(stderr, "Usage: m4 [-e] [-[BHST]int] [-Dname[=val]] [-Uname]\n"); 302 exit(1); 303 } 304 305 #ifdef GETOPT 306 /* Henry Spencer's getopt() - get option letter from argv */ 307 308 char *optarg; /* Global argument pointer. */ 309 int optind = 0; /* Global argv index. */ 310 311 static char *scan = NULL; /* Private scan pointer. */ 312 313 #ifndef __STDC__ 314 extern char *index(); 315 #define strchr index 316 #endif 317 318 int getopt(argc, argv, optstring) 319 int argc; 320 char **argv; 321 char *optstring; 322 { 323 register char c; 324 register char *place; 325 326 optarg = NULL; 327 328 if (scan == NULL || *scan == '\0') { 329 if (optind == 0) optind++; 330 if (optind >= argc 331 || argv[optind][0] != '-' 332 || argv[optind][1] == '\0') 333 return EOF; 334 if (strcmp(argv[optind], "--") == 0) { 335 optind++; 336 return EOF; 337 } 338 scan = argv[optind]+1; 339 optind++; 340 } 341 c = *scan++; 342 place = strchr(optstring, c); 343 344 if (place == NULL || c == ':') { 345 fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); 346 return '?'; 347 } 348 place++; 349 if (*place == ':') { 350 if (*scan != '\0') { 351 optarg = scan; 352 scan = NULL; 353 } else { 354 optarg = argv[optind]; 355 optind++; 356 } 357 } 358 return c; 359 } 360 #endif 361 362