aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src
diff options
context:
space:
mode:
authorStefan Monnier2022-01-03 15:04:12 -0500
committerStefan Monnier2022-01-03 15:04:12 -0500
commit460f35e96df1c39ce2ba0f424b36365a2f9e9825 (patch)
tree28398a961fccf9538114174b32d96f5dd918043a /lib-src
parentab5ee3e29e916d4009b301841e9780aad564a6a0 (diff)
downloademacs-460f35e96df1c39ce2ba0f424b36365a2f9e9825.tar.gz
emacs-460f35e96df1c39ce2ba0f424b36365a2f9e9825.zip
Revert part of 59732a83c8 to fix bug#52969
While we don't need to put docstrings of .elc files into etc/DOC, we still need to put those of `loaddefs.el` there since we don't have a "dynamic docstring" feature for the non-compiled files and keeping the actual docstrings in the heap would be prohibitive. * src/Makefile.in ($(etc)/DOC): Scan `lisp/loaddefs.el` still. * lib-src/make-docfile.c (scan_lisp_file): New function. (scan_file): Use it. (skip_white, read_lisp_symbol, search_lisp_doc_at_eol): New functions.
Diffstat (limited to 'lib-src')
-rw-r--r--lib-src/make-docfile.c362
1 files changed, 359 insertions, 3 deletions
diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c
index 33ed5ec0c92..199f1dbbcc7 100644
--- a/lib-src/make-docfile.c
+++ b/lib-src/make-docfile.c
@@ -19,8 +19,8 @@ You should have received a copy of the GNU General Public License
19along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ 19along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20 20
21 21
22/* The arguments given to this program are all the C files 22/* The arguments given to this program are all the C and some Lisp source files
23 of GNU Emacs. .c files are allowed. 23 of GNU Emacs. .el and .c files are allowed.
24 A .o file can also be specified; the .c file it was made from is used. 24 A .o file can also be specified; the .c file it was made from is used.
25 This helps the makefile pass the correct list of files. 25 This helps the makefile pass the correct list of files.
26 Option -d DIR means change to DIR before looking for files. 26 Option -d DIR means change to DIR before looking for files.
@@ -65,6 +65,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
65#endif /* not DOS_NT */ 65#endif /* not DOS_NT */
66 66
67static void scan_file (char *filename); 67static void scan_file (char *filename);
68static void scan_lisp_file (const char *filename, const char *mode);
68static void scan_c_file (char *filename, const char *mode); 69static void scan_c_file (char *filename, const char *mode);
69static void scan_c_stream (FILE *infile); 70static void scan_c_stream (FILE *infile);
70static void start_globals (void); 71static void start_globals (void);
@@ -234,9 +235,14 @@ put_filename (char *filename)
234static void 235static void
235scan_file (char *filename) 236scan_file (char *filename)
236{ 237{
238 ptrdiff_t len = strlen (filename);
239
237 if (!generate_globals) 240 if (!generate_globals)
238 put_filename (filename); 241 put_filename (filename);
239 scan_c_file (filename, "r"); 242 if (len > 3 && !strcmp (filename + len - 3, ".el"))
243 scan_lisp_file (filename, "r");
244 else
245 scan_c_file (filename, "r");
240} 246}
241 247
242static void 248static void
@@ -1214,4 +1220,354 @@ scan_c_stream (FILE *infile)
1214 fatal ("read error"); 1220 fatal ("read error");
1215} 1221}
1216 1222
1223/* Read a file of Lisp source code.
1224 Looks for
1225 (defun NAME ARGS DOCSTRING ...)
1226 (defmacro NAME ARGS DOCSTRING ...)
1227 (defsubst NAME ARGS DOCSTRING ...)
1228 (autoload (quote NAME) FILE DOCSTRING ...)
1229 (defvar NAME VALUE DOCSTRING)
1230 (defconst NAME VALUE DOCSTRING)
1231 (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
1232 (fset (quote NAME) #[... DOCSTRING ...])
1233 (defalias (quote NAME) #[... DOCSTRING ...])
1234 (custom-declare-variable (quote NAME) VALUE DOCSTRING ...)
1235 starting in column zero.
1236 (quote NAME) may appear as 'NAME as well.
1237
1238 We also look for #@LENGTH CONTENTS^_ at the beginning of the line.
1239 When we find that, we save it for the following defining-form,
1240 and we use that instead of reading a doc string within that defining-form.
1241
1242 For defvar, defconst, and fset we skip to the docstring with a kludgy
1243 formatting convention: all docstrings must appear on the same line as the
1244 initial open-paren (the one in column zero) and must contain a backslash
1245 and a newline immediately after the initial double-quote. No newlines
1246 must appear between the beginning of the form and the first double-quote.
1247 For defun, defmacro, and autoload, we know how to skip over the
1248 arglist, but the doc string must still have a backslash and newline
1249 immediately after the double quote.
1250 The only source files that follow this convention are autoload-generated
1251 files like loaddefs.el;
1252 The NAME and DOCSTRING are output.
1253 NAME is preceded by `F' for a function or `V' for a variable.
1254 An entry is output only if DOCSTRING has \ newline just after the opening ".
1255 */
1256
1257static void
1258skip_white (FILE *infile)
1259{
1260 int c;
1261 do
1262 c = getc (infile);
1263 while (c_isspace (c));
1264
1265 ungetc (c, infile);
1266}
1267
1268static void
1269read_lisp_symbol (FILE *infile, char *buffer)
1270{
1271 int c;
1272 char *fillp = buffer;
1273
1274 skip_white (infile);
1275 while (true)
1276 {
1277 c = getc (infile);
1278 if (c == '\\')
1279 {
1280 c = getc (infile);
1281 if (c < 0)
1282 return;
1283 *fillp++ = c;
1284 }
1285 else if (c_isspace (c) || c == '(' || c == ')' || c < 0)
1286 {
1287 ungetc (c, infile);
1288 *fillp = 0;
1289 break;
1290 }
1291 else
1292 *fillp++ = c;
1293 }
1294
1295 if (! buffer[0])
1296 fprintf (stderr, "## expected a symbol, got '%c'\n", c);
1297
1298 skip_white (infile);
1299}
1300
1301static bool
1302search_lisp_doc_at_eol (FILE *infile)
1303{
1304 int c = 0, c1 = 0, c2 = 0;
1305
1306 /* Skip until the end of line; remember two previous chars. */
1307 while (c != '\n' && c != '\r' && c != EOF)
1308 {
1309 c2 = c1;
1310 c1 = c;
1311 c = getc (infile);
1312 }
1313
1314 /* If two previous characters were " and \,
1315 this is a doc string. Otherwise, there is none. */
1316 if (c2 != '"' || c1 != '\\')
1317 {
1318#ifdef DEBUG
1319 fprintf (stderr, "## non-docstring found\n");
1320#endif
1321 ungetc (c, infile);
1322 return false;
1323 }
1324 return true;
1325}
1326
1327static void
1328scan_lisp_file (const char *filename, const char *mode)
1329{
1330 FILE *infile;
1331 int c;
1332 int i;
1333 int flen = strlen (filename);
1334
1335 if (generate_globals)
1336 fatal ("scanning lisp file when -g specified");
1337
1338 infile = fopen (filename, mode);
1339 if (infile == NULL)
1340 {
1341 perror (filename);
1342 exit (EXIT_FAILURE);
1343 }
1344
1345 c = '\n';
1346 while (!feof (infile))
1347 {
1348 char buffer[BUFSIZ];
1349 char type;
1350
1351 /* If not at end of line, skip till we get to one. */
1352 if (c != '\n' && c != '\r')
1353 {
1354 c = getc (infile);
1355 continue;
1356 }
1357 /* Skip the line break. */
1358 while (c == '\n' || c == '\r')
1359 c = getc (infile);
1360
1361 if (c != '(')
1362 continue;
1363
1364 read_lisp_symbol (infile, buffer);
1365
1366 if (! strcmp (buffer, "defun")
1367 || ! strcmp (buffer, "defmacro")
1368 || ! strcmp (buffer, "defsubst"))
1369 {
1370 type = 'F';
1371 read_lisp_symbol (infile, buffer);
1372
1373 /* Skip the arguments: either "nil" or a list in parens. */
1374
1375 c = getc (infile);
1376 if (c == 'n') /* nil */
1377 {
1378 if ((c = getc (infile)) != 'i'
1379 || (c = getc (infile)) != 'l')
1380 {
1381 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
1382 buffer, filename);
1383 continue;
1384 }
1385 }
1386 else if (c != '(')
1387 {
1388 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
1389 buffer, filename);
1390 continue;
1391 }
1392 else
1393 while (! (c == ')' || c < 0))
1394 c = getc (infile);
1395 skip_white (infile);
1396
1397 /* If the next three characters aren't `dquote bslash newline'
1398 then we're not reading a docstring.
1399 */
1400 if ((c = getc (infile)) != '"'
1401 || (c = getc (infile)) != '\\'
1402 || ((c = getc (infile)) != '\n' && c != '\r'))
1403 {
1404#ifdef DEBUG
1405 fprintf (stderr, "## non-docstring in %s (%s)\n",
1406 buffer, filename);
1407#endif
1408 continue;
1409 }
1410 }
1411
1412 else if (! strcmp (buffer, "defvar")
1413 || ! strcmp (buffer, "defconst")
1414 || ! strcmp (buffer, "defcustom"))
1415 {
1416 type = 'V';
1417 read_lisp_symbol (infile, buffer);
1418
1419 if (!search_lisp_doc_at_eol (infile))
1420 continue;
1421 }
1422
1423 else if (! strcmp (buffer, "custom-declare-variable")
1424 || ! strcmp (buffer, "defvaralias")
1425 )
1426 {
1427 type = 'V';
1428
1429 c = getc (infile);
1430 if (c == '\'')
1431 read_lisp_symbol (infile, buffer);
1432 else
1433 {
1434 if (c != '(')
1435 {
1436 fprintf (stderr,
1437 "## unparsable name in custom-declare-variable in %s\n",
1438 filename);
1439 continue;
1440 }
1441 read_lisp_symbol (infile, buffer);
1442 if (strcmp (buffer, "quote"))
1443 {
1444 fprintf (stderr,
1445 "## unparsable name in custom-declare-variable in %s\n",
1446 filename);
1447 continue;
1448 }
1449 read_lisp_symbol (infile, buffer);
1450 c = getc (infile);
1451 if (c != ')')
1452 {
1453 fprintf (stderr,
1454 "## unparsable quoted name in custom-declare-variable in %s\n",
1455 filename);
1456 continue;
1457 }
1458 }
1459
1460 if (!search_lisp_doc_at_eol (infile))
1461 continue;
1462 }
1463
1464 else if (! strcmp (buffer, "fset") || ! strcmp (buffer, "defalias"))
1465 {
1466 type = 'F';
1467
1468 c = getc (infile);
1469 if (c == '\'')
1470 read_lisp_symbol (infile, buffer);
1471 else
1472 {
1473 if (c != '(')
1474 {
1475 fprintf (stderr, "## unparsable name in fset in %s\n",
1476 filename);
1477 continue;
1478 }
1479 read_lisp_symbol (infile, buffer);
1480 if (strcmp (buffer, "quote"))
1481 {
1482 fprintf (stderr, "## unparsable name in fset in %s\n",
1483 filename);
1484 continue;
1485 }
1486 read_lisp_symbol (infile, buffer);
1487 c = getc (infile);
1488 if (c != ')')
1489 {
1490 fprintf (stderr,
1491 "## unparsable quoted name in fset in %s\n",
1492 filename);
1493 continue;
1494 }
1495 }
1496
1497 if (!search_lisp_doc_at_eol (infile))
1498 continue;
1499 }
1500
1501 else if (! strcmp (buffer, "autoload"))
1502 {
1503 type = 'F';
1504 c = getc (infile);
1505 if (c == '\'')
1506 read_lisp_symbol (infile, buffer);
1507 else
1508 {
1509 if (c != '(')
1510 {
1511 fprintf (stderr, "## unparsable name in autoload in %s\n",
1512 filename);
1513 continue;
1514 }
1515 read_lisp_symbol (infile, buffer);
1516 if (strcmp (buffer, "quote"))
1517 {
1518 fprintf (stderr, "## unparsable name in autoload in %s\n",
1519 filename);
1520 continue;
1521 }
1522 read_lisp_symbol (infile, buffer);
1523 c = getc (infile);
1524 if (c != ')')
1525 {
1526 fprintf (stderr,
1527 "## unparsable quoted name in autoload in %s\n",
1528 filename);
1529 continue;
1530 }
1531 }
1532 skip_white (infile);
1533 c = getc (infile);
1534 if (c != '\"')
1535 {
1536 fprintf (stderr, "## autoload of %s unparsable (%s)\n",
1537 buffer, filename);
1538 continue;
1539 }
1540 read_c_string_or_comment (infile, 0, false, 0);
1541
1542 if (!search_lisp_doc_at_eol (infile))
1543 continue;
1544 }
1545
1546#ifdef DEBUG
1547 else if (! strcmp (buffer, "if")
1548 || ! strcmp (buffer, "byte-code"))
1549 continue;
1550#endif
1551
1552 else
1553 {
1554#ifdef DEBUG
1555 fprintf (stderr, "## unrecognized top-level form, %s (%s)\n",
1556 buffer, filename);
1557#endif
1558 continue;
1559 }
1560
1561 /* At this point, we should gobble a doc string from the input file.
1562 The opening quote (and leading backslash-newline)
1563 have already been read. */
1564
1565 printf ("\037%c%s\n", type, buffer);
1566 read_c_string_or_comment (infile, 1, false, 0);
1567 }
1568 if (ferror (infile) || fclose (infile) != 0)
1569 fatal ("%s: read error", filename);
1570}
1571
1572
1217/* make-docfile.c ends here */ 1573/* make-docfile.c ends here */