|
|
1.1 ! root 1: /* Generate doc-string file for GNU Emacs from source files. ! 2: Copyright (C) 1985, 1986 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is distributed in the hope that it will be useful, ! 7: but without any warranty. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. ! 11: ! 12: Everyone is granted permission to copy, modify and redistribute ! 13: GNU Emacs, but only under the conditions described in the ! 14: document "GNU Emacs copying permission notice". An exact copy ! 15: of the document is supposed to have been given to you along with ! 16: GNU Emacs so that you can know how you may redistribute it all. ! 17: It should be in a file named COPYING. Among other things, the ! 18: copyright notice and this notice must be preserved on all copies. */ ! 19: ! 20: /* The arguments given to this program are all the C and Lisp source files ! 21: of GNU Emacs. .elc and .el and .c files are allowed. ! 22: A .o file can also be specified; the .c file it was made from is used. ! 23: This helps the makefile pass the correct list of files. ! 24: ! 25: The results, which go to standard output or to a file ! 26: specified with -a or -o (-a to append, -o to start from nothing), ! 27: are entries containing function or variable names and their documentation. ! 28: Each entry starts with a ^_ character. ! 29: Then comes F for a function or V for a variable. ! 30: Then comes the function or variable name, terminated with a newline. ! 31: Then comes the documentation for that function or variable. ! 32: */ ! 33: ! 34: #include <stdio.h> ! 35: ! 36: FILE *outfile; ! 37: ! 38: main (argc, argv) ! 39: int argc; ! 40: char **argv; ! 41: { ! 42: int i; ! 43: int err_count = 0; ! 44: ! 45: outfile = stdout; ! 46: ! 47: /* If first two args are -o FILE, output to FILE. */ ! 48: i = 1; ! 49: if (argc > i + 1 && !strcmp (argv[i], "-o")) ! 50: { ! 51: outfile = fopen (argv[i + 1], "w"); ! 52: i += 2; ! 53: } ! 54: if (argc > i + 1 && !strcmp (argv[i], "-a")) ! 55: { ! 56: outfile = fopen (argv[i + 1], "a"); ! 57: i += 2; ! 58: } ! 59: ! 60: for (; i < argc; i++) ! 61: err_count += scan_file (argv[i]); /* err_count seems to be {mis,un}used */ ! 62: #ifndef VMS ! 63: exit (err_count); /* see below - shane */ ! 64: #endif VMS ! 65: } ! 66: ! 67: /* Read file FILENAME and output its doc strings to stdout. */ ! 68: /* Return 1 if file is not found, 0 if it is found. */ ! 69: ! 70: scan_file (filename) ! 71: char *filename; ! 72: { ! 73: int len = strlen (filename); ! 74: if (!strcmp (filename + len - 4, ".elc")) ! 75: return scan_lisp_file (filename); ! 76: else if (!strcmp (filename + len - 3, ".el")) ! 77: return scan_lisp_file (filename); ! 78: else ! 79: return scan_c_file (filename); ! 80: } ! 81: ! 82: char buf[128]; ! 83: ! 84: /* Skip a C string from INFILE, ! 85: and return the character that follows the closing ". ! 86: If printflag is positive, output string contents to stdout. ! 87: If it is negative, store contents in buf. ! 88: Convert escape sequences \n and \t to newline and tab; ! 89: discard \ followed by newline. */ ! 90: ! 91: read_c_string (infile, printflag) ! 92: FILE *infile; ! 93: int printflag; ! 94: { ! 95: register int c; ! 96: char *p = buf; ! 97: ! 98: c = getc (infile); ! 99: while (c != EOF) ! 100: { ! 101: while (c != '"' && c != EOF) ! 102: { ! 103: if (c == '\\') ! 104: { ! 105: c = getc (infile); ! 106: if (c == '\n') ! 107: { ! 108: c = getc (infile); ! 109: continue; ! 110: } ! 111: if (c == 'n') ! 112: c = '\n'; ! 113: if (c == 't') ! 114: c = '\t'; ! 115: } ! 116: if (printflag > 0) ! 117: putc (c, outfile); ! 118: else if (printflag < 0) ! 119: *p++ = c; ! 120: c = getc (infile); ! 121: } ! 122: c = getc (infile); ! 123: if (c != '"') ! 124: break; ! 125: if (printflag > 0) ! 126: putc (c, outfile); ! 127: else if (printflag < 0) ! 128: *p++ = c; ! 129: c = getc (infile); ! 130: } ! 131: ! 132: if (printflag < 0) ! 133: *p = 0; ! 134: ! 135: return c; ! 136: } ! 137: ! 138: /* Read through a c file. If a .o file is named, ! 139: the corresponding .c file is read instead. ! 140: Looks for DEFUN constructs such as are defined in ../src/lisp.h. ! 141: Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */ ! 142: ! 143: scan_c_file (filename) ! 144: char *filename; ! 145: { ! 146: FILE *infile; ! 147: register int c; ! 148: register int commas; ! 149: register int defunflag; ! 150: register int defvarflag; ! 151: ! 152: if (filename[strlen (filename) - 1] == 'o') ! 153: filename[strlen (filename) - 1] = 'c'; ! 154: ! 155: infile = fopen (filename, "r"); ! 156: ! 157: /* No error if non-ex input file */ ! 158: if (infile == NULL) ! 159: { ! 160: perror (filename); ! 161: return 0; ! 162: } ! 163: ! 164: c = '\n'; ! 165: while (!feof (infile)) ! 166: { ! 167: if (c != '\n') ! 168: { ! 169: c = getc (infile); ! 170: continue; ! 171: } ! 172: c = getc (infile); ! 173: if (c == ' ') ! 174: { ! 175: while (c == ' ') ! 176: c = getc (infile); ! 177: if (c != 'D') ! 178: continue; ! 179: c = getc (infile); ! 180: if (c != 'E') ! 181: continue; ! 182: c = getc (infile); ! 183: if (c != 'F') ! 184: continue; ! 185: c = getc (infile); ! 186: if (c != 'V') ! 187: continue; ! 188: defvarflag = 1; ! 189: defunflag = 0; ! 190: c = getc (infile); ! 191: } ! 192: else if (c == 'D') ! 193: { ! 194: c = getc (infile); ! 195: if (c != 'E') ! 196: continue; ! 197: c = getc (infile); ! 198: if (c != 'F') ! 199: continue; ! 200: c = getc (infile); ! 201: defunflag = c == 'U'; ! 202: defvarflag = 0; ! 203: } ! 204: else continue; ! 205: ! 206: while (c != '(') ! 207: { ! 208: if (c < 0) ! 209: return 0; ! 210: c = getc (infile); ! 211: } ! 212: ! 213: c = getc (infile); ! 214: if (c != '"') ! 215: continue; ! 216: c = read_c_string (infile, -1); ! 217: ! 218: if (defunflag) ! 219: commas = 5; ! 220: else if (defvarflag) ! 221: commas = 1; ! 222: else /* For DEFSIMPLE and DEFPRED */ ! 223: commas = 2; ! 224: ! 225: while (commas) ! 226: { ! 227: if (c == ',') commas --; ! 228: if (c < 0) ! 229: return 0; ! 230: c = getc (infile); ! 231: } ! 232: while (c == ' ' || c == '\n' || c == '\t') ! 233: c = getc (infile); ! 234: if (c == '"') ! 235: c = read_c_string (infile, 0); ! 236: while (c != ',') ! 237: c = getc (infile); ! 238: c = getc (infile); ! 239: while (c == ' ' || c == '\n' || c == '\t') ! 240: c = getc (infile); ! 241: ! 242: if (c == '"') ! 243: { ! 244: putc (037, outfile); ! 245: putc (defvarflag ? 'V' : 'F', outfile); ! 246: fprintf (outfile, "%s\n", buf); ! 247: read_c_string (infile, 1); ! 248: } ! 249: } ! 250: fclose (infile); ! 251: return 0; ! 252: } ! 253: ! 254: /* Read a file of Lisp code, compiled or interpreted. ! 255: Looks for ! 256: (defun NAME ARGS DOCSTRING ...) ! 257: (autoload 'NAME FILE DOCSTRING ...) ! 258: (defvar NAME VALUE DOCSTRING) ! 259: (defconst NAME VALUE DOCSTRING) ! 260: starting in column zero. ! 261: ARGS, FILE or VALUE is ignored. We do not know how to parse Lisp code ! 262: so we use a kludge to skip them: ! 263: In a function definition, the form of ARGS of FILE is known, and we ! 264: can skip it. ! 265: In a variable definition, we use a formatting convention: ! 266: the DOCSTRING, if present, must be followed by a closeparen and a newline, ! 267: and no newline must appear between the defvar or defconst and the docstring, ! 268: The only source file that must follow this convention is loaddefs.el; ! 269: aside from that, it is always the .elc file that we look at, and ! 270: they are no problem because byte-compiler output follows this convention. ! 271: The NAME and DOCSTRING are output. ! 272: NAME is preceded by `F' for a function or `V' for a variable. ! 273: An entry is output only if DOCSTRING has \ newline just after the opening " ! 274: */ ! 275: ! 276: scan_lisp_file (filename) ! 277: char *filename; ! 278: { ! 279: FILE *infile; ! 280: register int c; ! 281: register int commas; ! 282: register char *p; ! 283: int defvarflag; ! 284: ! 285: infile = fopen (filename, "r"); ! 286: if (infile == NULL) ! 287: { ! 288: perror (filename); ! 289: return 0; /* No error */ ! 290: } ! 291: ! 292: c = '\n'; ! 293: while (!feof (infile)) ! 294: { ! 295: if (c != '\n') ! 296: { ! 297: c = getc (infile); ! 298: continue; ! 299: } ! 300: c = getc (infile); ! 301: if (c != '(') ! 302: continue; ! 303: c = getc (infile); ! 304: if (c == 'a') ! 305: { ! 306: c = getc (infile); ! 307: if (c != 'u') ! 308: continue; ! 309: c = getc (infile); ! 310: if (c != 't') ! 311: continue; ! 312: c = getc (infile); ! 313: if (c != 'o') ! 314: continue; ! 315: c = getc (infile); ! 316: if (c != 'l') ! 317: continue; ! 318: c = getc (infile); ! 319: if (c != 'o') ! 320: continue; ! 321: c = getc (infile); ! 322: if (c != 'a') ! 323: continue; ! 324: c = getc (infile); ! 325: if (c != 'd') ! 326: continue; ! 327: ! 328: c = getc (infile); ! 329: while (c == ' ') ! 330: c = getc (infile); ! 331: ! 332: if (c == '\'') ! 333: { ! 334: c = getc (infile); ! 335: } ! 336: else ! 337: { ! 338: if (c != '(') ! 339: continue; ! 340: c = getc (infile); ! 341: if (c != 'q') ! 342: continue; ! 343: c = getc (infile); ! 344: if (c != 'u') ! 345: continue; ! 346: c = getc (infile); ! 347: if (c != 'o') ! 348: continue; ! 349: c = getc (infile); ! 350: if (c != 't') ! 351: continue; ! 352: c = getc (infile); ! 353: if (c != 'e') ! 354: continue; ! 355: c = getc (infile); ! 356: if (c != ' ') ! 357: continue; ! 358: while (c == ' ') ! 359: c = getc (infile); ! 360: } ! 361: ! 362: p = buf; ! 363: while (c != ' ' && c != ')') ! 364: { ! 365: if (c == EOF) ! 366: return 1; ! 367: if (c == '\\') ! 368: c = getc (infile); ! 369: *p++ = c; ! 370: c = getc (infile); ! 371: } ! 372: *p = 0; ! 373: ! 374: while (c != '"') ! 375: { ! 376: if (c == EOF) ! 377: return 1; ! 378: c = getc (infile); ! 379: } ! 380: c = read_c_string (infile, 0); ! 381: } ! 382: else if (c == 'd') ! 383: { ! 384: c = getc (infile); ! 385: if (c != 'e') ! 386: continue; ! 387: c = getc (infile); ! 388: if (c != 'f') ! 389: continue; ! 390: c = getc (infile); ! 391: if (c == 'u') ! 392: { ! 393: c = getc (infile); ! 394: if (c != 'n') ! 395: continue; ! 396: defvarflag = 0; ! 397: } ! 398: else if (c == 'v') ! 399: { ! 400: c = getc (infile); ! 401: if (c != 'a') ! 402: continue; ! 403: c = getc (infile); ! 404: if (c != 'r') ! 405: continue; ! 406: defvarflag = 1; ! 407: } ! 408: else if (c == 'c') ! 409: { ! 410: c = getc (infile); ! 411: if (c != 'o') ! 412: continue; ! 413: c = getc (infile); ! 414: if (c != 'n') ! 415: continue; ! 416: c = getc (infile); ! 417: if (c != 's') ! 418: continue; ! 419: c = getc (infile); ! 420: if (c != 't') ! 421: continue; ! 422: defvarflag = 1; ! 423: } ! 424: else ! 425: continue; ! 426: ! 427: /* Now we have seen "defun" or "defvar" or "defconst". */ ! 428: ! 429: while (c != ' ' && c != '\n' && c != '\t') ! 430: c = getc (infile); ! 431: ! 432: while (c == ' ' || c == '\n' || c == '\t') ! 433: c = getc (infile); ! 434: ! 435: /* Read and store name of function or variable being defined ! 436: Discard backslashes that are for quoting. */ ! 437: p = buf; ! 438: while (c != ' ' && c != '\n' && c != '\t') ! 439: { ! 440: if (c == '\\') ! 441: c = getc (infile); ! 442: *p++ = c; ! 443: c = getc (infile); ! 444: } ! 445: *p = 0; ! 446: ! 447: while (c == ' ' || c == '\n' || c == '\t') ! 448: c = getc (infile); ! 449: ! 450: if (! defvarflag) ! 451: { ! 452: /* A function: */ ! 453: /* Skip the arguments: either "nil" or a list in parens */ ! 454: if (c == 'n') ! 455: { ! 456: while (c != ' ' && c != '\n' && c != '\t') ! 457: c = getc (infile); ! 458: } ! 459: else ! 460: { ! 461: while (c != '(') ! 462: c = getc (infile); ! 463: while (c != ')') ! 464: c = getc (infile); ! 465: } ! 466: c = getc (infile); ! 467: } ! 468: else ! 469: { ! 470: /* A variable: */ ! 471: ! 472: /* Skip until the first newline; remember ! 473: the two previous characters. */ ! 474: char c1 = 0, c2 = 0; ! 475: ! 476: while (c != '\n' && c >= 0) ! 477: { ! 478: c2 = c1; ! 479: c1 = c; ! 480: c = getc (infile); ! 481: } ! 482: ! 483: /* If two previous characters were " and \, ! 484: this is a doc string. Otherwise, there is none. */ ! 485: if (c2 == '"' && c1 == '\\') ! 486: { ! 487: putc (037, outfile); ! 488: putc ('V', outfile); ! 489: fprintf (outfile, "%s\n", buf); ! 490: read_c_string (infile, 1); ! 491: } ! 492: continue; ! 493: } ! 494: } ! 495: else ! 496: continue; ! 497: ! 498: /* Here for a function definition. ! 499: We have skipped the file name or arguments ! 500: and arrived at where the doc string is, ! 501: if there is a doc string. */ ! 502: ! 503: /* Skip whitespace */ ! 504: ! 505: while (c == ' ' || c == '\n' || c == '\t') ! 506: c = getc (infile); ! 507: ! 508: /* " followed by \ and newline means a doc string we should gobble */ ! 509: if (c != '"') ! 510: continue; ! 511: c = getc (infile); ! 512: if (c != '\\') ! 513: continue; ! 514: c = getc (infile); ! 515: if (c != '\n') ! 516: continue; ! 517: ! 518: putc (037, outfile); ! 519: putc ('F', outfile); ! 520: fprintf (outfile, "%s\n", buf); ! 521: read_c_string (infile, 1); ! 522: } ! 523: fclose (infile); ! 524: return 0; ! 525: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.