xref: /openbsd/gnu/usr.bin/texinfo/util/deref.c (revision 78b63d65)
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 */
40 extern int fclose(FILE *fp);
41 extern int fprintf(FILE *fp, const char *str, ...);
42 /* extern int sprintf(char *str, const char *fmt, ...); */
43 extern int fputs(char *buf, FILE *fp);
44 
45 extern char *strerror(int errno);
46 extern char *strchr(char *cp, int ch);
47 extern int strncmp(const char *s1, const char *s2, int count);
48 
49 extern int errno;
50 
51 void process(FILE *fp);
52 void repair(char *line, char *ref, int toffset);
53 
54 int Errs = 0;
55 char *Name = "stdin";
56 int Line = 0;
57 char *Me;
58 
59 /* main --- handle arguments, global vars for errors */
60 
61 int
62 main(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 
92 int
93 isref(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 
106 void
107 process(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 
141 void
142 repair(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 
197 char *
198 strerror(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