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