]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - util/subst.c
Many files:
[thirdparty/e2fsprogs.git] / util / subst.c
1 /*
2 * subst.c --- substitution program
3 *
4 * Subst is used as a quicky program to do @ substitutions
5 *
6 */
7
8 #include <stdio.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <ctype.h>
14
15 #ifdef HAVE_GETOPT_H
16 #include <getopt.h>
17 #endif
18
19
20 struct subst_entry {
21 char *name;
22 char *value;
23 struct subst_entry *next;
24 };
25
26 struct subst_entry *subst_table = 0;
27
28 static int add_subst(char *name, char *value)
29 {
30 struct subst_entry *ent = 0;
31 int retval;
32
33 retval = ENOMEM;
34 ent = malloc(sizeof(struct subst_entry));
35 if (!ent)
36 goto fail;
37 ent->name = malloc(strlen(name)+1);
38 if (!ent->name)
39 goto fail;
40 ent->value = malloc(strlen(value)+1);
41 if (!ent->value)
42 goto fail;
43 strcpy(ent->name, name);
44 strcpy(ent->value, value);
45 ent->next = subst_table;
46 subst_table = ent;
47 return 0;
48 fail:
49 if (ent) {
50 if (ent->name)
51 free(ent->name);
52 if (ent->value)
53 free(ent->value);
54 free(ent);
55 }
56 return retval;
57 }
58
59 static struct subst_entry *fetch_subst_entry(char *name)
60 {
61 struct subst_entry *ent;
62
63 for (ent = subst_table; ent; ent = ent->next) {
64 if (strcmp(name, ent->name) == 0)
65 break;
66 }
67 return ent;
68 }
69
70 static void substitute_line(char *line)
71 {
72 char *ptr, *name_ptr, *end_ptr;
73 struct subst_entry *ent;
74 char replace_name[128];
75 int len, replace_len;
76
77 ptr = line;
78 while (ptr) {
79 name_ptr = strchr(ptr, '@');
80 if (!name_ptr)
81 break;
82 end_ptr = strchr(name_ptr+1, '@');
83 if (!end_ptr)
84 break;
85 len = end_ptr - name_ptr - 1;
86 memcpy(replace_name, name_ptr+1, len);
87 replace_name[len] = 0;
88 ent = fetch_subst_entry(replace_name);
89 if (!ent) {
90 fprintf(stderr, "Unfound expansion: '%s'\n",
91 replace_name);
92 ptr = end_ptr + 1;
93 continue;
94 }
95 #if 0
96 fprintf(stderr, "Replace name = '%s' with '%s'\n",
97 replace_name, ent->value);
98 #endif
99 replace_len = strlen(ent->value);
100 if (replace_len != len+2)
101 memmove(end_ptr+(replace_len-len-2), end_ptr,
102 strlen(end_ptr)+1);
103 memcpy(name_ptr, ent->value, replace_len);
104 ptr = name_ptr;
105 }
106 }
107
108 static void parse_config_file(FILE *f)
109 {
110 char line[2048];
111 char *cp, *ptr;
112
113 while (!feof(f)) {
114 memset(line, 0, sizeof(line));
115 if (fgets(line, sizeof(line), f) == NULL)
116 break;
117 /*
118 * Strip newlines and comments.
119 */
120 cp = strchr(line, '\n');
121 if (cp)
122 *cp = 0;
123 cp = strchr(line, '#');
124 if (cp)
125 *cp = 0;
126 /*
127 * Skip trailing and leading whitespace
128 */
129 for (cp = line + strlen(line) - 1; cp >= line; cp--) {
130 if (*cp == ' ' || *cp == '\t')
131 *cp = 0;
132 else
133 break;
134 }
135 cp = line;
136 while (*cp && isspace(*cp))
137 cp++;
138 ptr = cp;
139 /*
140 * Skip empty lines
141 */
142 if (*ptr == 0)
143 continue;
144 /*
145 * Ignore future extensions
146 */
147 if (*ptr == '$')
148 continue;
149 /*
150 * Parse substitutions
151 */
152 for (cp = ptr; *cp; cp++)
153 if (isspace(*cp))
154 break;
155 *cp = 0;
156 for (cp++; *cp; cp++)
157 if (!isspace(*cp))
158 break;
159 #if 0
160 printf("Substitute: '%s' for '%s'\n", ptr, cp);
161 #endif
162 add_subst(ptr, cp);
163 }
164 }
165
166 /*
167 * Return 0 if the files are different, 1 if the files are the same.
168 */
169 static int compare_file(const char *outfn, const char *newfn)
170 {
171 FILE *old, *new;
172 char oldbuf[2048], newbuf[2048], *oldcp, *newcp;
173 int retval;
174
175 old = fopen(outfn, "r");
176 if (!old)
177 return 0;
178 new = fopen(newfn, "r");
179 if (!new)
180 return 0;
181
182 while (1) {
183 oldcp = fgets(oldbuf, sizeof(oldbuf), old);
184 newcp = fgets(newbuf, sizeof(newbuf), new);
185 if (!oldcp && !newcp) {
186 retval = 1;
187 break;
188 }
189 if (!oldcp || !newcp || strcmp(oldbuf, newbuf)) {
190 retval = 0;
191 break;
192 }
193 }
194 return retval;
195 }
196
197
198
199
200 int main(int argc, char **argv)
201 {
202 char line[2048];
203 int c;
204 FILE *in, *out;
205 char *outfn = NULL, *newfn = NULL;
206 int verbose = 0;
207
208 while ((c = getopt (argc, argv, "f:v")) != EOF) {
209 switch (c) {
210 case 'f':
211 in = fopen(optarg, "r");
212 if (!in) {
213 perror(optarg);
214 exit(1);
215 }
216 parse_config_file(in);
217 fclose(in);
218 break;
219 case 'v':
220 verbose++;
221 break;
222 default:
223 fprintf(stderr, "%s: [-f config-file] [file]\n",
224 argv[0]);
225 break;
226 }
227 }
228 if (optind < argc) {
229 in = fopen(argv[optind], "r");
230 if (!in) {
231 perror(argv[optind]);
232 exit(1);
233 }
234 optind++;
235 } else
236 in = stdin;
237
238 if (optind < argc) {
239 outfn = argv[optind];
240 newfn = malloc(strlen(outfn)+20);
241 if (!newfn) {
242 fprintf(stderr, "Memory error! Exiting.\n");
243 exit(1);
244 }
245 strcpy(newfn, outfn);
246 strcat(newfn, ".new");
247 out = fopen(newfn, "w");
248 if (!out) {
249 perror(newfn);
250 exit(1);
251 }
252 } else {
253 out = stdout;
254 outfn = 0;
255 }
256
257 while (!feof(in)) {
258 if (fgets(line, sizeof(line), in) == NULL)
259 break;
260 substitute_line(line);
261 fputs(line, out);
262 }
263 fclose(in);
264 fclose(out);
265 if (outfn) {
266 if (compare_file(outfn, newfn)) {
267 if (verbose)
268 printf("No change, keeping %s.\n", outfn);
269 unlink(newfn);
270 } else {
271 if (verbose)
272 printf("Creating or replacing %s.\n", outfn);
273 rename(newfn, outfn);
274 }
275 }
276 return (0);
277 }
278
279