1 /* $NetBSD: defun.c,v 1.4 2025/12/31 22:18:50 oster Exp $ */ 2 3 /* defun.c -- @defun and friends. 4 Id: defun.c,v 1.11 2004/04/11 17:56:46 karl Exp 5 6 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software 7 Foundation, Inc. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2, or (at your option) 12 any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software Foundation, 21 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 22 23 #include "system.h" 24 #include "defun.h" 25 #include "xml.h" 26 #include "insertion.h" 27 #include "makeinfo.h" 28 #include "cmds.h" 29 #include "html.h" 30 31 32 #define DEFUN_SELF_DELIMITING(c) \ 33 ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']') 34 35 struct token_accumulator 36 { 37 unsigned int length; 38 unsigned int index; 39 char **tokens; 40 }; 41 42 static void 43 initialize_token_accumulator (struct token_accumulator *accumulator) 44 { 45 accumulator->length = 0; 46 accumulator->index = 0; 47 accumulator->tokens = NULL; 48 } 49 50 static void 51 accumulate_token (struct token_accumulator *accumulator, char *token) 52 { 53 if (accumulator->index >= accumulator->length) 54 { 55 accumulator->length += 10; 56 accumulator->tokens = xrealloc (accumulator->tokens, 57 (accumulator->length * sizeof (char *))); 58 } 59 accumulator->tokens[accumulator->index] = token; 60 accumulator->index += 1; 61 } 62 63 /* Given STRING_POINTER pointing at an open brace, skip forward and return a 64 pointer to just past the matching close brace. */ 65 static int 66 scan_group_in_string (char **string_pointer) 67 { 68 char *scan_string = (*string_pointer) + 1; 69 unsigned int level = 1; 70 int started_command = 0; 71 72 for (;;) 73 { 74 int c; 75 if (level == 0) 76 { 77 *string_pointer = scan_string; 78 return 1; 79 } 80 c = *scan_string++; 81 if (c == 0) 82 { 83 /* Tweak line_number to compensate for fact that 84 we gobbled the whole line before coming here. */ 85 line_number--; 86 line_error (_("Missing `}' in @def arg")); 87 line_number++; 88 *string_pointer = scan_string - 1; 89 return 0; 90 } 91 92 if (c == '{' && !started_command) 93 level++; 94 if (c == '}' && !started_command) 95 level--; 96 97 /* remember if at @. */ 98 started_command = (c == '@' && !started_command); 99 } 100 } 101 102 /* Return a list of tokens from the contents of STRING. 103 Commands and brace-delimited groups count as single tokens. 104 Contiguous whitespace characters are converted to a token 105 consisting of a single space. */ 106 static char ** 107 args_from_string (char *string) 108 { 109 struct token_accumulator accumulator; 110 char *token_start, *token_end; 111 char *scan_string = string; 112 113 initialize_token_accumulator (&accumulator); 114 115 while (*scan_string) 116 { /* Replace arbitrary whitespace by a single space. */ 117 if (whitespace (*scan_string)) 118 { 119 scan_string += 1; 120 while (whitespace (*scan_string)) 121 scan_string += 1; 122 accumulate_token ((&accumulator), (xstrdup (" "))); 123 continue; 124 } 125 126 /* Commands count as single tokens. */ 127 if (*scan_string == COMMAND_PREFIX) 128 { 129 token_start = scan_string; 130 scan_string += 1; 131 if (self_delimiting (*scan_string)) 132 scan_string += 1; 133 else 134 { 135 int c; 136 while (1) 137 { 138 c = *scan_string++; 139 140 if ((c == 0) || (c == '{') || (whitespace (c))) 141 { 142 scan_string -= 1; 143 break; 144 } 145 } 146 147 if (*scan_string == '{') 148 { 149 char *s = scan_string; 150 (void) scan_group_in_string (&s); 151 scan_string = s; 152 } 153 } 154 token_end = scan_string; 155 } 156 157 /* Parentheses and brackets are self-delimiting. */ 158 else if (DEFUN_SELF_DELIMITING (*scan_string)) 159 { 160 token_start = scan_string; 161 scan_string += 1; 162 token_end = scan_string; 163 } 164 165 /* Open brace introduces a group that is a single token. */ 166 else if (*scan_string == '{') 167 { 168 char *s = scan_string; 169 int balanced = scan_group_in_string (&s); 170 171 token_start = scan_string + 1; 172 scan_string = s; 173 token_end = balanced ? (scan_string - 1) : scan_string; 174 } 175 176 /* Make commas separate tokens so to differentiate them from 177 parameter types in XML output. */ 178 else if (*scan_string == ',') 179 { 180 token_start = scan_string; 181 scan_string += 1; 182 token_end = scan_string; 183 } 184 185 /* Otherwise a token is delimited by whitespace, parentheses, 186 brackets, or braces. A token is also ended by a command. */ 187 else 188 { 189 token_start = scan_string; 190 191 for (;;) 192 { 193 int c; 194 195 c = *scan_string++; 196 197 /* Do not back up if we're looking at a }; since the only 198 valid }'s are those matched with {'s, we want to give 199 an error. If we back up, we go into an infinite loop. */ 200 if (!c || whitespace (c) || DEFUN_SELF_DELIMITING (c) 201 || c == '{') 202 { 203 scan_string--; 204 break; 205 } 206 207 /* End token if we are looking at a comma, as commas are 208 delimiters too. */ 209 if (c == ',') 210 { 211 scan_string--; 212 break; 213 } 214 215 /* If we encounter a command embedded within a token, 216 then end the token. */ 217 if (c == COMMAND_PREFIX) 218 { 219 scan_string--; 220 break; 221 } 222 } 223 token_end = scan_string; 224 } 225 226 accumulate_token (&accumulator, substring (token_start, token_end)); 227 } 228 accumulate_token (&accumulator, NULL); 229 return accumulator.tokens; 230 } 231 232 static void 233 process_defun_args (char **defun_args, int auto_var_p) 234 { 235 int pending_space = 0; 236 237 if (xml) 238 { 239 xml_process_defun_args (defun_args, auto_var_p); 240 return; 241 } 242 243 for (;;) 244 { 245 char *defun_arg = *defun_args++; 246 247 if (defun_arg == NULL) 248 break; 249 250 if (defun_arg[0] == ' ') 251 { 252 pending_space = 1; 253 continue; 254 } 255 256 if (pending_space) 257 { 258 add_char (' '); 259 pending_space = 0; 260 } 261 262 if (DEFUN_SELF_DELIMITING (defun_arg[0])) 263 { 264 /* Within @deffn and friends, texinfo.tex makes parentheses 265 sans serif and brackets bold. We use roman instead. */ 266 if (html) 267 insert_html_tag (START, ""); 268 269 add_char (defun_arg[0]); 270 271 if (html) 272 insert_html_tag (END, ""); 273 } 274 /* else if (defun_arg[0] == '&' || defun_arg[0] == COMMAND_PREFIX) */ 275 /* execute_string ("%s", defun_arg); */ 276 /* else if (auto_var_p) */ 277 /* execute_string ("%s", defun_arg); */ 278 else 279 execute_string ("%s", defun_arg); 280 } 281 } 282 283 static char * 284 next_nonwhite_defun_arg (char ***arg_pointer) 285 { 286 char **scan = (*arg_pointer); 287 char *arg = (*scan++); 288 289 if ((arg != 0) && (*arg == ' ')) 290 arg = *scan++; 291 292 if (arg == 0) 293 scan -= 1; 294 295 *arg_pointer = scan; 296 297 return (arg == 0) ? "" : arg; 298 } 299 300 301 /* This is needed also in insertion.c. */ 302 303 enum insertion_type 304 get_base_type (int type) 305 { 306 int base_type; 307 switch (type) 308 { 309 case defivar: base_type = defcv; break; 310 case defmac: base_type = deffn; break; 311 case defmethod: base_type = defop; break; 312 case defopt: base_type = defvr; break; 313 case defspec: base_type = deffn; break; 314 case deftypecv: base_type = deftypecv; break; 315 case deftypefun: base_type = deftypefn; break; 316 case deftypeivar: base_type = deftypeivar; break; 317 case deftypemethod: base_type = deftypemethod; break; 318 case deftypeop: base_type = deftypeop; break; 319 case deftypevar: base_type = deftypevr; break; 320 case defun: base_type = deffn; break; 321 case defvar: base_type = defvr; break; 322 default: 323 base_type = type; 324 break; 325 } 326 327 return base_type; 328 } 329 330 /* Make the defun type insertion. 332 TYPE says which insertion this is. 333 X_P, if nonzero, says not to start a new insertion. */ 334 static void 335 defun_internal (int type, int x_p) 336 { 337 int base_type; 338 char **defun_args, **scan_args; 339 const char *category; 340 char *defined_name; 341 char *type_name = NULL; 342 char *type_name2 = NULL; 343 344 { 345 char *line; 346 347 /* The @def.. line is the only place in Texinfo where you are 348 allowed to use unquoted braces that don't delimit arguments of 349 a command or a macro; in any other place it will trigger an 350 error message from the reader loop. The special handling of 351 this case inside `args_from_string' is an extra special hack 352 which allows this. The side effect is that if we try to expand 353 the rest of the line below, the recursive reader loop will 354 signal an error if there are brace-delimited arguments on that line. 355 356 The best solution to this would be to change the syntax of 357 @def.. commands so that it doesn't violate Texinfo's own rules. 358 But it's probably too late for this now, as it will break a lot 359 of existing manuals. 360 361 Unfortunately, this means that you can't call macros, use @value, etc. 362 inside @def.. commands, sigh. */ 363 get_rest_of_line (0, &line); 364 365 /* Basic line continuation. If a line ends with \s*@\s* concatanate 366 the next line. */ 367 { 368 char *next_line, *new_line; 369 int i; 370 371 line_continuation: 372 i = strlen (line) - 1; 373 374 if (line[i] == '@' && line[i-1] != '@') 375 { 376 get_rest_of_line (0, &next_line); 377 new_line = (char *) xmalloc (i + strlen (next_line) + 2); 378 strncpy (new_line, line, i); 379 new_line[i] = '\0'; 380 free (line); 381 strcat (new_line, " "); 382 strcat (new_line, next_line); 383 line = xstrdup (new_line); 384 free (next_line); 385 free (new_line); 386 387 goto line_continuation; 388 } 389 } 390 391 defun_args = (args_from_string (line)); 392 free (line); 393 } 394 395 scan_args = defun_args; 396 397 /* Get base type and category string. */ 398 base_type = get_base_type (type); 399 400 /* xx all these const strings should be determined upon 401 documentlanguage argument and NOT via gettext (kama). */ 402 switch (type) 403 { 404 case defun: 405 case deftypefun: 406 category = _("Function"); 407 break; 408 case defmac: 409 category = _("Macro"); 410 break; 411 case defspec: 412 category = _("Special Form"); 413 break; 414 case defvar: 415 case deftypevar: 416 category = _("Variable"); 417 break; 418 case defopt: 419 category = _("User Option"); 420 break; 421 case defivar: 422 case deftypeivar: 423 category = _("Instance Variable"); 424 break; 425 case defmethod: 426 case deftypemethod: 427 category = _("Method"); 428 break; 429 default: 430 category = next_nonwhite_defun_arg (&scan_args); 431 break; 432 } 433 434 /* The class name. */ 435 if ((base_type == deftypecv) 436 || (base_type == deftypefn) 437 || (base_type == deftypevr) 438 || (base_type == defcv) 439 || (base_type == defop) 440 || (base_type == deftypeivar) 441 || (base_type == deftypemethod) 442 || (base_type == deftypeop) 443 ) 444 type_name = next_nonwhite_defun_arg (&scan_args); 445 446 /* The type name for typed languages. */ 447 if ((base_type == deftypecv) 448 || (base_type == deftypeivar) 449 || (base_type == deftypemethod) 450 || (base_type == deftypeop) 451 ) 452 type_name2 = next_nonwhite_defun_arg (&scan_args); 453 454 /* The function or whatever that's actually being defined. */ 455 defined_name = next_nonwhite_defun_arg (&scan_args); 456 457 /* This hack exists solely for the purposes of formatting the Texinfo 458 manual. I couldn't think of a better way. The token might be a 459 simple @@ followed immediately by more text. If this is the case, 460 then the next defun arg is part of this one, and we should 461 concatenate them. */ 462 if (*scan_args && **scan_args && !whitespace (**scan_args) 463 && STREQ (defined_name, "@@")) 464 { 465 char *tem = xmalloc (3 + strlen (scan_args[0])); 466 467 sprintf (tem, "@@%s", scan_args[0]); 468 469 free (scan_args[0]); 470 scan_args[0] = tem; 471 scan_args++; 472 defined_name = tem; 473 } 474 475 /* It's easy to write @defun foo(arg1 arg2), but a following ( is 476 misparsed by texinfo.tex and this is next to impossible to fix. 477 Warn about it. */ 478 if (*scan_args && **scan_args && **scan_args == '(') 479 warning ("`%c' follows defined name `%s' instead of whitespace", 480 **scan_args, defined_name); 481 482 if (!x_p) 483 begin_insertion (type); 484 485 /* Write the definition header line. 486 This should start at the normal indentation. */ 487 current_indent -= default_indentation_increment; 488 start_paragraph (); 489 490 if (!html && !xml) 491 switch (base_type) 492 { 493 case deffn: 494 case defvr: 495 case deftp: 496 execute_string (" --- %s: %s", category, defined_name); 497 break; 498 case deftypefn: 499 case deftypevr: 500 execute_string (" --- %s: %s %s", category, type_name, defined_name); 501 break; 502 case defcv: 503 execute_string (" --- %s %s %s: %s", category, _("of"), type_name, 504 defined_name); 505 break; 506 case deftypecv: 507 case deftypeivar: 508 execute_string (" --- %s %s %s: %s %s", category, _("of"), type_name, 509 type_name2, defined_name); 510 break; 511 case defop: 512 execute_string (" --- %s %s %s: %s", category, _("on"), type_name, 513 defined_name); 514 break; 515 case deftypeop: 516 execute_string (" --- %s %s %s: %s %s", category, _("on"), type_name, 517 type_name2, defined_name); 518 break; 519 case deftypemethod: 520 execute_string (" --- %s %s %s: %s %s", category, _("on"), type_name, 521 type_name2, defined_name); 522 break; 523 } 524 else if (html) 525 { 526 /* If this is not a @def...x version, it could only 527 be a normal version @def.... So start the table here. */ 528 if (!x_p) 529 insert_string ("<div class=\"defun\">\n"); 530 else 531 rollback_empty_tag ("blockquote"); 532 533 /* xx The single words (on, off) used here, should depend on 534 documentlanguage and NOT on gettext --kama. */ 535 switch (base_type) 536 { 537 case deffn: 538 case defvr: 539 case deftp: 540 case deftypefn: 541 case deftypevr: 542 execute_string ("--- %s: ", category); 543 break; 544 545 case defcv: 546 case deftypecv: 547 case deftypeivar: 548 execute_string ("--- %s %s %s: ", category, _("of"), type_name); 549 break; 550 551 case defop: 552 case deftypemethod: 553 case deftypeop: 554 execute_string ("--- %s %s %s: ", category, _("on"), type_name); 555 break; 556 } /* switch (base_type)... */ 557 558 switch (base_type) 559 { 560 case deffn: 561 case defvr: 562 case deftp: 563 /* <var> is for the following function arguments. */ 564 insert_html_tag (START, "b"); 565 execute_string ("%s", defined_name); 566 insert_html_tag (END, "b"); 567 insert_html_tag (START, "var"); 568 break; 569 case deftypefn: 570 case deftypevr: 571 execute_string ("%s ", type_name); 572 insert_html_tag (START, "b"); 573 execute_string ("%s", defined_name); 574 insert_html_tag (END, "b"); 575 insert_html_tag (START, "var"); 576 break; 577 case defcv: 578 case defop: 579 insert_html_tag (START, "b"); 580 execute_string ("%s", defined_name); 581 insert_html_tag (END, "b"); 582 insert_html_tag (START, "var"); 583 break; 584 case deftypecv: 585 case deftypeivar: 586 case deftypemethod: 587 case deftypeop: 588 execute_string ("%s ", type_name2); 589 insert_html_tag (START, "b"); 590 execute_string ("%s", defined_name); 591 insert_html_tag (END, "b"); 592 insert_html_tag (START, "var"); 593 break; 594 } 595 } 596 else if (xml) 597 xml_begin_def_term (base_type, category, defined_name, type_name, 598 type_name2); 599 600 current_indent += default_indentation_increment; 601 602 /* Now process the function arguments, if any. If these carry onto 603 the next line, they should be indented by two increments to 604 distinguish them from the body of the definition, which is indented 605 by one increment. */ 606 current_indent += default_indentation_increment; 607 608 switch (base_type) 609 { 610 case deffn: 611 case defop: 612 process_defun_args (scan_args, 1); 613 break; 614 615 /* Through Makeinfo 1.67 we processed remaining args only for deftp, 616 deftypefn, and deftypemethod. But the libc manual, for example, 617 needs to say: 618 @deftypevar {char *} tzname[2] 619 And simply allowing the extra text seems far simpler than trying 620 to invent yet more defn commands. In any case, we should either 621 output it or give an error, not silently ignore it. */ 622 default: 623 process_defun_args (scan_args, 0); 624 break; 625 } 626 627 current_indent -= default_indentation_increment; 628 if (!html) 629 close_single_paragraph (); 630 631 /* Make an entry in the appropriate index. (XML and 632 Docbook already got their entries, so skip them.) */ 633 if (!xml) 634 switch (base_type) 635 { 636 case deffn: 637 case deftypefn: 638 execute_string ("@findex %s\n", defined_name); 639 break; 640 case defcv: 641 case deftypecv: 642 case deftypevr: 643 case defvr: 644 execute_string ("@vindex %s\n", defined_name); 645 break; 646 case deftypeivar: 647 execute_string ("@vindex %s %s %s\n", defined_name, _("of"), 648 type_name); 649 break; 650 case defop: 651 case deftypeop: 652 case deftypemethod: 653 execute_string ("@findex %s %s %s\n", defined_name, _("on"), 654 type_name); 655 break; 656 case deftp: 657 execute_string ("@tindex %s\n", defined_name); 658 break; 659 } 660 661 if (xml) 662 xml_end_def_term (); 663 else if (html) 664 { 665 inhibit_paragraph_indentation = 1; 666 no_indent = 1; 667 insert_html_tag (END, "var"); 668 insert_string ("<br>\n"); 669 /* Indent the definition a bit. */ 670 add_html_block_elt ("<blockquote>"); 671 no_indent = 0; 672 inhibit_paragraph_indentation = 0; 673 paragraph_is_open = 0; 674 } 675 676 /* Deallocate the token list. */ 677 scan_args = defun_args; 678 while (1) 679 { 680 char * arg = (*scan_args++); 681 if (arg == NULL) 682 break; 683 free (arg); 684 } 685 free (defun_args); 686 } 687 688 /* Add an entry for a function, macro, special form, variable, or option. 689 If the name of the calling command ends in `x', then this is an extra 690 entry included in the body of an insertion of the same type. */ 691 void 692 cm_defun (int arg, int arg2, int arg3) 693 { 694 int type; 695 char *base_command = xstrdup (command); /* command with any `x' removed */ 696 int x_p = (command[strlen (command) - 1] == 'x'); 697 698 if (x_p) 699 base_command[strlen (base_command) - 1] = 0; 700 701 type = find_type_from_name (base_command); 702 703 /* If we are adding to an already existing insertion, then make sure 704 that we are already in an insertion of type TYPE. */ 705 if (x_p) 706 { 707 INSERTION_ELT *i = insertion_stack; 708 /* Skip over ifclear and ifset conditionals. */ 709 while (i && (i->insertion == ifset || i->insertion == ifclear)) 710 i = i->next; 711 712 if (!i || i->insertion != type) 713 { 714 line_error (_("Must be in `@%s' environment to use `@%s'"), 715 base_command, command); 716 discard_until ("\n"); 717 return; 718 } 719 } 720 721 defun_internal (type, x_p); 722 free (base_command); 723 } 724