1/*	$NetBSD$	*/
2
3/*
4 * deref.c
5 *
6 * Make all texinfo references into the one argument form.
7 *
8 * Arnold Robbins
9 * arnold@gnu.org
10 * Written: December, 1991
11 * Released: November, 1998
12 *
13 * Copyright, 1991, 1998 Arnold David Robbins
14 *
15 * DEREF is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * DEREF is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
28 */
29
30/*
31 * LIMITATIONS:
32 *	One texinfo cross reference per line.
33 *	Cross references may not cross newlines.
34 *	Use of fgets for input (to be fixed).
35 */
36
37#include <stdio.h>
38#include <ctype.h>
39#include <errno.h>
40
41/* for gcc on the 3B1, delete if this gives you grief */
42extern int fclose(FILE *fp);
43extern int fprintf(FILE *fp, const char *str, ...);
44/* extern int sprintf(char *str, const char *fmt, ...); */
45extern int fputs(char *buf, FILE *fp);
46
47extern char *strerror(int errno);
48extern char *strchr(char *cp, int ch);
49extern int strncmp(const char *s1, const char *s2, int count);
50
51extern int errno;
52
53void process(FILE *fp);
54void repair(char *line, char *ref, int toffset);
55
56int Errs = 0;
57char *Name = "stdin";
58int Line = 0;
59char *Me;
60
61/* main --- handle arguments, global vars for errors */
62
63int
64main(int argc, char **argv)
65{
66	FILE *fp;
67
68	Me = argv[0];
69
70	if (argc == 1)
71		process(stdin);
72	else
73		for (argc--, argv++; *argv != NULL; argc--, argv++) {
74			if (argv[0][0] == '-' && argv[0][1] == '\0') {
75				Name = "stdin";
76				Line = 0;
77				process(stdin);
78			} else if ((fp = fopen(*argv, "r")) != NULL) {
79				Name = *argv;
80				Line = 0;
81				process(fp);
82				fclose(fp);
83			} else {
84				fprintf(stderr, "%s: can not open: %s\n",
85					*argv, strerror(errno));
86				Errs++;
87			}
88		}
89	return Errs != 0;
90}
91
92/* isref --- decide if we've seen a texinfo cross reference */
93
94int
95isref(char *cp)
96{
97	if (strncmp(cp, "@ref{", 5) == 0)
98		return 5;
99	if (strncmp(cp, "@xref{", 6) == 0)
100		return 6;
101	if (strncmp(cp, "@pxref{", 7) == 0)
102		return 7;
103	return 0;
104}
105
106/* process --- read files, look for references, fix them up */
107
108void
109process(FILE *fp)
110{
111	char buf[BUFSIZ];
112	char *cp;
113	int count;
114
115	while (fgets(buf, sizeof buf, fp) != NULL) {
116		Line++;
117		cp = strchr(buf, '@');
118		if (cp == NULL) {
119			fputs(buf, stdout);
120			continue;
121		}
122		do {
123			count = isref(cp);
124			if (count == 0) {
125				cp++;
126				cp = strchr(cp, '@');
127				if (cp == NULL) {
128					fputs(buf, stdout);
129					goto next;
130				}
131				continue;
132			}
133			/* got one */
134			repair(buf, cp, count);
135			break;
136		} while (cp != NULL);
137	next: ;
138	}
139}
140
141/* repair --- turn all texinfo cross references into the one argument form */
142
143void
144repair(char *line, char *ref, int toffset)
145{
146	int braces = 1;		/* have seen first left brace */
147	char *cp;
148
149	ref += toffset;
150
151	/* output line up to and including left brace in reference */
152	for (cp = line; cp <= ref; cp++)
153		putchar(*cp);
154
155	/* output node name */
156	for (; *cp && *cp != '}' && *cp != ',' && *cp != '\n'; cp++)
157		putchar(*cp);
158
159	if (*cp != '}')	{	/* could have been one arg xref */
160		/* skip to matching right brace */
161		for (; braces > 0; cp++) {
162			switch (*cp) {
163			case '@':
164				cp++;	/* blindly skip next character */
165				break;
166			case '{':
167				braces++;
168				break;
169			case '}':
170				braces--;
171				break;
172			case '\n':
173			case '\0':
174				Errs++;
175				fprintf(stderr,
176					"%s: %s: %d: mismatched braces\n",
177					Me, Name, Line);
178				goto out;
179			default:
180				break;
181			}
182		}
183	out:
184		;
185	}
186
187	putchar('}');
188	if (*cp == '}')
189		cp++;
190
191	/* now the rest of the line */
192	for (; *cp; cp++)
193		putchar(*cp);
194	return;
195}
196
197/* strerror --- return error string, delete if in your library */
198
199char *
200strerror(int errno)
201{
202	static char buf[100];
203	extern int sys_nerr;
204	extern char *sys_errlist[];
205
206	if (errno < sys_nerr && errno >= 0)
207		return sys_errlist[errno];
208
209	sprintf(buf, "unknown error %d", errno);
210	return buf;
211}
212