1 /* $NetBSD: conffile.c,v 1.7 2009/01/25 14:25:27 lukem Exp $ */
4 * Copyright © 2006 Alistair Crooks. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
31 #include <sys/param.h>
44 /* start of split routines */
48 conffile_open(conffile_t
*sp
, const char *f
, const char *mode
, const char *sep
, const char *comment
)
50 (void) memset(sp
, 0x0, sizeof(*sp
));
51 if ((sp
->fp
= fopen(f
, mode
)) == NULL
) {
52 (void) fprintf(stderr
, "can't open `%s' `%s' (%s)\n", f
, mode
, strerror(errno
));
55 (void) strlcpy(sp
->name
, f
, sizeof(sp
->name
));
57 sp
->comment
= comment
;
58 sp
->readonly
= (strcmp(mode
, "r") == 0);
64 conffile_close(conffile_t
*sp
)
66 (void) fclose(sp
->fp
);
69 /* read the next line from the file */
71 read_line(conffile_t
*sp
, ent_t
*ep
)
75 if (fgets(ep
->buf
, sizeof(ep
->buf
), sp
->fp
) == NULL
) {
79 for (from
= ep
->buf
; *from
&& isspace((unsigned int)*from
) ; from
++) {
84 /* return 1 if this line contains no entry */
86 iscomment(conffile_t
*sp
, char *from
)
88 return (*from
== 0x0 || *from
== '\n' || strchr(sp
->comment
, *from
) != NULL
);
91 /* split the entry up into fields */
93 conffile_split(conffile_t
*sp
, ent_t
*ep
, char *from
)
102 seps
= (sp
== NULL
) ? " \t" : sp
->sep
;
103 fp
= (sp
== NULL
) ? stdin
: sp
->fp
;
104 for (ep
->sv
.c
= 0 ; *from
&& *from
!= '\n' ; ) {
105 for (to
= from
, sepseen
= 0 ; *to
&& *to
!= '\n' && strchr(seps
, *to
) == NULL
; to
++) {
107 if (*(to
+ 1) == '\n') {
108 cc
= (int)(to
- ep
->buf
);
109 if (fgets(&ep
->buf
[cc
], (int)(sizeof(ep
->buf
) - cc
), fp
) != NULL
) {
120 ALLOC(char *, ep
->sv
.v
, ep
->sv
.size
, ep
->sv
.c
, 14, 14, "conffile_getent", exit(EXIT_FAILURE
));
121 ep
->sv
.v
[ep
->sv
.c
++] = from
;
127 for (cp
= from
; *cp
; cp
++) {
128 if (strchr(seps
, *cp
) != NULL
) {
129 (void) strcpy(cp
- 1, cp
);
133 if (was
== 0x0 || was
== '\n') {
136 for (from
= to
+ 1 ; *from
&& *from
!= '\n' && strchr(seps
, *from
) != NULL
; from
++) {
142 /* get the next entry */
144 conffile_getent(conffile_t
*sp
, ent_t
*ep
)
149 if ((from
= read_line(sp
, ep
)) == NULL
) {
152 if (iscomment(sp
, from
)) {
155 return conffile_split(sp
, ep
, from
);
159 /* return the line number */
161 conffile_get_lineno(conffile_t
*sp
)
166 /* return the name */
168 conffile_get_name(conffile_t
*sp
)
173 /* return the entry based upon the contents of field `f' */
175 conffile_get_by_field(conffile_t
*sp
, ent_t
*ep
, int f
, char *val
)
177 while (conffile_getent(sp
, ep
)) {
178 if (ep
->sv
.c
> (uint32_t)f
&& strcmp(ep
->sv
.v
[f
], val
) == 0) {
185 /* check that we wrote `cc' chars of `buf' to `fp' */
187 safe_write(FILE *fp
, char *buf
, unsigned cc
)
189 return fwrite(buf
, sizeof(char), cc
, fp
) == cc
;
193 /* check that we wrote the entry correctly */
195 safe_write_ent(FILE *fp
, conffile_t
*sp
, ent_t
*ep
)
201 for (cc
= i
= 0 ; i
< ep
->sv
.c
; i
++) {
202 cc
+= snprintf(&buf
[cc
], sizeof(buf
) - cc
, "%s%1.1s", ep
->sv
.v
[i
], (i
== ep
->sv
.c
- 1) ? "\n" : sp
->sep
);
204 return safe_write(fp
, buf
, cc
);
208 /* report an error and clear up */
210 report_error(FILE *fp
, char *name
, const char *fmt
, ...)
215 (void) vfprintf(stderr
, fmt
, vp
);
223 /* put the new entry (in place of ent[f] == val, if val is non-NULL) */
225 conffile_putent(conffile_t
*sp
, int f
, char *val
, char *newent
)
229 char name
[MAXPATHLEN
];
233 (void) strlcpy(name
, "/tmp/split.XXXXXX", sizeof(name
));
234 if ((fd
= mkstemp(name
)) < 0) {
235 (void) fprintf(stderr
, "can't mkstemp `%s' (%s)\n", name
, strerror(errno
));
238 fp
= fdopen(fd
, "w");
239 (void) memset(&e
, 0x0, sizeof(e
));
241 if ((from
= read_line(sp
, &e
)) == NULL
) {
244 if (iscomment(sp
, from
)) {
245 if (!safe_write(fp
, e
.buf
, strlen(e
.buf
))) {
246 return report_error(fp
, name
, "Short write 1 to `%s' (%s)\n", name
, strerror(errno
));
249 (void) conffile_split(sp
, &e
, from
);
250 if (val
!= NULL
&& (uint32_t)f
< e
.sv
.c
&& strcmp(val
, e
.sv
.v
[f
]) == 0) {
252 if (!safe_write(fp
, newent
, strlen(newent
))) {
253 return report_error(fp
, name
, "Short write 2 to `%s' (%s)\n", name
, strerror(errno
));
256 if (!safe_write(fp
, e
.buf
, strlen(e
.buf
))) {
257 return report_error(fp
, name
, "Short write 3 to `%s' (%s)\n", name
, strerror(errno
));
261 if (val
== NULL
&& !safe_write(fp
, newent
, strlen(newent
))) {
262 return report_error(fp
, name
, "Short write 4 to `%s' (%s)\n", name
, strerror(errno
));
265 if (rename(name
, sp
->name
) < 0) {
266 return report_error(NULL
, name
, "can't rename %s to %s (%s)\n", name
, sp
->name
, strerror(errno
));
271 /* print the entry on stdout */
273 conffile_printent(ent_t
*ep
)
277 for (i
= 0 ; i
< ep
->sv
.c
; i
++) {
278 printf("(%d `%s') ", i
, ep
->sv
.v
[i
]);