summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/texinfo/util
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>2000-02-09 01:27:25 +0000
committerMarc Espie <espie@cvs.openbsd.org>2000-02-09 01:27:25 +0000
commit328f35a635ee7b14c4d6f2dbddacba138e62219b (patch)
tree5f0effaeb304116c7826d814dfa001d501a3b10a /gnu/usr.bin/texinfo/util
parentc2daa957909e4243f84a2232ff4a481b6c44a393 (diff)
TexInfo 4.0. New manpages, can create html.
A bit more grumpy about bad texinfo, though.
Diffstat (limited to 'gnu/usr.bin/texinfo/util')
-rw-r--r--gnu/usr.bin/texinfo/util/README6
-rw-r--r--gnu/usr.bin/texinfo/util/deref.c317
-rw-r--r--gnu/usr.bin/texinfo/util/fix-info-dir317
-rw-r--r--gnu/usr.bin/texinfo/util/fixref.gawk145
-rw-r--r--gnu/usr.bin/texinfo/util/outline.gawk145
-rw-r--r--gnu/usr.bin/texinfo/util/prepinfo.awk356
-rw-r--r--gnu/usr.bin/texinfo/util/texi-docstring-magic.el347
7 files changed, 1460 insertions, 173 deletions
diff --git a/gnu/usr.bin/texinfo/util/README b/gnu/usr.bin/texinfo/util/README
index 5385522543b..20d7bdafd86 100644
--- a/gnu/usr.bin/texinfo/util/README
+++ b/gnu/usr.bin/texinfo/util/README
@@ -2,3 +2,9 @@ Assorted Texinfo-related programs and scripts.
texindex, texi2dvi, and install-info get installed.
The other items here are for your amusement and/or hacking pleasure.
+
+You may also be interested in a2ps, an ASCII->PostScript program which
+has a Texinfo style option. Available from
+http://www.inf.enst.fr/~demaille/a2ps/ and
+ftp://ftp.enst.fr/pub/unix/a2ps/.
+
diff --git a/gnu/usr.bin/texinfo/util/deref.c b/gnu/usr.bin/texinfo/util/deref.c
index c15bc1abcf1..e08be48105f 100644
--- a/gnu/usr.bin/texinfo/util/deref.c
+++ b/gnu/usr.bin/texinfo/util/deref.c
@@ -1,44 +1,28 @@
/*
* deref.c
-
- * compile command: gcc -g -o deref deref.c
-
- * execute command: deref filename.texi > newfile.texi
-
- * To: bob@gnu.ai.mit.edu
- * Subject: another tool
- * Date: 18 Dec 91 16:03:13 EST (Wed)
- * From: gatech!skeeve!arnold@eddie.mit.edu (Arnold D. Robbins)
- *
- * Here is deref.c. It turns texinfo cross references back into the
- * one argument form. It has the same limitations as fixref; one xref per
- * line and can't cross lines. You can use it to find references that do
- * cross a line boundary this way:
- *
- * deref < manual > /dev/null 2>errs
- *
- * (This assumes bash or /bin/sh.) The file errs will have list of lines
- * where deref could not find matching braces.
- *
- * A gawk manual processed by deref goes through makeinfo without complaint.
- * Compile with gcc and you should be set.
- *
- * Enjoy,
- *
- * Arnold
- * -----------
- */
-
-/*
- * deref.c
*
* Make all texinfo references into the one argument form.
- *
+ *
* Arnold Robbins
- * arnold@skeeve.atl.ga.us
- * December, 1991
+ * arnold@gnu.org
+ * Written: December, 1991
+ * Released: November, 1998
*
- * Copyright, 1991, Arnold Robbins
+ * Copyright, 1991, 1998 Arnold David Robbins
+ *
+ * DEREF is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DEREF is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/*
@@ -53,17 +37,19 @@
#include <errno.h>
/* for gcc on the 3B1, delete if this gives you grief */
-extern int fclose (FILE * fp);
-extern int fprintf (FILE * fp, const char *str,...);
+extern int fclose(FILE *fp);
+extern int fprintf(FILE *fp, const char *str, ...);
+/* extern int sprintf(char *str, const char *fmt, ...); */
+extern int fputs(char *buf, FILE *fp);
-extern char *strerror (int errno);
-extern char *strchr (char *cp, int ch);
-extern int strncmp (const char *s1, const char *s2, int count);
+extern char *strerror(int errno);
+extern char *strchr(char *cp, int ch);
+extern int strncmp(const char *s1, const char *s2, int count);
extern int errno;
-void process (FILE * fp);
-void repair (char *line, char *ref, int toffset);
+void process(FILE *fp);
+void repair(char *line, char *ref, int toffset);
int Errs = 0;
char *Name = "stdin";
@@ -73,166 +59,151 @@ char *Me;
/* main --- handle arguments, global vars for errors */
int
-main (int argc, char **argv)
+main(int argc, char **argv)
{
- FILE *fp;
-
- Me = argv[0];
-
- if (argc == 1)
- process (stdin);
- else
- for (argc--, argv++; *argv != NULL; argc--, argv++)
- {
- if (argv[0][0] == '-' && argv[0][1] == '\0')
- {
- Name = "stdin";
- Line = 0;
- process (stdin);
- }
- else if ((fp = fopen (*argv, "r")) != NULL)
- {
- Name = *argv;
- Line = 0;
- process (fp);
- fclose (fp);
- }
+ FILE *fp;
+
+ Me = argv[0];
+
+ if (argc == 1)
+ process(stdin);
else
- {
- fprintf (stderr, "%s: can not open: %s\n",
- *argv, strerror (errno));
- Errs++;
- }
- }
- return Errs != 0;
+ for (argc--, argv++; *argv != NULL; argc--, argv++) {
+ if (argv[0][0] == '-' && argv[0][1] == '\0') {
+ Name = "stdin";
+ Line = 0;
+ process(stdin);
+ } else if ((fp = fopen(*argv, "r")) != NULL) {
+ Name = *argv;
+ Line = 0;
+ process(fp);
+ fclose(fp);
+ } else {
+ fprintf(stderr, "%s: can not open: %s\n",
+ *argv, strerror(errno));
+ Errs++;
+ }
+ }
+ return Errs != 0;
}
/* isref --- decide if we've seen a texinfo cross reference */
int
-isref (char *cp)
+isref(char *cp)
{
- if (strncmp (cp, "@ref{", 5) == 0)
- return 5;
- if (strncmp (cp, "@xref{", 6) == 0)
- return 6;
- if (strncmp (cp, "@pxref{", 7) == 0)
- return 7;
- return 0;
+ if (strncmp(cp, "@ref{", 5) == 0)
+ return 5;
+ if (strncmp(cp, "@xref{", 6) == 0)
+ return 6;
+ if (strncmp(cp, "@pxref{", 7) == 0)
+ return 7;
+ return 0;
}
/* process --- read files, look for references, fix them up */
void
-process (FILE * fp)
+process(FILE *fp)
{
- char buf[BUFSIZ];
- char *cp;
- int count;
-
- while (fgets (buf, sizeof buf, fp) != NULL)
- {
- Line++;
- cp = strchr (buf, '@');
- if (cp == NULL)
- {
- fputs (buf, stdout);
- continue;
- }
- do
- {
- count = isref (cp);
- if (count == 0)
- {
- cp++;
- cp = strchr (cp, '@');
- if (cp == NULL)
- {
- fputs (buf, stdout);
- goto next;
+ char buf[BUFSIZ];
+ char *cp;
+ int count;
+
+ while (fgets(buf, sizeof buf, fp) != NULL) {
+ Line++;
+ cp = strchr(buf, '@');
+ if (cp == NULL) {
+ fputs(buf, stdout);
+ continue;
}
- continue;
- }
- /* got one */
- repair (buf, cp, count);
- break;
+ do {
+ count = isref(cp);
+ if (count == 0) {
+ cp++;
+ cp = strchr(cp, '@');
+ if (cp == NULL) {
+ fputs(buf, stdout);
+ goto next;
+ }
+ continue;
+ }
+ /* got one */
+ repair(buf, cp, count);
+ break;
+ } while (cp != NULL);
+ next: ;
}
- while (cp != NULL);
- next:;
- }
}
/* repair --- turn all texinfo cross references into the one argument form */
void
-repair (char *line, char *ref, int toffset)
+repair(char *line, char *ref, int toffset)
{
- int braces = 1; /* have seen first left brace */
- char *cp;
-
- ref += toffset;
-
- /* output line up to and including left brace in reference */
- for (cp = line; cp <= ref; cp++)
- putchar (*cp);
-
- /* output node name */
- for (; *cp && *cp != '}' && *cp != ',' && *cp != '\n'; cp++)
- putchar (*cp);
-
- if (*cp != '}')
- { /* could have been one arg xref */
- /* skip to matching right brace */
- for (; braces > 0; cp++)
- {
- switch (*cp)
- {
- case '@':
- cp++; /* blindly skip next character */
- break;
- case '{':
- braces++;
- break;
- case '}':
- braces--;
- break;
- case '\n':
- case '\0':
- Errs++;
- fprintf (stderr,
- "%s: %s: %d: mismatched braces\n",
- Me, Name, Line);
- goto out;
- default:
- break;
- }
+ int braces = 1; /* have seen first left brace */
+ char *cp;
+
+ ref += toffset;
+
+ /* output line up to and including left brace in reference */
+ for (cp = line; cp <= ref; cp++)
+ putchar(*cp);
+
+ /* output node name */
+ for (; *cp && *cp != '}' && *cp != ',' && *cp != '\n'; cp++)
+ putchar(*cp);
+
+ if (*cp != '}') { /* could have been one arg xref */
+ /* skip to matching right brace */
+ for (; braces > 0; cp++) {
+ switch (*cp) {
+ case '@':
+ cp++; /* blindly skip next character */
+ break;
+ case '{':
+ braces++;
+ break;
+ case '}':
+ braces--;
+ break;
+ case '\n':
+ case '\0':
+ Errs++;
+ fprintf(stderr,
+ "%s: %s: %d: mismatched braces\n",
+ Me, Name, Line);
+ goto out;
+ default:
+ break;
+ }
+ }
+ out:
+ ;
}
- out:
- ;
- }
-
- putchar ('}');
- if (*cp == '}')
- cp++;
-
- /* now the rest of the line */
- for (; *cp; cp++)
- putchar (*cp);
- return;
+
+ putchar('}');
+ if (*cp == '}')
+ cp++;
+
+ /* now the rest of the line */
+ for (; *cp; cp++)
+ putchar(*cp);
+ return;
}
/* strerror --- return error string, delete if in your library */
char *
-strerror (int errno)
+strerror(int errno)
{
- static char buf[100];
- extern int sys_nerr;
- extern char *sys_errlist[];
+ static char buf[100];
+ extern int sys_nerr;
+ extern char *sys_errlist[];
- if (errno < sys_nerr && errno >= 0)
- return sys_errlist[errno];
+ if (errno < sys_nerr && errno >= 0)
+ return sys_errlist[errno];
- sprintf (buf, "unknown error %d", errno);
- return buf;
+ sprintf(buf, "unknown error %d", errno);
+ return buf;
}
diff --git a/gnu/usr.bin/texinfo/util/fix-info-dir b/gnu/usr.bin/texinfo/util/fix-info-dir
new file mode 100644
index 00000000000..bf0901caa30
--- /dev/null
+++ b/gnu/usr.bin/texinfo/util/fix-info-dir
@@ -0,0 +1,317 @@
+#!/bin/sh
+#fix-info-dir (GNU texinfo)
+VERSION=1.1
+#Copyright (C) 1998 Free Software Foundation, Inc.
+#fix-info-dir comes with NO WARRANTY, to the extent permitted by law.
+#You may redistribute copies of fix-info-dir
+#under the terms of the GNU General Public License.
+#For more information about these matters, see the files named COPYING."
+#fix-info-dir was derived from update-info and gen-dir-node
+# The skeleton file contains info topic names in the
+# order they should appear in the output. There are three special
+# lines that alter the behavior: a line consisting of just "--" causes
+# the next line to be echoed verbatim to the output. A line
+# containing just "%%" causes all the remaining filenames (wildcards
+# allowed) in the rest of the file to be ignored. A line containing
+# just "!!" exits the script when reached (unless preceded by a line
+# containing just "--").
+#Author: Richard L. Hawes, rhawes@dmapub.dma.org.
+
+# ###SECTION 1### Constants
+set -h 2>/dev/null
+# ENVIRONMENT
+if test -z "$TMPDIR"; then
+ TMPDIR="/usr/tmp"
+fi
+if test -z "$LINENO"; then
+ LINENO="0"
+fi
+
+MENU_BEGIN='^\*\([ ]\)\{1,\}Menu:'
+MENU_ITEM='^\* ([^ ]).*:([ ])+\('
+MENU_FILTER1='s/^\*\([ ]\)\{1,\}/* /'
+MENU_FILTER2='s/\([ ]\)\{1,\}$//g'
+
+TMP_FILE1="${TMPDIR}/fx${$}.info"
+TMP_FILE2="${TMPDIR}/fy${$}.info"
+TMP_FILE_LIST="$TMP_FILE1 $TMP_FILE2"
+
+TRY_HELP_MSG="Try --help for more information"
+
+# ###SECTION 100### main program
+#variables set by options
+CREATE_NODE=""
+DEBUG=":"
+MODE=""
+#
+Total="0"
+Changed=""
+
+while test "$*"; do
+ case "$1" in
+ -c|--create) CREATE_NODE="y";;
+ --debug) set -eux; DEBUG="set>&2";;
+ -d|--delete) MODE="Detect_Invalid";;
+ +d);;
+ --version)
+cat<<VersionEOF
+fix-info-dir (GNU Texinfo) $VERSION
+Copyright (C) 1998 Free Software Foundation, Inc.
+fix-info-dir comes with NO WARRANTY, to the extent permitted by law.
+You may redistribute copies of fix-info-dir
+under the terms of the GNU General Public License.
+For more information about these matters, see the files named COPYING.
+Author: Richard L. Hawes
+VersionEOF
+ exit;;
+
+ --help)
+cat<<HelpEndOfFile
+Usage: fix-info-dir [OPTION]... [INFO_DIR/[DIR_FILE]] [SKELETON]
+
+It detects and inserts missing menu items into the info dir file.
+The info dir must be the current directory.
+
+Options:
+-c, --create create a new info node
+-d, --delete delete invalid menu items (ignore missing menu items)
+ --debug print debug information to standard error path
+ --help print this help message and exit
+ --version print current version and exit
+Backup of the info node has a '.old' suffix added. This is a shell script.
+Environment Variables: TMPDIR
+Email bug reports to bug-texinfo@gnu.org.
+HelpEndOfFile
+ exit;;
+
+ [-+]*) echo "$0:$LINENO: \"$1\" is not a valid option">&2
+ echo "$TRY_HELP_MSG">&2
+ exit 2;;
+ *) break;;
+ esac
+ shift
+done
+
+ORIGINAL_DIR=`pwd`
+
+if test "$#" -gt "0"; then
+ INFO_DIR="$1"
+ shift
+else
+ INFO_DIR=$DEFAULT_INFO_DIR
+fi
+
+if test ! -d "${INFO_DIR}"; then
+ DIR_FILE=`basename ${INFO_DIR}`;
+ INFO_DIR=`dirname ${INFO_DIR}`;
+else
+ DIR_FILE="dir"
+fi
+
+cd "$INFO_DIR"||exit
+
+
+if test "$CREATE_NODE"; then
+ if test "$#" -gt "0"; then
+ if test `expr $1 : /` = '1'; then
+ SKELETON="$1"
+ else
+ SKELETON="$ORIGINAL_DIR/$1"
+ fi
+ if test ! -r "$SKELETON" -a -f "$SKELETON"; then
+ echo "$0:$LINENO: $SKELETON is not readable">&2
+ exit 2
+ fi
+ shift
+ else
+ SKELETON=/dev/null
+
+ fi
+else
+ if test ! -f "$DIR_FILE"; then
+ echo "$0:$LINENO: $DIR_FILE is irregular or nonexistant">&2
+ exit 2
+ elif test ! -r "$DIR_FILE"; then
+ echo "$0:$LINENO: $DIR_FILE is not readable">&2
+ exit 2
+ elif test ! -w "$DIR_FILE"; then
+ echo "$0:$LINENO: $DIR_FILE is not writeable">&2
+ exit 2
+ fi
+fi
+
+if test "$#" -gt "0"; then
+ echo "$0:$LINENO: Too many parameters">&2
+ echo "$TRY_HELP_MSG">&2
+ exit 2
+fi
+
+if test -f "$DIR_FILE"; then
+ cp "$DIR_FILE" "$DIR_FILE.old"
+ echo "Backed up $DIR_FILE to $DIR_FILE.old."
+fi
+
+if test "$CREATE_NODE"; then
+ if test "$MODE"; then
+ echo "$0:$LINENO: ERROR: Illogical option combination: -d -c">&2
+ echo "$TRY_HELP_MSG">&2
+ exit 2
+ fi
+ echo "Creating new Info Node: `pwd`/$DIR_FILE"
+ Changed="y"
+
+{
+
+ ### output the dir header
+ echo "-*- Text -*-"
+ echo "This file was generated automatically by $0."
+ echo "This version was generated on `date`"
+ echo "by `whoami`@`hostname` for `pwd`"
+
+ cat<<DIR_FILE_END_OF_FILE
+This is the file .../info/$DIR_FILE, which contains the topmost node of the
+Info hierarchy. The first time you invoke Info you start off
+looking at that node, which is ($DIR_FILE)Top.
+
+
+File: $DIR_FILE Node: Top This is the top of the INFO tree
+
+ This (the Directory node) gives a menu of major topics.
+ Typing "q" exits, "?" lists all Info commands, "d" returns here,
+ "h" gives a primer for first-timers,
+ "mEmacs<Return>" visits the Emacs topic, etc.
+
+ In Emacs, you can click mouse button 2 on a menu item or cross reference
+ to select it.
+
+* Menu: The list of major topics begins on the next line.
+
+DIR_FILE_END_OF_FILE
+
+### go through the list of files in the skeleton. If an info file
+### exists, grab the ENTRY information from it. If an entry exists
+### use it, otherwise create a minimal $DIR_FILE entry.
+
+ # Read one line from the file. This is so that we can echo lines with
+ # whitespace and quoted characters in them.
+ while read fileline; do
+ # flag fancy features
+ if test ! -z "$echoline"; then # echo line
+ echo "$fileline"
+ echoline=""
+ continue
+ elif test "${fileline}" = "--"; then
+ # echo the next line
+ echoline="1"
+ continue
+ elif test "${fileline}" = "%%"; then
+ # skip remaining files listed in skeleton file
+ skip="1"
+ continue
+ elif test "${fileline}" = "!!"; then
+ # quit now
+ break
+ fi
+
+ # handle files if they exist
+ for file in $fileline""; do
+ fname=
+ if test -z "$file"; then
+ break
+ fi
+ # Find the file to operate upon.
+ if test -r "$file"; then
+ fname="$file"
+ elif test -r "${file}.info"; then
+ fname="${file}.info"
+ elif test -r "${file}.gz"; then
+ fname="${file}.gz"
+ elif test -r "${file}.info.gz"; then
+ fname="${file}.info.gz"
+ else
+ echo "$0:$LINENO: can't find info file for ${file}?">&2
+ continue
+ fi
+
+ # if we found something and aren't skipping, do the entry
+ if test "$skip"; then
+ continue
+ fi
+
+ infoname=`echo $file|sed -e 's/.info$//'`
+ entry=`zcat -f $fname|\
+ sed -e '1,/START-INFO-DIR-ENTRY/d'\
+ -e '/END-INFO-DIR-ENTRY/,$d'`
+ if [ ! -z "${entry}" ]; then
+ echo "${entry}"
+ else
+ echo "* ${infoname}: (${infoname})."
+ fi
+ Total=`expr "$Total" + "1"`
+ done
+ done
+}>$DIR_FILE<$SKELETON
+fi
+
+trap ' eval "$DEBUG"; rm -f $TMP_FILE_LIST; exit ' 0
+trap ' rm -f $TMP_FILE_LIST
+ exit ' 1
+trap ' rm -f $TMP_FILE_LIST
+ echo "$0:$LINENO: received INT signal.">&2
+ exit ' 2
+trap ' rm -f $TMP_FILE_LIST
+ echo "$0:$LINENO: received QUIT signal.">&2
+ exit ' 3
+
+sed -e "1,/$MENU_BEGIN/d" -e "$MENU_FILTER1" -e "$MENU_FILTER2"<$DIR_FILE\
+|sed -n -e '/\* /{
+s/).*$//g
+s/\.gz$//
+s/\.info$//
+s/^.*(//p
+}'|sort -u>$TMP_FILE1
+ls -F|sed -e '/\/$/d' -e '/[-.][0-9]/d'\
+ -e "/^$DIR_FILE\$/d" -e "/^$DIR_FILE.old\$/d"\
+ -e 's/[*@]$//' -e 's/\.gz$//' -e 's/\.info$//'|sort>$TMP_FILE2
+
+if test -z "$MODE"; then
+ #Detect Missing
+ DONE_MSG="total menu item(s) were inserted into `pwd`/$DIR_FILE"
+ for Info_Name in `comm -13 $TMP_FILE1 $TMP_FILE2`; do
+ if test -r "$Info_Name"; then
+ Info_File="$Info_Name"
+ elif test -r "${Info_Name}.info"; then
+ Info_File="${Info_Name}.info"
+ elif test -r "${Info_Name}.gz"; then
+ Info_File="${Info_Name}.gz"
+ elif test -r "${Info_Name}.info.gz"; then
+ Info_File="${Info_Name}.info.gz"
+ else
+ echo "$0:$LINENO: can't find info file for ${Info_Name}?">&2
+ continue
+ fi
+ Changed="y"
+ if install-info $Info_File $DIR_FILE; then
+ Total=`expr "$Total" + "1"`
+ fi
+ done
+else
+ # Detect Invalid
+ DONE_MSG="total invalid menu item(s) were removed from `pwd`/$DIR_FILE"
+ for Info_Name in `comm -23 $TMP_FILE1 $TMP_FILE2`; do
+ Changed="y"
+ if install-info --remove $Info_Name $DIR_FILE; then
+ Total=`expr "$Total" + "1"`
+ fi
+ done
+fi
+
+# print summary
+if test "$Changed"; then
+ echo "$Total $DONE_MSG"
+else
+ echo "Nothing to do"
+fi
+rm -f $TMP_FILE_LIST
+eval "$DEBUG"
+exit 0
diff --git a/gnu/usr.bin/texinfo/util/fixref.gawk b/gnu/usr.bin/texinfo/util/fixref.gawk
new file mode 100644
index 00000000000..f0e3cf6d606
--- /dev/null
+++ b/gnu/usr.bin/texinfo/util/fixref.gawk
@@ -0,0 +1,145 @@
+#! /usr/local/bin/gawk -f
+
+# fixref.awk --- fix xrefs in texinfo documents
+# Copyright, 1991, Arnold David Robbins, arnold@skeeve.atl.ga.us
+# Copyright, 1998, Arnold David Robbins, arnold@gnu.org
+
+# FIXREF is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# FIXREF is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+# Updated: Jul 21 1992 --- change unknown
+# Updated: Jul 18 1997 --- bug fix
+
+# usage: gawk -f fixref.awk input-file > output-file
+# or if you have #!: fixref.awk input-file > output-file
+
+# Limitations:
+# 1. no more than one cross reference on a line
+# 2. cross references may not cross a newline
+
+BEGIN \
+{
+ # we make two passes over the file. To do that we artificially
+ # tweak the argument vector to do a variable assignment
+
+ if (ARGC != 2) {
+ printf("usage: %s texinfo-file\n", ARGV[0]) > "/dev/stderr"
+ exit 1
+ }
+ ARGV[2] = "pass=2"
+ ARGV[3] = ARGV[1]
+ ARGC = 4
+
+ # examine paragraphs
+ RS = ""
+
+ heading = "@(chapter|appendix|unnumbered|(appendix(sec|subsec|subsubsec))|section|subsection|subsubsection|unnumberedsec|heading|top)"
+
+ pass = 1
+
+ # put space between paragraphs on output
+ ORS = "\n\n"
+}
+
+pass == 1 && NF == 0 { next }
+
+# pass == 1 && /@node/ \
+# bug fix 7/18/96
+pass == 1 && /^@node/ \
+{
+ lname = name = ""
+ n = split($0, lines, "\n")
+ for (i = 1; i <= n; i++) {
+ if (lines[i] ~ ("^" heading)) {
+ sub(heading, "", lines[i])
+ sub(/^[ \t]*/, "", lines[i])
+ lname = lines[i]
+# printf "long name is '%s'\n", lines[i]
+ } else if (lines[i] ~ /@node/) {
+ sub(/@node[ \t]*/, "", lines[i])
+ sub(/[ \t]*,.*$/, "", lines[i])
+ name = lines[i]
+# printf "node name is '%s'\n", lines[i]
+ }
+ }
+ if (name && lname)
+ names[name] = lname
+ else if (lname)
+ printf("node name for %s missing!\n", lname) > "/dev/stderr"
+ else
+ printf("long name for %s missing!\n", name) > "/dev/stderr"
+
+ if (name ~ /:/)
+ printf("node `%s' contains a `:'\n", name) > "/dev/stderr"
+
+ if (lname) {
+ if (lname ~ /:/)
+ printf("name `%s' contains a `:'\n", lname) > "/dev/stderr"
+ else if (lname ~ /,/) {
+ printf("name `%s' contains a `,'\n", lname) > "/dev/stderr"
+ gsub(/,/, " ", lname)
+ names[name] = lname # added 7/18/97
+ }
+ }
+}
+
+pass == 2 && /@(x|px)?ref{/ \
+{
+ # split the paragraph into lines
+ # write them out one by one after fixing them
+ n = split($0, lines, "\n")
+ for (i = 1; i <= n; i++)
+ if (lines[i] ~ /@(x|px)?ref{/) {
+ res = updateref(lines[i])
+ printf "%s\n", res
+ } else
+ printf "%s\n", lines[i]
+
+ printf "\n" # avoid ORS
+ next
+}
+
+function updateref(orig, refkind, line)
+{
+ line = orig # work on a copy
+
+ # find the beginning of the reference
+ match(line, "@(x|px)?ref{")
+ refkind = substr(line, RSTART, RLENGTH)
+
+ # pull out just the node name
+ sub(/.*ref{/, "", line)
+ sub(/}.*$/, "", line)
+ sub(/,.*/, "", line)
+
+# debugging
+# printf("found ref to node '%s'\n", line) > "/dev/stderr"
+
+ # If the node name and the section name are the same
+ # we don't want to bother doing this.
+
+ if (! (line in names)) # sanity checking
+ printf("no long name for %s\n", line) > "/dev/stderr"
+ else if (names[line] != line && names[line] !~ /[:,]/) {
+ # build up new ref
+ newref = refkind line ", ," names[line] "}"
+ pat = refkind line "[^}]*}"
+
+ sub(pat, newref, orig)
+ }
+
+ return orig
+}
+
+pass == 2 { print }
diff --git a/gnu/usr.bin/texinfo/util/outline.gawk b/gnu/usr.bin/texinfo/util/outline.gawk
new file mode 100644
index 00000000000..329bb17529a
--- /dev/null
+++ b/gnu/usr.bin/texinfo/util/outline.gawk
@@ -0,0 +1,145 @@
+#! /usr/local/bin/gawk -f
+
+# texi.outline --- produce an outline from a texinfo source file
+#
+# Copyright (C) 1998 Arnold David Robbins (arnold@gnu.org)
+#
+# TEXI.OUTLINE is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# TEXI.OUTLINE is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+# NOTE:
+# This program uses gensub(), which is specific to gawk.
+# With some work (split, substr, etc), it could be made to work
+# on other awks, but it's not worth the trouble for me.
+
+BEGIN \
+{
+ # Levels at which different nodes can be
+ Level["@top"] = 0
+ Level["@appendix"] = 1
+ Level["@chapter"] = 1
+ Level["@majorheading"] = 1
+ Level["@unnumbered"] = 1
+ Level["@appendixsec"] = 2
+ Level["@heading"] = 2
+ Level["@section"] = 2
+ Level["@unnumberedsec"] = 2
+ Level["@unnumberedsubsec"] = 3
+ Level["@appendixsubsec"] = 3
+ Level["@subheading"] = 3
+ Level["@subsection"] = 3
+ Level["@appendixsubsubsec"] = 4
+ Level["@subsubheading"] = 4
+ Level["@subsubsection"] = 4
+ Level["@unnumberedsubsubsec"] = 4
+
+ # insure that we were called correctly
+ if (ARGC != 2) {
+ printf("usage: %s texinfo-file\n", ARGV[0]) > "/dev/stderr"
+ exit 1
+ }
+
+ # init header counters
+ app_letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ app_h = 0
+ l1_h = l2_h = l3_h = l4_h = 0
+}
+
+# skip lines we're not interested in
+/^[^@]/ || ! ($1 in Level) { next }
+
+Level[$1] == 1 {
+ if ($1 !~ /^@unnumbered/ || $1 !~ /heading/)
+ l1_h++
+ l2_h = l3_h = l4_h = 0
+ Ntabs = 0
+ Number = makenumber($1)
+ Title = maketitle($0)
+ print_title()
+}
+
+Level[$1] == 2 {
+ l2_h++
+ l3_h = l4_h = 0
+ Ntabs = 1
+ Number = makenumber($1)
+ Title = maketitle($0)
+ print_title()
+}
+
+Level[$1] == 3 {
+ l3_h++
+ l4_h = 0
+ Ntabs = 2
+ Number = makenumber($1)
+ Title = maketitle($0)
+ print_title()
+}
+
+Level[$1] == 4 {
+ l4_h++
+ Ntabs = 3
+ Number = makenumber($1)
+ Title = maketitle($0)
+ print_title()
+}
+
+# maketitle --- extract title
+
+function maketitle(str, text)
+{
+ $1 = "" # clobber section keyword
+ text = $0
+ gsub(/^[ \t]*/, "", text)
+ text = gensub(/@[a-z]+{/, "", "g", text)
+ text = gensub(/([^@])}/, "\\1", "g", text)
+ return text
+}
+
+# print_title --- print the title
+
+function print_title( i)
+{
+ for (i = 1; i <= Ntabs; i++)
+ printf "\t"
+ printf("%s %s\n", Number, Title)
+}
+
+# makenumber --- construct a heading number from levels and section command
+
+function makenumber(command, result, lev1)
+{
+ result = ""
+ if (command ~ /^@appendix/) {
+ if (Level[command] == 1)
+ app_h++
+
+ lev1 = substr(app_letters, app_h, 1)
+ } else if (command ~ /^@unnumbered/ || command ~ /heading/) {
+ lev1 = "(unnumbered)"
+ } else
+ lev1 = l1_h ""
+
+ result = lev1 "."
+ if (l2_h > 0) {
+ result = result l2_h "."
+ if (l3_h > 0) {
+ result = result l3_h "."
+ if (l4_h > 0) {
+ result = result l4_h "."
+ }
+ }
+ }
+ return result
+}
diff --git a/gnu/usr.bin/texinfo/util/prepinfo.awk b/gnu/usr.bin/texinfo/util/prepinfo.awk
new file mode 100644
index 00000000000..273c97f8460
--- /dev/null
+++ b/gnu/usr.bin/texinfo/util/prepinfo.awk
@@ -0,0 +1,356 @@
+#! /usr/local/bin/gawk -f
+
+# prepinfo.awk --- fix node lines and menus
+#
+# Copyright, 1998, Arnold Robbins, arnold@gnu.org
+#
+# PREPINFO is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# PREPINFO is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+BEGIN \
+{
+ # manifest constants
+ TRUE = 1
+ FALSE = 0
+
+ # Levels at which different nodes can be
+ Level["@top"] = 0
+ Level["@appendix"] = 1
+ Level["@chapter"] = 1
+ Level["@majorheading"] = 1
+ Level["@unnumbered"] = 1
+ Level["@appendixsec"] = 2
+ Level["@heading"] = 2
+ Level["@section"] = 2
+ Level["@unnumberedsec"] = 2
+ Level["@unnumberedsubsec"] = 3
+ Level["@appendixsubsec"] = 3
+ Level["@subheading"] = 3
+ Level["@subsection"] = 3
+ Level["@appendixsubsubsec"] = 4
+ Level["@subsubheading"] = 4
+ Level["@subsubsection"] = 4
+ Level["@unnumberedsubsubsec"] = 4
+
+ # Length of menus
+ Menumargin = 78
+
+ # Length of menu item
+ Min_menitem_length = 29
+
+ # insure that we were called correctly
+ if (ARGC != 2) {
+ printf("usage: %s texinfo-file\n", ARGV[0]) > "/dev/stderr"
+ exit 1
+ }
+
+ # Arrange for two passes over input file
+ Pass = 1
+ ARGV[2] = "Pass=2"
+ ARGV[3] = ARGV[1]
+ ARGC = 4
+ Lastlevel = -1
+
+ # Initialize stacks
+ Up[-1] = "(dir)"
+ Prev[0] = "(dir)"
+
+ if (Debug == "args") {
+ for (i = 0; i < ARGC; i++)
+ printf("ARGV[%d] = %s\n", i, ARGV[i]) > "/dev/stderr"
+ }
+}
+
+$1 == "@node" \
+{
+ Name = getnodename($0)
+ Nodeseen = TRUE
+
+ if ((l = length(Name)) > Maxlen)
+ Maxlen = l
+
+ if (Debug == "nodenames")
+ printf("Name = %s\n", Name) > "/dev/stderr"
+
+ if (Pass == 1)
+ next
+}
+
+Pass == 1 && /^@c(omment)?[ \t]+fakenode/ \
+{
+ if (Debug == "fakenodes")
+ printf("fakenode at %d\n", FNR) > "/dev/stderr"
+ Fakenode = TRUE
+ next
+}
+
+Pass == 1 && ($1 in Level) \
+{
+ # skip fake nodes --- titles without associated @node lines
+ if (Fakenode) {
+ if (Debug == "fakenodes")
+ printf("%s at %d is a fakenode\n", $1, FNR) > "/dev/stderr"
+ Fakenode = FALSE
+ next
+ }
+
+ if (Debug == "titles")
+ printf("Processing %s: Name = %s\n", $1, Name) > "/dev/stderr"
+
+ # save type
+ type = $1
+
+ if (! Nodeseen) {
+ err_prefix()
+ printf("%s line with no @node or fakenode line\n",
+ type) > "/dev/stderr"
+ Badheading[FNR] = 1
+ # ??? used ???
+ next
+ } else
+ Nodeseen = FALSE # reset it
+
+ # Squirrel away the info
+ levelnum = Level[type]
+ Node[Name ".level"] = levelnum
+ Node[Name ".name"] = Name
+ if (Debug == "titles") {
+ printf("Node[%s\".level\"] = %s\n", Name, Node[Name ".level"]) > "/dev/stderr"
+ printf("Node[%s\".name\"] = %s\n", Name, Node[Name ".name"]) > "/dev/stderr"
+ }
+
+ if (levelnum == Lastlevel) { # e.g., two sections in a row
+ Node[Name ".up"] = Up[levelnum - 1]
+ if (levelnum in Prev) {
+ Node[Prev[levelnum] ".next"] = Name
+ Node[Name ".prev"] = Prev[levelnum]
+ }
+ Prev[levelnum] = Name
+ Up[levelnum] = Name # ???
+ } else if (levelnum < Lastlevel) { # section, now chapter
+ Lastlevel = levelnum
+ Node[Name ".up"] = Up[levelnum - 1]
+ if (levelnum in Prev) {
+ Node[Name ".prev"] = Prev[levelnum]
+ Node[Prev[levelnum] ".next"] = Name
+ }
+ Prev[levelnum] = Name
+ Up[levelnum] = Name
+ } else { # chapter, now section, levelnum > Lastlevel
+ Node[Name ".up"] = Up[levelnum - 1]
+ Node[Up[Lastlevel] ".child"] = Name
+ Up[levelnum] = Name
+ Prev[levelnum] = Name
+ Lastlevel = levelnum
+ }
+
+ # For master menu
+ if (Level[$1] >= 2)
+ List[++Sequence] = Name
+
+ if (Debug == "titles") {
+ printf("Node[%s\".prev\"] = %s\n", Name, Node[Name ".prev"]) > "/dev/stderr"
+ printf("Node[%s\".up\"] = %s\n", Name, Node[Name ".up"]) > "/dev/stderr"
+ printf("Node[%s\".child\"] = %s\n", Name, Node[Name ".child"]) > "/dev/stderr"
+ }
+}
+
+Pass == 2 && Debug == "dumptitles" && FNR <= 1 \
+{
+ for (i in Node)
+ printf("Node[%s] = %s\n", i, Node[i]) | "sort 1>&2"
+ close("sort 1>&2")
+}
+
+/^@menu/ && Pass == 1, /^@end[ \t]+menu/ && Pass == 1 \
+{
+ if (/^@menu/ || /^@end[ \t]+menu/)
+ next
+
+# if (Debug == "menu")
+# printf("processing: %s\n", $0) > "/dev/stderr"
+
+ if (/^\*/) {
+ if (In_menitem) { # file away info from previousline
+ Node[node ".mendesc"] = desc
+ Node[node ".longdesc"] = longdesc
+ if (Debug == "mendesc") {
+ printf("Node[%s.mendesc] = %s\n",
+ node, Node[node ".mendesc"]) > "/dev/stderr"
+ printf("Node[%s.longdesc] = %s\n",
+ node, Node[node ".longdesc"]) > "/dev/stderr"
+ }
+ }
+ In_menitem = TRUE
+
+ # pull apart menu item
+ $1 = "" # nuke ``*''
+ $0 = $0 # reparse line
+ i1 = index($0, ":")
+ if (i1 <= 0) {
+ err_prefix()
+ printf("badly formed menu item") > "/dev/stderr"
+ next
+ }
+ if (substr($0, i1+1, 1) != ":") { # desc: node. long desc
+ i2 = index($0, ".")
+ if (i2 <= 0) {
+ err_prefix()
+ printf("badly formed menu item") > "/dev/stderr"
+ next
+ }
+ desc = substr($0, 1, i1 - 1)
+ sub(/^[ \t]+/, "", node)
+ sub(/[ \t]+$/, "", node)
+ longdesc = substr($0, i2 + 1)
+ } else { # nodname:: long desc
+ desc = ""
+ node = substr($0, 1, i1 - 1)
+ sub(/^[ \t]+/, "", node)
+ sub(/[ \t]+$/, "", node)
+ longdesc = substr($0, i1 + 2)
+ }
+ } else if (In_menitem) { # continuation line
+ longdesc = longdesc " " $0
+ } else
+ In_menitem = FALSE
+
+ Node[node ".mendesc"] = desc
+ Node[node ".longdesc"] = longdesc
+ if (Debug == "mendesc") {
+ printf("Node[%s.mendesc] = %s\n",
+ node, Node[node ".mendesc"]) > "/dev/stderr"
+ printf("Node[%s.longdesc] = %s\n",
+ node, Node[node ".longdesc"]) > "/dev/stderr"
+ }
+
+ if (Debug == "menu")
+ printf("Menu:: Name %s: desc %s: longdesc %s\n",
+ node, desc, longdesc) > "/dev/stderr"
+}
+
+function err_prefix()
+{
+ printf("%s: %s: %d: ", ARGV[0], FILENAME, FNR) > "/dev/stderr"
+}
+
+function getnodename(str)
+{
+ sub(/@node[ \t]+/, "", str)
+ sub(/,.*/, "", str)
+ if (Debug == "nodenames")
+ printf("getnodename: return %s\n", str) > "/dev/stderr"
+ return str
+}
+
+Pass == 2 && /^@node/ \
+{
+ Name = getnodename($0)
+
+ # Top node is special. It's next is the first child
+ n = Node[Name ".next"]
+ if (Node[Name ".level"] == 0 && n == "")
+ n = Node[Name ".child"]
+
+ printf("@node %s, %s, %s, %s\n", Name, n,
+ Node[Name ".prev"] ? Node[Name ".prev"] : Node[Name ".up"],
+ Node[Name ".up"])
+ next
+}
+
+Pass == 2 && /^@menu/ \
+{
+ # First, nuke current contents of menu
+ do {
+ if ((getline) <= 0) {
+ err_prefix()
+ printf("unexpected EOF inside menu\n") > "/dev/stderr"
+ exit 1
+ }
+ } while (! /^@end[ \t]+menu/)
+
+ # next, compute maximum length of a node name
+ max = 0
+ for (n = Node[Name ".child"]; (n ".next") in Node; n = Node[n ".next"]) {
+ if ((n ".desc") in Node)
+ s = Node[n ".desc"] ": " n "."
+ else
+ s = n "::"
+ l = length(s)
+ if (l > max)
+ max = l
+ }
+ if (max < Min_menitem_length)
+ max = Min_menitem_length
+
+ # now dump the menu
+ print "@menu"
+
+ for (n = Node[Name ".child"]; (n ".next") in Node; n = Node[n ".next"]) {
+ print_menuitem(n, max)
+ }
+ print_menuitem(n, max)
+
+ if (Name == "Top") { # Master Menu
+ if (Maxlen < Min_menitem_length)
+ Maxlen = Min_menitem_length
+ print ""
+ for (i = 1; i <= Sequence; i++)
+ print_menuitem(List[i], Maxlen)
+ print ""
+ }
+ print "@end menu"
+ next
+}
+
+Pass == 2 # print
+
+
+function print_menuitem(n, max, nodesc, i, dwords, count, p)
+{
+ nodesc = FALSE
+ if (! ((n ".longdesc") in Node)) {
+ err_prefix()
+ printf("warning: %s: no long description\n", n) > "/dev/stderr"
+ nodesc = TRUE
+ } else {
+ for (i in dwords)
+ delete dwords[i]
+ count = split(Node[n ".longdesc"], dwords, "[ \t\n]+")
+ }
+ if ((n ".desc") in Node)
+ s = Node[n ".desc"] ": " n "."
+ else
+ s = n "::"
+ printf("* %-*s", max, s)
+
+ if (Debug == "mendescitem")
+ printf("<* %-*s>\n", max, s) > "/dev/stderr"
+
+ p = max + 2
+ if (! nodesc) {
+ for (i = 1; i <= count; i++) {
+ l = length(dwords[i])
+ if (l == 0)
+ continue
+ if (p + l + 1 > Menumargin) {
+ printf("\n%*s", max + 2, " ")
+ p = max + 2
+ }
+ printf(" %s", dwords[i])
+ p += l + 1
+ }
+ }
+ print ""
+}
diff --git a/gnu/usr.bin/texinfo/util/texi-docstring-magic.el b/gnu/usr.bin/texinfo/util/texi-docstring-magic.el
new file mode 100644
index 00000000000..c645fbcf699
--- /dev/null
+++ b/gnu/usr.bin/texinfo/util/texi-docstring-magic.el
@@ -0,0 +1,347 @@
+;; texi-docstring-magic.el -- munge internal docstrings into texi
+;;
+;; Keywords: lisp, docs, tex
+;; Author: David Aspinall <da@dcs.ed.ac.uk>
+;; Copyright (C) 1998 David Aspinall
+;; Maintainer: David Aspinall <da@dcs.ed.ac.uk>
+;;
+;; $Id: texi-docstring-magic.el,v 1.1.1.1 2000/02/09 01:26:24 espie Exp $
+;;
+;; This package is distributed under the terms of the
+;; GNU General Public License, Version 2.
+;; You should have a copy of the GPL with your version of
+;; GNU Emacs or the Texinfo distribution.
+;;
+;;
+;; This package generates Texinfo source fragments from Emacs
+;; docstrings. This avoids documenting functions and variables
+;; in more than one place, and automatically adds Texinfo markup
+;; to docstrings.
+;;
+;; It relies heavily on you following the Elisp documentation
+;; conventions to produce sensible output, check the Elisp manual
+;; for details. In brief:
+;;
+;; * The first line of a docstring should be a complete sentence.
+;; * Arguments to functions should be written in upper case: ARG1..ARGN
+;; * User options (variables users may want to set) should have docstrings
+;; beginning with an asterisk.
+;;
+;; Usage:
+;;
+;; Write comments of the form:
+;;
+;; @c TEXI DOCSTRING MAGIC: my-package-function-or-variable-name
+;;
+;; In your texi source, mypackage.texi. From within an Emacs session
+;; where my-package is loaded, visit mypackage.texi and run
+;; M-x texi-docstring-magic to update all of the documentation strings.
+;;
+;; This will insert @defopt, @deffn and the like underneath the
+;; magic comment strings.
+;;
+;; The default value for user options will be printed.
+;;
+;; Symbols are recognized if they are defined for faces, functions,
+;; or variables (in that order).
+;;
+;; Automatic markup rules:
+;;
+;; 1. Indented lines are gathered into @lisp environment.
+;; 2. Pieces of text `stuff' or surrounded in quotes marked up with @samp.
+;; 3. Words *emphasized* are made @strong{emphasized}
+;; 4. Words sym-bol which are symbols become @code{sym-bol}.
+;; 5. Upper cased words ARG corresponding to arguments become @var{arg}.
+;; In fact, you can any word longer than three letters, so that
+;; metavariables can be used easily.
+;; FIXME: to escape this, use `ARG'
+;; 6. Words 'sym which are lisp-quoted are marked with @code{'sym}.
+;;
+;; -----
+;;
+;; Useful key binding when writing Texinfo:
+;;
+;; (define-key TeXinfo-mode-map "C-cC-d" 'texi-docstring-magic-insert-magic)
+;;
+;; -----
+;;
+;; Useful enhancements to do:
+;;
+;; * Use customize properties (e.g. group, simple types)
+;; * Look for a "texi-docstring" property for symbols
+;; so TeXInfo can be defined directly in case automatic markup
+;; goes badly wrong.
+;; * Add tags to special comments so that user can specify face,
+;; function, or variable binding for a symbol in case more than
+;; one binding exists.
+;;
+;; ------
+
+(defun texi-docstring-magic-splice-sep (strings sep)
+ "Return concatenation of STRINGS spliced together with separator SEP."
+ (let (str)
+ (while strings
+ (setq str (concat str (car strings)))
+ (if (cdr strings)
+ (setq str (concat str sep)))
+ (setq strings (cdr strings)))
+ str))
+
+(defconst texi-docstring-magic-munge-table
+ '(;; 1. Indented lines are gathered into @lisp environment.
+ ("\\(^.*\\S-.*$\\)"
+ t
+ (let
+ ((line (match-string 0 docstring)))
+ (if (eq (char-syntax (string-to-char line)) ?\ )
+ ;; whitespace
+ (if in-quoted-region
+ line
+ (setq in-quoted-region t)
+ (concat "@lisp\n" line))
+ ;; non-white space
+ (if in-quoted-region
+ (progn
+ (setq in-quoted-region nil)
+ (concat "@end lisp\n" line))
+ line))))
+ ;; 2. Pieces of text `stuff' or surrounded in quotes
+ ;; are marked up with @samp. NB: Must be backquote
+ ;; followed by forward quote for this to work.
+ ;; Can't use two forward quotes else problems with
+ ;; symbols.
+ ;; Odd hack: because ' is a word constituent in text/texinfo
+ ;; mode, putting this first enables the recognition of args
+ ;; and symbols put inside quotes.
+ ("\\(`\\([^']+\\)'\\)"
+ t
+ (concat "@samp{" (match-string 2 docstring) "}"))
+ ;; 3. Words *emphasized* are made @strong{emphasized}
+ ("\\(\\*\\(\\w+\\)\\*\\)"
+ t
+ (concat "@strong{" (match-string 2 docstring) "}"))
+ ;; 4. Words sym-bol which are symbols become @code{sym-bol}.
+ ;; Must have at least one hyphen to be recognized,
+ ;; terminated in whitespace, end of line, or punctuation.
+ ;; (Only consider symbols made from word constituents
+ ;; and hyphen.
+ ("\\(\\(\\w+\\-\\(\\w\\|\\-\\)+\\)\\)\\(\\s\)\\|\\s-\\|\\s.\\|$\\)"
+ (or (boundp (intern (match-string 2 docstring)))
+ (fboundp (intern (match-string 2 docstring))))
+ (concat "@code{" (match-string 2 docstring) "}"
+ (match-string 4 docstring)))
+ ;; 5. Upper cased words ARG corresponding to arguments become
+ ;; @var{arg}
+ ;; In fact, include any word so long as it is more than 3 characters
+ ;; long. (Comes after symbols to avoid recognizing the
+ ;; lowercased form of an argument as a symbol)
+ ;; FIXME: maybe we don't want to downcase stuff already
+ ;; inside @samp
+ ;; FIXME: should - terminate? should _ be included?
+ ("\\([A-Z0-9\\-]+\\)\\(/\\|\)\\|}\\|\\s-\\|\\s.\\|$\\)"
+ (or (> (length (match-string 1 docstring)) 3)
+ (member (downcase (match-string 1 docstring)) args))
+ (concat "@var{" (downcase (match-string 1 docstring)) "}"
+ (match-string 2 docstring)))
+
+ ;; 6. Words 'sym which are lisp quoted are
+ ;; marked with @code.
+ ("\\(\\(\\s-\\|^\\)'\\(\\(\\w\\|\\-\\)+\\)\\)\\(\\s\)\\|\\s-\\|\\s.\\|$\\)"
+ t
+ (concat (match-string 2 docstring)
+ "@code{'" (match-string 3 docstring) "}"
+ (match-string 5 docstring)))
+ ;; 7,8. Clean up for @lisp environments left with spurious newlines
+ ;; after 1.
+ ("\\(\\(^\\s-*$\\)\n@lisp\\)" t "@lisp")
+ ("\\(\\(^\\s-*$\\)\n@end lisp\\)" t "@end lisp"))
+ "Table of regexp matches and replacements used to markup docstrings.
+Format of table is a list of elements of the form
+ (regexp predicate replacement-form)
+If regexp matches and predicate holds, then replacement-form is
+evaluated to get the replacement for the match.
+predicate and replacement-form can use variables arg,
+and forms such as (match-string 1 docstring)
+Match string 1 is assumed to determine the
+length of the matched item, hence where parsing restarts from.
+The replacement must cover the whole match (match string 0),
+including any whitespace included to delimit matches.")
+
+
+(defun texi-docstring-magic-munge-docstring (docstring args)
+ "Markup DOCSTRING for texi according to regexp matches."
+ (let ((case-fold-search nil))
+ (dolist (test texi-docstring-magic-munge-table docstring)
+ (let ((regexp (nth 0 test))
+ (predicate (nth 1 test))
+ (replace (nth 2 test))
+ (i 0)
+ in-quoted-region)
+
+ (while (and
+ (< i (length docstring))
+ (string-match regexp docstring i))
+ (setq i (match-end 1))
+ (if (eval predicate)
+ (let* ((origlength (- (match-end 0) (match-beginning 0)))
+ (replacement (eval replace))
+ (newlength (length replacement)))
+ (setq docstring
+ (replace-match replacement t t docstring))
+ (setq i (+ i (- newlength origlength))))))
+ (if in-quoted-region
+ (setq docstring (concat docstring "\n@end lisp"))))))
+ ;; Force a new line after (what should be) the first sentence,
+ ;; if not already a new paragraph.
+ (let*
+ ((pos (string-match "\n" docstring))
+ (needscr (and pos
+ (not (string= "\n"
+ (substring docstring
+ (1+ pos)
+ (+ pos 2)))))))
+ (if (and pos needscr)
+ (concat (substring docstring 0 pos)
+ "@*\n"
+ (substring docstring (1+ pos)))
+ docstring)))
+
+(defun texi-docstring-magic-texi (env grp name docstring args &optional endtext)
+ "Make a texi def environment ENV for entity NAME with DOCSTRING."
+ (concat "@def" env (if grp (concat " " grp) "") " " name
+ " "
+ (texi-docstring-magic-splice-sep args " ")
+ ;; " "
+ ;; (texi-docstring-magic-splice-sep extras " ")
+ "\n"
+ (texi-docstring-magic-munge-docstring docstring args)
+ "\n"
+ (or endtext "")
+ "@end def" env "\n"))
+
+(defun texi-docstring-magic-format-default (default)
+ "Make a default value string for the value DEFAULT.
+Markup as @code{stuff} or @lisp stuff @end lisp."
+ (let ((text (format "%S" default)))
+ (concat
+ "\nThe default value is "
+ (if (string-match "\n" text)
+ ;; Carriage return will break @code, use @lisp
+ (if (stringp default)
+ (concat "the string: \n@lisp\n" default "\n@end lisp\n")
+ (concat "the value: \n@lisp\n" text "\n@end lisp\n"))
+ (concat "@code{" text "}.\n")))))
+
+
+(defun texi-docstring-magic-texi-for (symbol)
+ (cond
+ ;; Faces
+ ((find-face symbol)
+ (let*
+ ((face symbol)
+ (name (symbol-name face))
+ (docstring (or (face-doc-string face)
+ "Not documented."))
+ (useropt (eq ?* (string-to-char docstring))))
+ ;; Chop off user option setting
+ (if useropt
+ (setq docstring (substring docstring 1)))
+ (texi-docstring-magic-texi "fn" "Face" name docstring nil)))
+ ((fboundp symbol)
+ ;; Functions.
+ ;; We don't handle macros, aliases, or compiled fns properly.
+ (let*
+ ((function symbol)
+ (name (symbol-name function))
+ (docstring (or (documentation function)
+ "Not documented."))
+ (def (symbol-function function))
+ (argsyms (cond ((eq (car-safe def) 'lambda)
+ (nth 1 def))))
+ (args (mapcar 'symbol-name argsyms)))
+ (if (commandp function)
+ (texi-docstring-magic-texi "fn" "Command" name docstring args)
+ (texi-docstring-magic-texi "un" nil name docstring args))))
+ ((boundp symbol)
+ ;; Variables.
+ (let*
+ ((variable symbol)
+ (name (symbol-name variable))
+ (docstring (or (documentation-property variable
+ 'variable-documentation)
+ "Not documented."))
+ (useropt (eq ?* (string-to-char docstring)))
+ (default (if useropt
+ (texi-docstring-magic-format-default
+ (default-value symbol)))))
+ ;; Chop off user option setting
+ (if useropt
+ (setq docstring (substring docstring 1)))
+ (texi-docstring-magic-texi
+ (if useropt "opt" "var") nil name docstring nil default)))
+ (t
+ (error "Don't know anything about symbol %s" (symbol-name symbol)))))
+
+(defconst texi-docstring-magic-comment
+ "@c TEXI DOCSTRING MAGIC:"
+ "Magic string in a texi buffer expanded into @defopt, or @deffn.")
+
+(defun texi-docstring-magic ()
+ "Update all texi docstring magic annotations in buffer."
+ (interactive)
+ (save-excursion
+ (goto-char (point-min))
+ (let ((magic (concat "^"
+ (regexp-quote texi-docstring-magic-comment)
+ "\\s-*\\(\\(\\w\\|\\-\\)+\\)$"))
+ p
+ symbol)
+ (while (re-search-forward magic nil t)
+ (setq symbol (intern (match-string 1)))
+ (forward-line)
+ (setq p (point))
+ ;; If comment already followed by an environment, delete it.
+ (if (and
+ (looking-at "@def\\(\\w+\\)\\s-")
+ (search-forward (concat "@end def" (match-string 1)) nil t))
+ (progn
+ (forward-line)
+ (delete-region p (point))))
+ (insert
+ (texi-docstring-magic-texi-for symbol))))))
+
+(defun texi-docstring-magic-face-at-point ()
+ (ignore-errors
+ (let ((stab (syntax-table)))
+ (unwind-protect
+ (save-excursion
+ (set-syntax-table emacs-lisp-mode-syntax-table)
+ (or (not (zerop (skip-syntax-backward "_w")))
+ (eq (char-syntax (char-after (point))) ?w)
+ (eq (char-syntax (char-after (point))) ?_)
+ (forward-sexp -1))
+ (skip-chars-forward "'")
+ (let ((obj (read (current-buffer))))
+ (and (symbolp obj) (find-face obj) obj)))
+ (set-syntax-table stab)))))
+
+(defun texi-docstring-magic-insert-magic (symbol)
+ (interactive
+ (let* ((v (or (variable-at-point)
+ (function-at-point)
+ (texi-docstring-magic-face-at-point)))
+ (val (let ((enable-recursive-minibuffers t))
+ (completing-read
+ (if v
+ (format "Magic docstring for symbol (default %s): " v)
+ "Magic docstring for symbol: ")
+ obarray '(lambda (sym)
+ (or (boundp sym)
+ (fboundp sym)
+ (find-face sym)))
+ t nil 'variable-history))))
+ (list (if (equal val "") v (intern val)))))
+ (insert "\n" texi-docstring-magic-comment " " (symbol-name symbol)))
+
+
+(provide 'texi-docstring-magic)