1 1.27 joerg /* $NetBSD: getNAME.c,v 1.27 2011/08/29 20:41:06 joerg Exp $ */ 2 1.4 mrg 3 1.1 cgd /*- 4 1.24 christos * Copyright (c) 1997, Christos Zoulas. All rights reserved. 5 1.3 tls * Copyright (c) 1980, 1993 6 1.3 tls * The Regents of the University of California. All rights reserved. 7 1.1 cgd * 8 1.1 cgd * Redistribution and use in source and binary forms, with or without 9 1.1 cgd * modification, are permitted provided that the following conditions 10 1.1 cgd * are met: 11 1.1 cgd * 1. Redistributions of source code must retain the above copyright 12 1.1 cgd * notice, this list of conditions and the following disclaimer. 13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer in the 15 1.1 cgd * documentation and/or other materials provided with the distribution. 16 1.21 agc * 3. Neither the name of the University nor the names of its contributors 17 1.21 agc * may be used to endorse or promote products derived from this software 18 1.21 agc * without specific prior written permission. 19 1.21 agc * 20 1.21 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 1.21 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.21 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.21 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 1.21 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.21 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.21 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.21 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.21 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.21 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.21 agc * SUCH DAMAGE. 31 1.21 agc */ 32 1.21 agc 33 1.4 mrg #include <sys/cdefs.h> 34 1.1 cgd #ifndef lint 35 1.26 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ 36 1.26 lukem The Regents of the University of California. All rights reserved."); 37 1.3 tls #if 0 38 1.3 tls static char sccsid[] = "@(#)getNAME.c 8.1 (Berkeley) 6/30/93"; 39 1.4 mrg #else 40 1.27 joerg __RCSID("$NetBSD: getNAME.c,v 1.27 2011/08/29 20:41:06 joerg Exp $"); 41 1.3 tls #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.1 cgd /* 45 1.1 cgd * Get name sections from manual pages. 46 1.1 cgd * -t for building toc 47 1.1 cgd * -i for building intro entries 48 1.8 mrg * -w for querying type of manual source 49 1.14 christos * -v verbose 50 1.1 cgd * other apropos database 51 1.1 cgd */ 52 1.11 perry #include <err.h> 53 1.14 christos #include <ctype.h> 54 1.1 cgd #include <stdio.h> 55 1.3 tls #include <stdlib.h> 56 1.1 cgd #include <string.h> 57 1.11 perry #include <unistd.h> 58 1.10 christos 59 1.10 christos static int tocrc; 60 1.10 christos static int intro; 61 1.10 christos static int typeflag; 62 1.14 christos static int verbose; 63 1.10 christos 64 1.10 christos #define SLOP 10 /* strlen(" () - ") < 10 */ 65 1.10 christos 66 1.10 christos static char *linebuf = NULL; 67 1.10 christos static size_t maxlen = 0; 68 1.10 christos 69 1.10 christos 70 1.23 christos static void doname(char *); 71 1.23 christos static void dorefname(char *); 72 1.23 christos static void getfrom(char *); 73 1.23 christos static void oldman(char *, char *); 74 1.23 christos static void newman(char *, char *); 75 1.23 christos static void remcomma(char *, size_t *); 76 1.23 christos static void remquote(char *, size_t *); 77 1.23 christos static void fixxref(char *, size_t *); 78 1.23 christos static void split(char *, char *); 79 1.27 joerg __dead static void usage(void); 80 1.1 cgd 81 1.23 christos int main(int, char *[]); 82 1.3 tls 83 1.16 augustss /* The .SH NAMEs that are allowed. */ 84 1.23 christos static const char *names[] = { "name", "namn", 0 }; 85 1.16 augustss 86 1.3 tls int 87 1.23 christos main(int argc, char *argv[]) 88 1.1 cgd { 89 1.1 cgd int ch; 90 1.1 cgd 91 1.14 christos while ((ch = getopt(argc, argv, "itvw")) != -1) 92 1.6 enami switch (ch) { 93 1.1 cgd case 'i': 94 1.1 cgd intro = 1; 95 1.1 cgd break; 96 1.1 cgd case 't': 97 1.1 cgd tocrc = 1; 98 1.1 cgd break; 99 1.14 christos case 'v': 100 1.14 christos verbose = 1; 101 1.14 christos break; 102 1.3 tls case 'w': 103 1.3 tls typeflag = 1; 104 1.3 tls break; 105 1.1 cgd case '?': 106 1.1 cgd default: 107 1.1 cgd usage(); 108 1.1 cgd } 109 1.1 cgd argc -= optind; 110 1.1 cgd argv += optind; 111 1.1 cgd 112 1.1 cgd if (!*argv) 113 1.1 cgd usage(); 114 1.1 cgd 115 1.1 cgd for (; *argv; ++argv) 116 1.1 cgd getfrom(*argv); 117 1.23 christos return 0; 118 1.1 cgd } 119 1.1 cgd 120 1.23 christos static void 121 1.23 christos getfrom(char *pathname) 122 1.1 cgd { 123 1.10 christos char *name; 124 1.10 christos char *line; 125 1.10 christos size_t len; 126 1.1 cgd 127 1.3 tls if (freopen(pathname, "r", stdin) == 0) { 128 1.10 christos warn("Cannot open `%s'", pathname); 129 1.1 cgd return; 130 1.1 cgd } 131 1.10 christos if ((name = strrchr(pathname, '/')) != NULL) 132 1.3 tls name++; 133 1.3 tls else 134 1.3 tls name = pathname; 135 1.1 cgd for (;;) { 136 1.10 christos if ((line = fgetln(stdin, &len)) == NULL) { 137 1.3 tls if (typeflag) 138 1.23 christos (void)printf("%-60s\tUNKNOWN\n", pathname); 139 1.23 christos if (verbose) 140 1.23 christos warnx("missing .TH or .Dt section in `%s'", 141 1.23 christos pathname); 142 1.1 cgd return; 143 1.3 tls } 144 1.20 christos if (len < 3) 145 1.20 christos continue; 146 1.10 christos if (line[0] != '.') 147 1.1 cgd continue; 148 1.10 christos if ((line[1] == 'T' && line[2] == 'H') || 149 1.23 christos (line[1] == 't' && line[2] == 'h')) { 150 1.23 christos oldman(pathname, name); 151 1.23 christos return; 152 1.23 christos } 153 1.23 christos if (line[1] == 'D' && line[2] == 't') { 154 1.23 christos newman(pathname, name); 155 1.23 christos return; 156 1.23 christos } 157 1.3 tls } 158 1.10 christos } 159 1.10 christos 160 1.10 christos static void 161 1.23 christos oldman(char *pathname, char *name) 162 1.10 christos { 163 1.22 itojun char *line, *ext, *s, *newlinebuf; 164 1.10 christos size_t len, i, extlen; 165 1.10 christos size_t curlen = 0; 166 1.22 itojun size_t newmaxlen; 167 1.25 hubertf size_t ocurlen = -1; 168 1.10 christos 169 1.3 tls if (typeflag) { 170 1.23 christos (void)printf("%-60s\tOLD\n", pathname); 171 1.3 tls return; 172 1.1 cgd } 173 1.1 cgd for (;;) { 174 1.14 christos if ((line = fgetln(stdin, &len)) == NULL) { 175 1.14 christos if (verbose) 176 1.14 christos warnx("missing .SH section in `%s'", pathname); 177 1.1 cgd return; 178 1.14 christos } 179 1.20 christos if (len < 4) 180 1.20 christos continue; 181 1.10 christos if (line[0] != '.') 182 1.1 cgd continue; 183 1.10 christos if (line[1] == 'S' && line[2] == 'H') 184 1.1 cgd break; 185 1.10 christos if (line[1] == 's' && line[2] == 'h') 186 1.1 cgd break; 187 1.1 cgd } 188 1.10 christos 189 1.14 christos for (s = &line[3]; s < &line[len] && 190 1.14 christos (isspace((unsigned char) *s) || *s == '"' || *s == '\''); s++) 191 1.14 christos continue; 192 1.14 christos if (s == &line[len]) { 193 1.14 christos warnx("missing argument to .SH in `%s'", pathname); 194 1.14 christos return; 195 1.14 christos } 196 1.16 augustss for (i = 0; names[i]; i++) 197 1.16 augustss if (strncasecmp(s, names[i], strlen(names[i])) == 0) 198 1.16 augustss break; 199 1.16 augustss if (names[i] == NULL) { 200 1.14 christos warnx("first .SH section is not \"NAME\" in `%s'", pathname); 201 1.14 christos return; 202 1.14 christos } 203 1.14 christos 204 1.25 hubertf again: 205 1.1 cgd if (tocrc) 206 1.1 cgd doname(name); 207 1.10 christos 208 1.10 christos for (i = 0;; i++) { 209 1.10 christos if ((line = fgetln(stdin, &len)) == NULL) 210 1.1 cgd break; 211 1.10 christos if (line[0] == '.') { 212 1.13 fair if (line[1] == '\\' && line[2] == '"') 213 1.13 fair continue; /* [nt]roff comment */ 214 1.10 christos if (line[1] == 'S' && line[2] == 'H') 215 1.1 cgd break; 216 1.10 christos if (line[1] == 's' && line[2] == 'h') 217 1.12 mrg break; 218 1.12 mrg if (line[1] == 'P' && line[2] == 'P') 219 1.1 cgd break; 220 1.25 hubertf if (line[1] == 'b' && line[2] == 'r') { 221 1.25 hubertf if (intro) 222 1.25 hubertf split(linebuf, name); 223 1.25 hubertf else 224 1.25 hubertf (void)printf("%s\n", linebuf); 225 1.25 hubertf curlen = ocurlen; 226 1.25 hubertf goto again; 227 1.25 hubertf } 228 1.1 cgd } 229 1.10 christos if (line[len - 1] == '\n') { 230 1.10 christos line[len - 1] = '\0'; 231 1.10 christos len--; 232 1.10 christos } 233 1.10 christos if ((ext = strrchr(name, '.')) != NULL) { 234 1.10 christos ext++; 235 1.10 christos extlen = strlen(ext); 236 1.10 christos } 237 1.10 christos else 238 1.10 christos extlen = 0; 239 1.10 christos 240 1.10 christos if (maxlen + extlen < curlen + len + SLOP) { 241 1.22 itojun newmaxlen = 2 * (curlen + len) + SLOP + extlen; 242 1.22 itojun if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL) 243 1.17 drochner err(1, NULL); 244 1.22 itojun linebuf = newlinebuf; 245 1.22 itojun maxlen = newmaxlen; 246 1.10 christos } 247 1.3 tls if (i != 0) 248 1.10 christos linebuf[curlen++] = ' '; 249 1.10 christos (void)memcpy(&linebuf[curlen], line, len); 250 1.25 hubertf ocurlen = curlen; 251 1.10 christos curlen += len; 252 1.10 christos linebuf[curlen] = '\0'; 253 1.15 hubertf 254 1.15 hubertf if(!tocrc && !intro) { 255 1.15 hubertf /* change the \- into (N) - */ 256 1.15 hubertf if ((s = strstr(linebuf, "\\-")) != NULL) { 257 1.15 hubertf (void)memmove(s + extlen + 3, s + 1, 258 1.15 hubertf curlen - (s + 1 - linebuf)); 259 1.15 hubertf curlen--; 260 1.15 hubertf if (extlen) { 261 1.15 hubertf *s++ = '('; 262 1.15 hubertf while (*ext) 263 1.15 hubertf *s++ = *ext++; 264 1.15 hubertf *s++ = ')'; 265 1.15 hubertf *s++ = ' '; 266 1.15 hubertf curlen += extlen + 3; 267 1.15 hubertf } 268 1.15 hubertf linebuf[curlen] = '\0'; 269 1.8 mrg } 270 1.8 mrg } 271 1.3 tls } 272 1.10 christos 273 1.3 tls if (intro) 274 1.10 christos split(linebuf, name); 275 1.3 tls else 276 1.23 christos (void)printf("%s\n", linebuf); 277 1.3 tls return; 278 1.10 christos } 279 1.10 christos 280 1.10 christos static void 281 1.23 christos newman(char *pathname, char *name) 282 1.10 christos { 283 1.22 itojun char *line, *ext, *s, *newlinebuf; 284 1.10 christos size_t len, i, extlen; 285 1.10 christos size_t curlen = 0; 286 1.22 itojun size_t newmaxlen; 287 1.3 tls 288 1.9 lukem if (typeflag) { 289 1.23 christos (void)printf("%-60s\tNEW\n", pathname); 290 1.9 lukem return; 291 1.9 lukem } 292 1.3 tls for (;;) { 293 1.14 christos if ((line = fgetln(stdin, &len)) == NULL) { 294 1.14 christos if (verbose) 295 1.14 christos warnx("missing .Sh section in `%s'", pathname); 296 1.3 tls return; 297 1.14 christos } 298 1.10 christos if (line[0] != '.') 299 1.1 cgd continue; 300 1.10 christos if (line[1] == 'S' && line[2] == 'h') 301 1.3 tls break; 302 1.14 christos } 303 1.14 christos 304 1.14 christos for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++) 305 1.14 christos continue; 306 1.14 christos if (s == &line[len]) { 307 1.14 christos warnx("missing argument to .Sh in `%s'", pathname); 308 1.14 christos return; 309 1.14 christos } 310 1.16 augustss for (i = 0; names[i]; i++) 311 1.16 augustss if (strncasecmp(s, names[i], strlen(names[i])) == 0) 312 1.16 augustss break; 313 1.16 augustss if (names[i] == NULL) { 314 1.16 augustss warnx("first .SH section is not \"NAME\" in `%s'", pathname); 315 1.14 christos return; 316 1.3 tls } 317 1.10 christos 318 1.3 tls if (tocrc) 319 1.3 tls doname(name); 320 1.10 christos 321 1.10 christos for (i = 0;; i++) { 322 1.10 christos if ((line = fgetln(stdin, &len)) == NULL) 323 1.3 tls break; 324 1.10 christos 325 1.10 christos if (line[0] == '.') { 326 1.13 fair if (line[1] == '\\' && line[2] == '"') 327 1.13 fair continue; /* [nt]roff comment */ 328 1.10 christos if (line[1] == 'S' && line[2] == 'h') 329 1.3 tls break; 330 1.1 cgd } 331 1.10 christos 332 1.10 christos if (line[len - 1] == '\n') { 333 1.10 christos line[len - 1] = '\0'; 334 1.10 christos len--; 335 1.10 christos } 336 1.10 christos 337 1.10 christos if ((ext = strrchr(name, '.')) != NULL) { 338 1.10 christos ext++; 339 1.10 christos extlen = strlen(ext); 340 1.10 christos } 341 1.10 christos else 342 1.10 christos extlen = 0; 343 1.10 christos 344 1.10 christos if (maxlen + extlen < curlen + len + SLOP) { 345 1.22 itojun newmaxlen = 2 * (curlen + len) + SLOP + extlen; 346 1.22 itojun if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL) 347 1.17 drochner err(1, NULL); 348 1.22 itojun linebuf = newlinebuf; 349 1.22 itojun maxlen = newmaxlen; 350 1.10 christos } 351 1.10 christos 352 1.1 cgd if (i != 0) 353 1.10 christos linebuf[curlen++] = ' '; 354 1.10 christos 355 1.10 christos remcomma(line, &len); 356 1.10 christos 357 1.10 christos if (line[0] != '.') { 358 1.10 christos (void)memcpy(&linebuf[curlen], line, len); 359 1.10 christos curlen += len; 360 1.10 christos } 361 1.10 christos else { 362 1.10 christos remquote(line, &len); 363 1.10 christos fixxref(line, &len); 364 1.8 mrg 365 1.3 tls /* 366 1.8 mrg * Put section and dash between names and description. 367 1.3 tls */ 368 1.10 christos if (line[1] == 'N' && line[2] == 'd') { 369 1.15 hubertf if(!tocrc && !intro) { 370 1.15 hubertf if (extlen) { 371 1.15 hubertf linebuf[curlen++] = '('; 372 1.15 hubertf while (*ext) 373 1.15 hubertf linebuf[curlen++] = *ext++; 374 1.15 hubertf linebuf[curlen++] = ')'; 375 1.15 hubertf linebuf[curlen++] = ' '; 376 1.15 hubertf } 377 1.8 mrg } 378 1.10 christos linebuf[curlen++] = '-'; 379 1.10 christos linebuf[curlen++] = ' '; 380 1.8 mrg } 381 1.3 tls /* 382 1.3 tls * Skip over macro names. 383 1.3 tls */ 384 1.10 christos if (len <= 4) 385 1.10 christos continue; 386 1.10 christos (void)memcpy(&linebuf[curlen], &line[4], len - 4); 387 1.10 christos curlen += len - 4; 388 1.3 tls } 389 1.1 cgd } 390 1.10 christos linebuf[curlen] = '\0'; 391 1.3 tls if (intro) 392 1.10 christos split(linebuf, name); 393 1.3 tls else 394 1.23 christos (void)printf("%s\n", linebuf); 395 1.1 cgd } 396 1.1 cgd 397 1.10 christos /* 398 1.10 christos * convert " ," -> " " 399 1.10 christos */ 400 1.10 christos static void 401 1.23 christos remcomma(char *line, size_t *len) 402 1.10 christos { 403 1.10 christos char *pline = line, *loc; 404 1.10 christos size_t plen = *len; 405 1.10 christos 406 1.10 christos while ((loc = memchr(pline, ' ', plen)) != NULL) { 407 1.10 christos plen -= loc - pline + 1; 408 1.10 christos pline = loc; 409 1.10 christos if (loc[1] == ',') { 410 1.10 christos (void)memcpy(loc, &loc[1], plen); 411 1.10 christos (*len)--; 412 1.10 christos } 413 1.10 christos else 414 1.10 christos pline++; 415 1.10 christos } 416 1.10 christos } 417 1.10 christos 418 1.10 christos /* 419 1.10 christos * Get rid of quotes in macros. 420 1.10 christos */ 421 1.23 christos static void 422 1.23 christos remquote(char *line, size_t *len) 423 1.10 christos { 424 1.10 christos char *loc; 425 1.10 christos char *pline = &line[4]; 426 1.10 christos size_t plen = *len - 4; 427 1.10 christos 428 1.10 christos if (*len < 4) 429 1.10 christos return; 430 1.10 christos 431 1.10 christos while ((loc = memchr(pline, '"', plen)) != NULL) { 432 1.10 christos plen -= loc - pline + 1; 433 1.10 christos pline = loc; 434 1.10 christos (void)memcpy(loc, &loc[1], plen); 435 1.10 christos (*len)--; 436 1.10 christos } 437 1.10 christos } 438 1.10 christos 439 1.10 christos /* 440 1.10 christos * Handle cross references 441 1.10 christos */ 442 1.10 christos static void 443 1.23 christos fixxref(char *line, size_t *len) 444 1.1 cgd { 445 1.10 christos char *loc; 446 1.10 christos char *pline = &line[4]; 447 1.10 christos size_t plen = *len - 4; 448 1.1 cgd 449 1.10 christos if (*len < 4) 450 1.10 christos return; 451 1.10 christos 452 1.10 christos if (line[1] == 'X' && line[2] == 'r') { 453 1.10 christos if ((loc = memchr(pline, ' ', plen)) != NULL) { 454 1.10 christos *loc++ = '('; 455 1.10 christos loc++; 456 1.10 christos *loc++ = ')'; 457 1.10 christos *len = loc - line; 458 1.10 christos } 459 1.10 christos } 460 1.1 cgd } 461 1.1 cgd 462 1.10 christos static void 463 1.23 christos doname(char *name) 464 1.1 cgd { 465 1.9 lukem char *dp = name, *ep; 466 1.1 cgd 467 1.1 cgd again: 468 1.1 cgd while (*dp && *dp != '.') 469 1.23 christos (void)putchar(*dp++); 470 1.1 cgd if (*dp) 471 1.1 cgd for (ep = dp+1; *ep; ep++) 472 1.1 cgd if (*ep == '.') { 473 1.23 christos (void)putchar(*dp++); 474 1.1 cgd goto again; 475 1.1 cgd } 476 1.23 christos (void)putchar('('); 477 1.1 cgd if (*dp) 478 1.1 cgd dp++; 479 1.1 cgd while (*dp) 480 1.23 christos (void)putchar(*dp++); 481 1.23 christos (void)putchar(')'); 482 1.23 christos (void)putchar(' '); 483 1.1 cgd } 484 1.1 cgd 485 1.10 christos static void 486 1.23 christos split(char *line, char *name) 487 1.1 cgd { 488 1.9 lukem char *cp, *dp; 489 1.23 christos char *sp; 490 1.23 christos const char *sep; 491 1.1 cgd 492 1.3 tls cp = strchr(line, '-'); 493 1.1 cgd if (cp == 0) 494 1.1 cgd return; 495 1.1 cgd sp = cp + 1; 496 1.1 cgd for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--) 497 1.1 cgd ; 498 1.1 cgd *++cp = '\0'; 499 1.1 cgd while (*sp && (*sp == ' ' || *sp == '\t')) 500 1.1 cgd sp++; 501 1.1 cgd for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") { 502 1.3 tls cp = strchr(dp, ','); 503 1.1 cgd if (cp) { 504 1.9 lukem char *tp; 505 1.1 cgd 506 1.1 cgd for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--) 507 1.1 cgd ; 508 1.1 cgd *++tp = '\0'; 509 1.1 cgd for (++cp; *cp == ' ' || *cp == '\t'; cp++) 510 1.1 cgd ; 511 1.1 cgd } 512 1.23 christos (void)printf("%s%s\t", sep, dp); 513 1.1 cgd dorefname(name); 514 1.23 christos (void)printf("\t- %s", sp); 515 1.1 cgd } 516 1.23 christos (void)putchar('\n'); 517 1.1 cgd } 518 1.1 cgd 519 1.10 christos static void 520 1.23 christos dorefname(char *name) 521 1.1 cgd { 522 1.9 lukem char *dp = name, *ep; 523 1.1 cgd 524 1.1 cgd again: 525 1.1 cgd while (*dp && *dp != '.') 526 1.23 christos (void)putchar(*dp++); 527 1.1 cgd if (*dp) 528 1.1 cgd for (ep = dp+1; *ep; ep++) 529 1.1 cgd if (*ep == '.') { 530 1.23 christos (void)putchar(*dp++); 531 1.1 cgd goto again; 532 1.1 cgd } 533 1.23 christos (void)putchar('.'); 534 1.1 cgd if (*dp) 535 1.1 cgd dp++; 536 1.1 cgd while (*dp) 537 1.23 christos (void)putchar(*dp++); 538 1.1 cgd } 539 1.1 cgd 540 1.10 christos static void 541 1.23 christos usage(void) 542 1.1 cgd { 543 1.19 cgd 544 1.19 cgd (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", getprogname()); 545 1.1 cgd exit(1); 546 1.1 cgd } 547