profile.c revision 8f234d9650eb6f6a897148d5136cb27f373de4a7
13f00e317064560ad11168d22030416d853829f6eJim Grosbach/*
23f00e317064560ad11168d22030416d853829f6eJim Grosbach * profile.c -- A simple configuration file parsing "library in a file"
33f00e317064560ad11168d22030416d853829f6eJim Grosbach *
4e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * The profile library was originally written by Theodore Ts'o in 1995
5e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * for use in the MIT Kerberos v5 library.  It has been
6e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * modified/enhanced/bug-fixed over time by other members of the MIT
7e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * Kerberos team.  This version was originally taken from the Kerberos
8e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * v5 distribution, version 1.4.2, and radically simplified for use in
9e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * e2fsprogs.  (Support for locking for multi-threaded operations,
10e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * being able to modify and update the configuration file
113f00e317064560ad11168d22030416d853829f6eJim Grosbach * programmatically, and Mac/Windows portability have been removed.
123f00e317064560ad11168d22030416d853829f6eJim Grosbach * It has been folded into a single C source file to make it easier to
133f00e317064560ad11168d22030416d853829f6eJim Grosbach * fold into an application program.)
14da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach *
153f00e317064560ad11168d22030416d853829f6eJim Grosbach * Copyright (C) 2005, 2006 by Theodore Ts'o.
16da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach *
173f00e317064560ad11168d22030416d853829f6eJim Grosbach * %Begin-Header%
183f00e317064560ad11168d22030416d853829f6eJim Grosbach * This file may be redistributed under the terms of the GNU Public
193f00e317064560ad11168d22030416d853829f6eJim Grosbach * License.
203f00e317064560ad11168d22030416d853829f6eJim Grosbach * %End-Header%
213f00e317064560ad11168d22030416d853829f6eJim Grosbach *
223f00e317064560ad11168d22030416d853829f6eJim Grosbach * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology.
233f00e317064560ad11168d22030416d853829f6eJim Grosbach *
243f00e317064560ad11168d22030416d853829f6eJim Grosbach * All rights reserved.
253f00e317064560ad11168d22030416d853829f6eJim Grosbach *
263f00e317064560ad11168d22030416d853829f6eJim Grosbach * Export of this software from the United States of America may require
273f00e317064560ad11168d22030416d853829f6eJim Grosbach * a specific license from the United States Government.  It is the
28dc89561fecf100d6c32d73c7b009fd73e51be688Jim Grosbach * responsibility of any person or organization contemplating export to
293f00e317064560ad11168d22030416d853829f6eJim Grosbach * obtain such a license before exporting.
303f00e317064560ad11168d22030416d853829f6eJim Grosbach *
313f00e317064560ad11168d22030416d853829f6eJim Grosbach * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
323f00e317064560ad11168d22030416d853829f6eJim Grosbach * distribute this software and its documentation for any purpose and
333f00e317064560ad11168d22030416d853829f6eJim Grosbach * without fee is hereby granted, provided that the above copyright
343f00e317064560ad11168d22030416d853829f6eJim Grosbach * notice appear in all copies and that both that copyright notice and
353f00e317064560ad11168d22030416d853829f6eJim Grosbach * this permission notice appear in supporting documentation, and that
363f00e317064560ad11168d22030416d853829f6eJim Grosbach * the name of M.I.T. not be used in advertising or publicity pertaining
373f00e317064560ad11168d22030416d853829f6eJim Grosbach * to distribution of the software without specific, written prior
383f00e317064560ad11168d22030416d853829f6eJim Grosbach * permission.  Furthermore if you modify this software you must label
393f00e317064560ad11168d22030416d853829f6eJim Grosbach * your software as modified software and not distribute it in such a
403f00e317064560ad11168d22030416d853829f6eJim Grosbach * fashion that it might be confused with the original MIT software.
413f00e317064560ad11168d22030416d853829f6eJim Grosbach * M.I.T. makes no representations about the suitability of this software
42dc89561fecf100d6c32d73c7b009fd73e51be688Jim Grosbach * for any purpose.  It is provided "as is" without express or implied
43e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * warranty.
44da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach *
45e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
46da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
47da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
48e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach *
49e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach */
50e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach
51e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#ifdef HAVE_UNISTD_H
52e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <unistd.h>
53e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#endif
54e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <stdio.h>
55e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#ifdef HAVE_STDLIB_H
56e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <stdlib.h>
57e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#endif
58e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <time.h>
59e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <string.h>
60e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <errno.h>
61e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <ctype.h>
62e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <limits.h>
63e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <stddef.h>
64e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <sys/types.h>
65e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <sys/stat.h>
66e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#include <dirent.h>
67e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#ifdef HAVE_PWD_H
6837ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#include <pwd.h>
6937ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#endif
7037ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach
7137ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#include <et/com_err.h>
7237ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#include "profile.h"
7337ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#include "prof_err.h"
7437ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach
7537ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#undef STAT_ONCE_PER_SECOND
7637ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#undef HAVE_STAT
7737ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach
7837ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach/*
7937ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach * prof_int.h
8037ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach */
8137ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach
8237ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbachtypedef long prf_magic_t;
8337ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach
8437ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach/*
8537ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach * This is the structure which stores the profile information for a
8637ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach * particular configuration file.
87e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach */
88e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbachstruct _prf_file_t {
89e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	prf_magic_t	magic;
90e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	char		*filespec;
91e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#ifdef STAT_ONCE_PER_SECOND
92e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	time_t		last_stat;
93e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach#endif
94e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	time_t		timestamp; /* time tree was last updated from file */
95e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	int		flags;	/* r/w, dirty */
96e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	int		upd_serial; /* incremented when data changes */
97e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	struct profile_node *root;
98e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach	struct _prf_file_t *next;
99e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach};
100e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach
101e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbachtypedef struct _prf_file_t *prf_file_t;
102e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach
103e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach/*
104e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach * The profile flags
105e8606dc7c878d4562da5e3e5609b9d7d734d498cJim Grosbach */
10637ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#define PROFILE_FILE_RW		0x0001
10737ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#define PROFILE_FILE_DIRTY	0x0002
10837ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach
10937ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach/*
11037ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach * This structure defines the high-level, user visible profile_t
11137ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach * object, which is used as a handle by users who need to query some
11237ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach * configuration file(s)
11337ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach */
11437ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbachstruct _profile_t {
11537ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach	prf_magic_t	magic;
11637ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach	prf_file_t	first_file;
11737ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach};
11837ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach
11937ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach/*
12037ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach * Used by the profile iterator in prof_get.c
12137ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach */
12237ee464ea98544d3ed84cec6dde5f769ce003d5fJim Grosbach#define PROFILE_ITER_LIST_SECTION	0x0001
123da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#define PROFILE_ITER_SECTIONS_ONLY	0x0002
124da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#define PROFILE_ITER_RELATIONS_ONLY	0x0004
125da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
1267ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach#define PROFILE_ITER_FINAL_SEEN		0x0100
1277ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach
1287ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach/*
1297ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS
130da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach */
131da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
132da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#define	PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0'))
133da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
134da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstruct profile_node {
135da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	errcode_t	magic;
136da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	char *name;
137da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	char *value;
138da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	int group_level;
139da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	unsigned int final:1;		/* Indicate don't search next file */
140da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	unsigned int deleted:1;
141da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	struct profile_node *first_child;
142da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	struct profile_node *parent;
143da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	struct profile_node *next, *prev;
144da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach};
145da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
146da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#define CHECK_MAGIC(node) \
147da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	  if ((node)->magic != PROF_MAGIC_NODE) \
148da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach		  return PROF_MAGIC_NODE;
149da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
150da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach/* profile parser declarations */
151da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstruct parse_state {
152da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	int	state;
153da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	int	group_level;
154da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	int	line_num;
155da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	struct profile_node *root_section;
156da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	struct profile_node *current_section;
157da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach};
158da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
159da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic profile_syntax_err_cb_t	syntax_err_cb;
160da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
161da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic errcode_t parse_line(char *line, struct parse_state *state);
162da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
163da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#ifdef DEBUG_PROGRAM
164da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic errcode_t profile_write_tree_file
165da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	(struct profile_node *root, FILE *dstfile);
166da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
167da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic errcode_t profile_write_tree_to_buffer
168da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	(struct profile_node *root, char **buf);
169da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#endif
170da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
171da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
172da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic void profile_free_node
173da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	(struct profile_node *relation);
174da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
175da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic errcode_t profile_create_node
176da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	(const char *name, const char *value,
177da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach		   struct profile_node **ret_node);
178da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
179da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#ifdef DEBUG_PROGRAM
180da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic errcode_t profile_verify_node
181da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach	(struct profile_node *node);
182da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach#endif
183da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbach
184da9f278c741e8ced7c1652720270918eb04ed348Jim Grosbachstatic errcode_t profile_add_node
18559642c260064a0c9140e048d702a21830020487fJim Grosbach	(struct profile_node *section,
18659642c260064a0c9140e048d702a21830020487fJim Grosbach		    const char *name, const char *value,
18759642c260064a0c9140e048d702a21830020487fJim Grosbach		    struct profile_node **ret_node);
18859642c260064a0c9140e048d702a21830020487fJim Grosbach
18959642c260064a0c9140e048d702a21830020487fJim Grosbachstatic errcode_t profile_find_node
19059642c260064a0c9140e048d702a21830020487fJim Grosbach	(struct profile_node *section,
19159642c260064a0c9140e048d702a21830020487fJim Grosbach		    const char *name, const char *value,
19259642c260064a0c9140e048d702a21830020487fJim Grosbach		    int section_flag, void **state,
19359642c260064a0c9140e048d702a21830020487fJim Grosbach		    struct profile_node **node);
19459642c260064a0c9140e048d702a21830020487fJim Grosbach
19559642c260064a0c9140e048d702a21830020487fJim Grosbachstatic errcode_t profile_node_iterator
19659642c260064a0c9140e048d702a21830020487fJim Grosbach	(void	**iter_p, struct profile_node **ret_node,
19759642c260064a0c9140e048d702a21830020487fJim Grosbach		   char **ret_name, char **ret_value);
19859642c260064a0c9140e048d702a21830020487fJim Grosbach
19959642c260064a0c9140e048d702a21830020487fJim Grosbachstatic errcode_t profile_open_file
20059642c260064a0c9140e048d702a21830020487fJim Grosbach	(const char * file, prf_file_t *ret_prof);
20159642c260064a0c9140e048d702a21830020487fJim Grosbach
20259642c260064a0c9140e048d702a21830020487fJim Grosbachstatic errcode_t profile_update_file
20359642c260064a0c9140e048d702a21830020487fJim Grosbach	(prf_file_t prf);
20459642c260064a0c9140e048d702a21830020487fJim Grosbach
20559642c260064a0c9140e048d702a21830020487fJim Grosbachstatic void profile_free_file
20659642c260064a0c9140e048d702a21830020487fJim Grosbach	(prf_file_t profile);
20759642c260064a0c9140e048d702a21830020487fJim Grosbach
20859642c260064a0c9140e048d702a21830020487fJim Grosbachstatic errcode_t profile_get_value(profile_t profile, const char *name,
20959642c260064a0c9140e048d702a21830020487fJim Grosbach				   const char *subname, const char *subsubname,
21059642c260064a0c9140e048d702a21830020487fJim Grosbach				   const char **ret_value);
21159642c260064a0c9140e048d702a21830020487fJim Grosbach
21259642c260064a0c9140e048d702a21830020487fJim Grosbach
21359642c260064a0c9140e048d702a21830020487fJim Grosbach/*
21459642c260064a0c9140e048d702a21830020487fJim Grosbach * prof_init.c --- routines that manipulate the user-visible profile_t
21559642c260064a0c9140e048d702a21830020487fJim Grosbach * 	object.
21659642c260064a0c9140e048d702a21830020487fJim Grosbach */
21759642c260064a0c9140e048d702a21830020487fJim Grosbach
21859642c260064a0c9140e048d702a21830020487fJim Grosbachstatic int compstr(const void *m1, const void *m2)
21959642c260064a0c9140e048d702a21830020487fJim Grosbach{
22059642c260064a0c9140e048d702a21830020487fJim Grosbach	const char *s1 = *((const char * const *) m1);
22159642c260064a0c9140e048d702a21830020487fJim Grosbach	const char *s2 = *((const char * const *) m2);
22259642c260064a0c9140e048d702a21830020487fJim Grosbach
22359642c260064a0c9140e048d702a21830020487fJim Grosbach	return strcmp(s1, s2);
22459642c260064a0c9140e048d702a21830020487fJim Grosbach}
22559642c260064a0c9140e048d702a21830020487fJim Grosbach
22659642c260064a0c9140e048d702a21830020487fJim Grosbachstatic void free_list(char **list)
22759642c260064a0c9140e048d702a21830020487fJim Grosbach{
22859642c260064a0c9140e048d702a21830020487fJim Grosbach    char	**cp;
22959642c260064a0c9140e048d702a21830020487fJim Grosbach
23059642c260064a0c9140e048d702a21830020487fJim Grosbach    if (list == 0)
23159642c260064a0c9140e048d702a21830020487fJim Grosbach	    return;
23259642c260064a0c9140e048d702a21830020487fJim Grosbach
23359642c260064a0c9140e048d702a21830020487fJim Grosbach    for (cp = list; *cp; cp++)
23459642c260064a0c9140e048d702a21830020487fJim Grosbach	free(*cp);
23559642c260064a0c9140e048d702a21830020487fJim Grosbach    free(list);
23659642c260064a0c9140e048d702a21830020487fJim Grosbach}
23759642c260064a0c9140e048d702a21830020487fJim Grosbach
23859642c260064a0c9140e048d702a21830020487fJim Grosbachstatic errcode_t get_dirlist(const char *dirname, char***ret_array)
23959642c260064a0c9140e048d702a21830020487fJim Grosbach{
24059642c260064a0c9140e048d702a21830020487fJim Grosbach	DIR *dir;
24159642c260064a0c9140e048d702a21830020487fJim Grosbach	struct dirent *de;
24259642c260064a0c9140e048d702a21830020487fJim Grosbach	struct stat st;
2437ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach	errcode_t retval;
2447ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach	char *fn, *cp;
2457ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach	char **array = 0, **new_array;
2467ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach	int max = 0, num = 0;
2477ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach
2487ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach	dir = opendir(dirname);
2497ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach	if (!dir)
2507ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach		return errno;
2517ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach
2527ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach	while ((de = readdir(dir)) != NULL) {
2537ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach		for (cp = de->d_name; *cp; cp++) {
2547ed6d22e9637c52b3511ac6907830251d1124e60Jim Grosbach			if (!isalnum(*cp) &&
255e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			    (*cp != '-') &&
256e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			    (*cp != '_'))
25776cbe02cdd57a297d9c6f1e5106e4718abd7ff9fJim Grosbach				break;
258e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		}
259e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		if (*cp)
260e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			continue;
261e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		fn = malloc(strlen(dirname) + strlen(de->d_name) + 2);
262e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		if (!fn) {
263e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			retval = ENOMEM;
264e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			goto errout;
265e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		}
266e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		sprintf(fn, "%s/%s", dirname, de->d_name);
267e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) {
268e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			free(fn);
269e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			continue;
270e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		}
271e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		if (num >= max) {
272e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			max += 10;
273e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			new_array = realloc(array, sizeof(char *) * (max+1));
274e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			if (!new_array) {
275e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach				retval = ENOMEM;
276e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach				goto errout;
277e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			}
278e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach			array = new_array;
279e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		}
280e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		array[num++] = fn;
281e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	}
282e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	if (array) {
283e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		qsort(array, num, sizeof(char *), compstr);
284e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		array[num++] = 0;
285e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	}
286e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	*ret_array = array;
287e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	closedir(dir);
288e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	return 0;
289e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbacherrout:
290e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	closedir(dir);
291e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	free_list(array);
292e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	return retval;
293e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach}
294e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach
295e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbacherrcode_t
296e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbachprofile_init(const char **files, profile_t *ret_profile)
297e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach{
298e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	const char **fs;
299e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	profile_t profile;
300e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	prf_file_t  new_file, *last;
301e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	errcode_t retval = 0;
302e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	char **cpp, *cp, **array = 0;
303e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach
304e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	profile = malloc(sizeof(struct _profile_t));
305e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	if (!profile)
306e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach		return ENOMEM;
307e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	memset(profile, 0, sizeof(struct _profile_t));
308e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	profile->magic = PROF_MAGIC_PROFILE;
309e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach	last = &profile->first_file;
310e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach
311e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach        /* if the filenames list is not specified return an empty profile */
312e52240c3705f3133eb8c4ebb4220054c68de2651Jim Grosbach        if ( files ) {
31321101d60ce94f51651f71eeb61ceb8264eccac83Jim Grosbach	    for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) {
31421101d60ce94f51651f71eeb61ceb8264eccac83Jim Grosbach		retval = get_dirlist(*fs, &array);
31521101d60ce94f51651f71eeb61ceb8264eccac83Jim Grosbach		if (retval == 0) {
31621101d60ce94f51651f71eeb61ceb8264eccac83Jim Grosbach			if (!array)
31721101d60ce94f51651f71eeb61ceb8264eccac83Jim Grosbach				continue;
31821101d60ce94f51651f71eeb61ceb8264eccac83Jim Grosbach			for (cpp = array; (cp = *cpp); cpp++) {
319fff76ee7ef007b2bb74804f165fee475e30ead0dJim Grosbach				retval = profile_open_file(cp, &new_file);
320fff76ee7ef007b2bb74804f165fee475e30ead0dJim Grosbach				if (retval == EACCES)
32137023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach					continue;
32237023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach				if (retval)
32337023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach					goto errout;
32437023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach				*last = new_file;
32537023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach				last = &new_file->next;
32637023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach			}
32737023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach		} else if (retval != ENOTDIR)
32837023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach			goto errout;
329f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach
330f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach		retval = profile_open_file(*fs, &new_file);
331f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach		/* if this file is missing, skip to the next */
332f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach		if (retval == ENOENT || retval == EACCES) {
333f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach			continue;
334f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach		}
33537023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach		if (retval)
33637023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach			goto errout;
33737023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach		*last = new_file;
33837023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach		last = &new_file->next;
33937023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach	    }
34037023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach	    /*
341f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	     * If all the files were not found, return the appropriate error.
342f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	     */
343f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	    if (!profile->first_file) {
344f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach		profile_release(profile);
345f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach		return ENOENT;
346f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	    }
347f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	}
348f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach
349f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	free_list(array);
350f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach        *ret_profile = profile;
351f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach        return 0;
352f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbacherrout:
353f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	free_list(array);
354f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	profile_release(profile);
355f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach	return retval;
356f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbach}
35737023b05c84000373fcfc0871edad3c2b995be33Jim Grosbach
358f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbachvoid
359f333d471d2cdd47d830dfe3a3e40efbb106c100dJim Grosbachprofile_release(profile_t profile)
36083ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach{
36183ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach	prf_file_t	p, next;
36283ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach
36383ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
36483ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach		return;
36583ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach
36683ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach	for (p = profile->first_file; p; p = next) {
36783ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach		next = p->next;
36883ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach		profile_free_file(p);
369d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	}
370d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	profile->magic = 0;
37183ab070fc1fbb02ca77b0a37e6ae0eacf58001e1Jim Grosbach	free(profile);
372d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach}
373d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach
374d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach
375d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach/*
376d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach * prof_file.c ---- routines that manipulate an individual profile file.
377d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach */
378d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach
379d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbacherrcode_t profile_open_file(const char * filespec,
380d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach			    prf_file_t *ret_prof)
381d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach{
382d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	prf_file_t	prf;
383d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	errcode_t	retval;
384d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	char		*home_env = 0;
385d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	unsigned int	len;
386d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	char		*expanded_filename;
387d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach
388d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	prf = malloc(sizeof(struct _prf_file_t));
389d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	if (!prf)
390d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach		return ENOMEM;
391d986bc66bc56251c2b7d5b9a89df14c4760568fcJim Grosbach	memset(prf, 0, sizeof(struct _prf_file_t));
39214ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	prf->magic = PROF_MAGIC_FILE;
39314ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach
39414ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	len = strlen(filespec)+1;
39514ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	if (filespec[0] == '~' && filespec[1] == '/') {
39614ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		home_env = getenv("HOME");
39714ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#ifdef HAVE_PWD_H
39814ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		if (home_env == NULL) {
39914ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#ifdef HAVE_GETWUID_R
40014ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    struct passwd *pw, pwx;
40114ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    uid_t uid;
40214ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    char pwbuf[BUFSIZ];
40314ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach
40414ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    uid = getuid();
40514ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    if (!getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw)
40614ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach			&& pw != NULL && pw->pw_dir[0] != 0)
40714ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach			home_env = pw->pw_dir;
40814ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#else
40914ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    struct passwd *pw;
41014ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach
41114ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    pw = getpwuid(getuid());
41214ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		    home_env = pw->pw_dir;
41314ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#endif
41414ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		}
41514ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#endif
41614ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		if (home_env)
41714ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach			len += strlen(home_env);
41814ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	}
41914ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	expanded_filename = malloc(len);
42014ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	if (expanded_filename == 0) {
42114ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	    profile_free_file(prf);
42214ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	    return errno;
42314ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	}
42414ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	if (home_env) {
42514ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	    strcpy(expanded_filename, home_env);
42614ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	    strcat(expanded_filename, filespec+1);
42714ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	} else
42814ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	    memcpy(expanded_filename, filespec, len);
42914ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach
43014ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	prf->filespec = expanded_filename;
43114ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach
43214ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	retval = profile_update_file(prf);
43314ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	if (retval) {
43414ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		profile_free_file(prf);
43514ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach		return retval;
43614ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	}
43714ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach
43814ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	*ret_prof = prf;
43914ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	return 0;
44014ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach}
44114ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach
44214ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbacherrcode_t profile_update_file(prf_file_t prf)
44314ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach{
44414ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	errcode_t retval;
44514ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#ifdef HAVE_STAT
44614ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	struct stat st;
44714ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#ifdef STAT_ONCE_PER_SECOND
44814ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach	time_t now;
44914ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#endif
45014ab1c3387a240a914cf8b1907bb3609bae72269Jim Grosbach#endif
4516f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach	FILE *f;
4526f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach	char buf[2048];
4536f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach	struct parse_state state;
4546f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach
4556f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach#ifdef HAVE_STAT
4566f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach#ifdef STAT_ONCE_PER_SECOND
4576f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach	now = time(0);
4586f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach	if (now == prf->last_stat && prf->root != NULL) {
4596f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach	    return 0;
4606f9f8845028d4d3b96c33417398034a71137d867Jim Grosbach	}
461032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach#endif
462032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	if (stat(prf->filespec, &st)) {
463032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	    retval = errno;
464032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	    return retval;
465032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	}
466032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach#ifdef STAT_ONCE_PER_SECOND
467032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	prf->last_stat = now;
468032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach#endif
469032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	if (st.st_mtime == prf->timestamp && prf->root != NULL) {
470032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	    return 0;
471032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	}
472032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	if (prf->root) {
473032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach		profile_free_node(prf->root);
474032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach		prf->root = 0;
475032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	}
476032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach#else
477032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	/*
478032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	 * If we don't have the stat() call, assume that our in-core
479032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	 * memory image is correct.  That is, we won't reread the
480032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	 * profile file if it changes.
481032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	 */
482032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	if (prf->root) {
483032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	    return 0;
484032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	}
485032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach#endif
486032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	memset(&state, 0, sizeof(struct parse_state));
487032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	retval = profile_create_node("(root)", 0, &state.root_section);
488032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	if (retval)
489032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach		return retval;
490032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	errno = 0;
491032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	f = fopen(prf->filespec, "r");
492032434d622b6cd030a60bb9045a520c93b0d7d68Jim Grosbach	if (f == NULL) {
493e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach		retval = errno;
494e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach		if (retval == 0)
495e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach			retval = ENOENT;
496e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach		return retval;
497e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	}
498e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	prf->upd_serial++;
499e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	while (!feof(f)) {
500e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach		if (fgets(buf, sizeof(buf), f) == NULL)
501e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach			break;
502e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach		retval = parse_line(buf, &state);
503e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach		if (retval) {
504e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach			if (syntax_err_cb)
505e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach				(syntax_err_cb)(prf->filespec, retval,
506e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach						state.line_num);
507e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach			fclose(f);
508e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach			return retval;
509e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach		}
510e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	}
511e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	prf->root = state.root_section;
512e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach
513e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	fclose(f);
514e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach
515e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach#ifdef HAVE_STAT
516e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	prf->timestamp = st.st_mtime;
517e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach#endif
518e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach	return 0;
519e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach}
520e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach
521e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbachvoid profile_free_file(prf_file_t prf)
522e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach{
523e77494e3e3da59afaa51d1bbcf732fa2851d865dJim Grosbach    if (prf->root)
52400a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	profile_free_node(prf->root);
52500a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach    if (prf->filespec)
52600a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	    free(prf->filespec);
52700a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach    free(prf);
52800a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach}
52900a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
53000a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach/* Begin the profile parser */
53100a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
53200a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbachprofile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook)
53300a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach{
53400a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	profile_syntax_err_cb_t	old;
53500a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
53600a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	old = syntax_err_cb;
53700a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	syntax_err_cb = hook;
53800a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	return(old);
53900a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach}
54000a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
54100a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach#define STATE_INIT_COMMENT	0
54200a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach#define STATE_STD_LINE		1
54300a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach#define STATE_GET_OBRACE	2
54400a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
54500a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbachstatic char *skip_over_blanks(char *cp)
54600a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach{
54700a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	while (*cp && isspace((int) (*cp)))
54800a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach		cp++;
54900a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	return cp;
55000a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach}
55100a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
55200a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbachstatic int end_or_comment(char ch)
55300a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach{
55400a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	return (ch == 0 || ch == '#' || ch == ';');
55500a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach}
55600a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
55700a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbachstatic char *skip_over_nonblanks(char *cp)
55800a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach{
55900a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	while (!end_or_comment(*cp) && !isspace(*cp))
56000a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach		cp++;
56100a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	return cp;
56200a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach}
56300a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
56400a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbachstatic void strip_line(char *line)
56500a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach{
56600a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	char *p = line + strlen(line);
56700a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	while (p > line && (p[-1] == '\n' || p[-1] == '\r'))
56800a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	    *p-- = 0;
56900a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach}
57000a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
57100a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbachstatic void parse_quoted_string(char *str)
57200a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach{
57300a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	char *to, *from;
57400a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
57500a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	to = from = str;
57600a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach
57700a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach	for (to = from = str; *from && *from != '"'; to++, from++) {
57800a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach		if (*from == '\\') {
57900a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach			from++;
58000a66653cbe56dfbdb831172b54097bf8256a191Jim Grosbach			switch (*from) {
581791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach			case 'n':
582791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach				*to = '\n';
583791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach				break;
584791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach			case 't':
585791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach				*to = '\t';
586791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach				break;
587791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach			case 'b':
588791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach				*to = '\b';
589791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach				break;
590791feea10071223886e2fe2bfa0e1f4cb2c0ce74Jim Grosbach			default:
5913b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach				*to = *from;
5923b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach			}
5933b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach			continue;
5943b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		}
5953b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		*to = *from;
5963b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	}
5973b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	*to = '\0';
5983b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach}
5993b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach
6003b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbachstatic errcode_t parse_line(char *line, struct parse_state *state)
6013b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach{
6023b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	char	*cp, ch, *tag, *value;
6033b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	char	*p;
6043b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	errcode_t retval;
6053b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	struct profile_node	*node;
6063b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	int do_subsection = 0;
6073b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	void *iter = 0;
6083b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach
6093b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	state->line_num++;
6103b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	if (state->state == STATE_GET_OBRACE) {
6113b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		cp = skip_over_blanks(line);
6123b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		if (*cp != '{')
6133b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach			return PROF_MISSING_OBRACE;
6143b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		state->state = STATE_STD_LINE;
6153b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		return 0;
6163b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	}
6173b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	if (state->state == STATE_INIT_COMMENT) {
6183b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		if (line[0] != '[')
6193b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach			return 0;
6203b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		state->state = STATE_STD_LINE;
6213b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	}
622e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach
623e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach	if (*line == 0)
624e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach		return 0;
62536711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	strip_line(line);
62636711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	cp = skip_over_blanks(line);
62736711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	ch = *cp;
62836711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	if (end_or_comment(ch))
62936711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		return 0;
63036711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	if (ch == '[') {
63136711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		if (state->group_level > 0)
63236711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach			return PROF_SECTION_NOTOP;
63336711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		cp++;
63436711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		cp = skip_over_blanks(cp);
63536711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		p = strchr(cp, ']');
63636711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		if (p == NULL)
63736711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach			return PROF_SECTION_SYNTAX;
63836711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		if (*cp == '"') {
63936711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach			cp++;
640e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach			parse_quoted_string(cp);
641e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach		} else {
642e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach			*p-- = '\0';
643e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach			while (isspace(*p) && (p > cp))
644e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach				*p-- = '\0';
645e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach			if (*cp == 0)
646e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach				return PROF_SECTION_SYNTAX;
647e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach		}
648e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach		retval = profile_find_node(state->root_section, cp, 0, 1,
649e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach					   &iter, &state->current_section);
650e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach		if (retval == PROF_NO_SECTION) {
651e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach			retval = profile_add_node(state->root_section,
652e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach						  cp, 0,
653e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach						  &state->current_section);
654e540c7422ca13c950f0e8f6f93af7225bb7742a9Jim Grosbach			if (retval)
6553b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach				return retval;
6563b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		} else if (retval)
657c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach			return retval;
658c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach
659c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach		/*
660c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach		 * Finish off the rest of the line.
661c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach		 */
662c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach		cp = p+1;
663c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach		if (*cp == '*') {
664c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach			state->current_section->final = 1;
66570d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach			cp++;
66670d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		}
66770d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		/*
66870d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		 * Spaces or comments after ']' should not be fatal
66970d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		 */
67070d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		cp = skip_over_blanks(cp);
67170d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		if (!end_or_comment(*cp))
67270d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach			return PROF_SECTION_SYNTAX;
67370d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		return 0;
67470d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach	}
67570d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach	if (ch == '}') {
67670d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		if (state->group_level == 0)
67770d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach			return PROF_EXTRA_CBRACE;
67870d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		if (*(cp+1) == '*')
67970d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach			state->current_section->final = 1;
68070d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		state->current_section = state->current_section->parent;
68170d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		state->group_level--;
68270d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach		return 0;
68370d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach	}
68470d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach	/*
68570d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach	 * Parse the relations
68670d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach	 */
68770d8fcfaa04eb20541b006a8fb97cbc1d3033cc4Jim Grosbach	tag = cp;
688c8ae39e746a20dc326def0ccfc052df3e21f16d3Jim Grosbach	cp = strchr(cp, '=');
689ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach	if (!cp)
690ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		return PROF_RELATION_SYNTAX;
691ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach	if (cp == tag)
692ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach	    return PROF_RELATION_SYNTAX;
693ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach	*cp = '\0';
694ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach	if (*tag == '"') {
695ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		tag++;
6965f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		parse_quoted_string(tag);
6975f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	} else {
6985f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		/* Look for whitespace on left-hand side.  */
699ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		p = skip_over_nonblanks(tag);
700ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		if (*p)
701ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach			*p++ = 0;
702ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		p = skip_over_blanks(p);
703ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		/* If we have more non-whitespace, it's an error.  */
704ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		if (*p)
7055f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach			return PROF_RELATION_SYNTAX;
7065f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	}
7075f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach
7085f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	cp = skip_over_blanks(cp+1);
7095f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	value = cp;
7105f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	ch = value[0];
7115f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	if (ch == '"') {
7125f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		value++;
7135f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		parse_quoted_string(value);
7145f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	} else if (end_or_comment(ch)) {
7155f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		do_subsection++;
7165f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		state->state = STATE_GET_OBRACE;
7175f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach	} else if (value[0] == '{') {
7185f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		cp = skip_over_blanks(value+1);
7195f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		ch = *cp;
7205f16057d1e4b711d492091bc555693a03d4a1b6eJim Grosbach		if (end_or_comment(ch))
721ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach			do_subsection++;
722ffa3225e26cc1977d20f0d9649fcd6f38a3c4815Jim Grosbach		else
7231a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach			return PROF_RELATION_SYNTAX;
7241a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach	} else {
7251a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach		cp = skip_over_nonblanks(value);
7261a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach		p = skip_over_blanks(cp);
7271a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach		ch = *p;
7281a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach		*cp = 0;
7291a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach		if (!end_or_comment(ch))
7301a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach			return PROF_RELATION_SYNTAX;
7311a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach	}
7321a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach	if (do_subsection) {
7332317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		p = strchr(tag, '*');
7342317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		if (p)
7352317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach			*p = '\0';
7362317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		retval = profile_add_node(state->current_section,
7372317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach					  tag, 0, &state->current_section);
7382317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		if (retval)
7392317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach			return retval;
7402317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		if (p)
7412317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach			state->current_section->final = 1;
7422317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		state->group_level++;
7432317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		return 0;
7442317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach	}
7452317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach	p = strchr(tag, '*');
7462317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach	if (p)
7472317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		*p = '\0';
7482317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach	profile_add_node(state->current_section, tag, value, &node);
7492317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach	if (p)
7502317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach		node->final = 1;
7512317fe1584e02582c616c1c4d15954999ff5525aJim Grosbach	return 0;
75280d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach}
75380d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach
75480d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach#ifdef DEBUG_PROGRAM
75580d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach/*
75680d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach * Return TRUE if the string begins or ends with whitespace
75780d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach */
75880d01dd3d19a84621324ac444c6749602df7a513Jim Grosbachstatic int need_double_quotes(char *str)
75980d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach{
76080d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach	if (!str || !*str)
76180d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach		return 0;
76280d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach	if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1))))
76380d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach		return 1;
76480d01dd3d19a84621324ac444c6749602df7a513Jim Grosbach	if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b') ||
7651a2be4db5b12cb7bfa351bcebd5e94b0decb021fJim Grosbach	    strchr(str, ' ') || strchr(str, '#') || strchr(str, ';'))
766b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		return 1;
767b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	return 0;
768b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach}
769b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach
770b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach/*
771b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach * Output a string with double quotes, doing appropriate backquoting
772b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach * of characters as necessary.
773b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach */
774b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbachstatic void output_quoted_string(char *str, void (*cb)(const char *,void *),
775b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach				 void *data)
776b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach{
777b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	char	ch;
778b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	char buf[2];
779b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach
780b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	cb("\"", data);
781b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	if (!str) {
782b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		cb("\"", data);
783b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		return;
784b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	}
785b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	buf[1] = 0;
786b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	while ((ch = *str++)) {
787b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		switch (ch) {
788b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		case '\\':
789b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			cb("\\\\", data);
790b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			break;
791b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		case '\n':
792b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			cb("\\n", data);
793b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			break;
794b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		case '\t':
795b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			cb("\\t", data);
796b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			break;
797b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		case '\b':
798b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			cb("\\b", data);
799b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			break;
800b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		default:
801b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			/* This would be a lot faster if we scanned
802b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			   forward for the next "interesting"
803b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			   character.  */
804b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			buf[0] = ch;
805b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			cb(buf, data);
806b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			break;
807b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		}
808b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	}
809b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	cb("\"", data);
810b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach}
811b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach
812b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach#ifndef EOL
813b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach#define EOL "\n"
814b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach#endif
815b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach
816b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach/* Errors should be returned, not ignored!  */
817b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbachstatic void dump_profile(struct profile_node *root, int level,
818b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			 void (*cb)(const char *, void *), void *data)
819b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach{
820b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	int i;
821b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	struct profile_node *p;
822b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	void *iter;
823b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	long retval;
824b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach
825b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	iter = 0;
826b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach	do {
827b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		retval = profile_find_node(root, 0, 0, 0, &iter, &p);
828b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach		if (retval)
829b29b4dd988c50d5c4a15cd196e7910bf46f30b83Jim Grosbach			break;
830ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		for (i=0; i < level; i++)
831ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach			cb("\t", data);
832ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		if (need_double_quotes(p->name))
833ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach			output_quoted_string(p->name, cb, data);
834ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		else
835ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach			cb(p->name, data);
836ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		cb(" = ", data);
837ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		if (need_double_quotes(p->value))
838ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach			output_quoted_string(p->value, cb, data);
839ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		else
840ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach			cb(p->value, data);
841ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		cb(EOL, data);
842ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach	} while (iter != 0);
843c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach
844c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	iter = 0;
845c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	do {
846c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach		retval = profile_find_node(root, 0, 0, 1, &iter, &p);
847c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach		if (retval)
848c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			break;
849c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach		if (level == 0)	{ /* [xxx] */
850c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb("[", data);
851c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			if (need_double_quotes(p->name))
852c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach				output_quoted_string(p->name, cb, data);
853c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			else
854c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach				cb(p->name, data);
855c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb("]", data);
856c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb(p->final ? "*" : "", data);
857c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb(EOL, data);
858c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			dump_profile(p, level+1, cb, data);
859c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb(EOL, data);
860c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach		} else { 	/* xxx = { ... } */
861c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			for (i=0; i < level; i++)
862c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach				cb("\t", data);
863c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			if (need_double_quotes(p->name))
864c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach				output_quoted_string(p->name, cb, data);
865c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			else
866c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach				cb(p->name, data);
867c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb(" = {", data);
868c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb(EOL, data);
869c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			dump_profile(p, level+1, cb, data);
870c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			for (i=0; i < level; i++)
871c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach				cb("\t", data);
872c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb("}", data);
873c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb(p->final ? "*" : "", data);
874c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			cb(EOL, data);
875c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach		}
876c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	} while (iter != 0);
877c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach}
878c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach
879c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbachstatic void dump_profile_to_file_cb(const char *str, void *data)
880c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach{
881c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	fputs(str, data);
882c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach}
883c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach
884c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbacherrcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile)
885c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach{
886c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	dump_profile(root, 0, dump_profile_to_file_cb, dstfile);
887c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	return 0;
888c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach}
889c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach
890c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbachstruct prof_buf {
891c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	char *base;
892c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	size_t cur, max;
893c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	int err;
894c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach};
895c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach
896c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbachstatic void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len)
897c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach{
898c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach	if (b->err)
899a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach		return;
900a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach	if (b->max - b->cur < len) {
901a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach		size_t newsize;
902a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach		char *newptr;
903a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach
904a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach		newsize = b->max + (b->max >> 1) + len + 1024;
905a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach		newptr = realloc(b->base, newsize);
906a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach		if (newptr == NULL) {
907a67851445902d1fc01fa2a37a3dfc347af949f84Jim Grosbach			b->err = 1;
908c3635c2e928a7ecde11398ff272411f6dea2dcd2Jim Grosbach			return;
909ab40f4b737b0a87c4048a9ad2f0c02be735e3770Jim Grosbach		}
91088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		b->base = newptr;
91188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		b->max = newsize;
91288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	}
91388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	memcpy(b->base + b->cur, d, len);
91488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	b->cur += len; 		/* ignore overflow */
91588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach}
91688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
91788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbachstatic void dump_profile_to_buffer_cb(const char *str, void *data)
91888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach{
91988d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	add_data_to_buffer((struct prof_buf *)data, str, strlen(str));
92088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach}
92188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
92288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbacherrcode_t profile_write_tree_to_buffer(struct profile_node *root,
92388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach				       char **buf)
92488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach{
92588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	struct prof_buf prof_buf = { 0, 0, 0, 0 };
92688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
92788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf);
92888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	if (prof_buf.err) {
92988d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		*buf = NULL;
93088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		return ENOMEM;
93188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	}
93288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	add_data_to_buffer(&prof_buf, "", 1); /* append nul */
93388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) {
93488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		char *newptr = realloc(prof_buf.base, prof_buf.cur);
93588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		if (newptr)
93688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach			prof_buf.base = newptr;
93788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	}
93888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	*buf = prof_buf.base;
93988d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	return 0;
94088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach}
94188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach#endif
94288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
94388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach/*
94488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * prof_tree.c --- these routines maintain the parse tree of the
94588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * 	config file.
94688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach *
94788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * All of the details of how the tree is stored is abstracted away in
94888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * this file; all of the other profile routines build, access, and
94988d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * modify the tree via the accessor functions found in this file.
95088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach *
95188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * Each node may represent either a relation or a section header.
95288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach *
95388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * A section header must have its value field set to 0, and may a one
95488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * or more child nodes, pointed to by first_child.
95588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach *
95688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * A relation has as its value a pointer to allocated memory
95788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * containing a string.  Its first_child pointer must be null.
95888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach *
95988d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach */
96088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
96188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach/*
96288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach * Free a node, and any children
96388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach */
96488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbachvoid profile_free_node(struct profile_node *node)
96588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach{
96688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	struct profile_node *child, *next;
96788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
96888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	if (node->magic != PROF_MAGIC_NODE)
96988d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		return;
97088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
97188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	if (node->name)
97288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		free(node->name);
97388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	if (node->value)
97488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		free(node->value);
97588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
97688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	for (child=node->first_child; child; child = next) {
97788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		next = child->next;
97888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach		profile_free_node(child);
97988d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	}
98088d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	node->magic = 0;
98188d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
98288d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	free(node);
98388d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach}
98488d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
98588d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach#ifndef HAVE_STRDUP
98688d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach#undef strdup
98761b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach#define strdup MYstrdup
98861b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbachstatic char *MYstrdup (const char *s)
98961b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach{
99061b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach    size_t sz = strlen(s) + 1;
99161b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach    char *p = malloc(sz);
99261b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach    if (p != 0)
99361b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach	memcpy(p, s, sz);
99461b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach    return p;
99561b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach}
99661b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach#endif
99761b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach
99861b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach/*
99961b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach * Create a node
100061b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach */
100161b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbacherrcode_t profile_create_node(const char *name, const char *value,
100261b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach			      struct profile_node **ret_node)
100361b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach{
100461b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach	struct profile_node *new;
100561b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach
100661b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach	new = malloc(sizeof(struct profile_node));
100761b1b21e9ad2b8af163a352766eeb159979f4ff2Jim Grosbach	if (!new)
100810c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach		return ENOMEM;
100910c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	memset(new, 0, sizeof(struct profile_node));
101010c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	new->name = strdup(name);
101110c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	if (new->name == 0) {
101210c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	    profile_free_node(new);
101310c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	    return ENOMEM;
101410c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	}
101510c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	if (value) {
101610c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach		new->value = strdup(value);
101710c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach		if (new->value == 0) {
101810c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach		    profile_free_node(new);
101910c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach		    return ENOMEM;
102010c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach		}
102110c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	}
102210c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	new->magic = PROF_MAGIC_NODE;
102310c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach
102410c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	*ret_node = new;
102510c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	return 0;
102610c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach}
102710c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach
102810c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach/*
102910c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach * This function verifies that all of the representation invarients of
103010c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach * the profile are true.  If not, we have a programming bug somewhere,
103110c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach * probably in this file.
103210c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach */
103310c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach#ifdef DEBUG_PROGRAM
103410c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbacherrcode_t profile_verify_node(struct profile_node *node)
103510c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach{
103610c7d70a4e843b3006db9f5f583d6f6f56cc245eJim Grosbach	struct profile_node *p, *last;
103788d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach	errcode_t	retval;
103888d1bc832ca5b458c8460929227be8eae6c6bdc3Jim Grosbach
1039a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	CHECK_MAGIC(node);
1040a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach
1041a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	if (node->value && node->first_child)
1042a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		return PROF_SECTION_WITH_VALUE;
1043a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach
1044a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	last = 0;
1045a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	for (p = node->first_child; p; last = p, p = p->next) {
1046a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		if (p->prev != last)
1047a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach			return PROF_BAD_LINK_LIST;
1048a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		if (last && (last->next != p))
1049a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach			return PROF_BAD_LINK_LIST;
1050a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		if (node->group_level+1 != p->group_level)
1051a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach			return PROF_BAD_GROUP_LVL;
1052a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		if (p->parent != node)
1053a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach			return PROF_BAD_PARENT_PTR;
1054a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		retval = profile_verify_node(p);
1055a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		if (retval)
1056a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach			return retval;
1057a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	}
1058a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	return 0;
1059a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach}
1060a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach#endif
1061a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach
1062a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach/*
1063a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach * Add a node to a particular section
1064a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach */
1065a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbacherrcode_t profile_add_node(struct profile_node *section, const char *name,
1066a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach			   const char *value, struct profile_node **ret_node)
1067a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach{
1068a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	errcode_t retval;
1069a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	struct profile_node *p, *last, *new;
1070a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach
1071a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	CHECK_MAGIC(section);
1072a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach
1073a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	if (section->value)
1074a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		return PROF_ADD_NOT_SECTION;
1075a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach
1076a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	/*
1077a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	 * Find the place to insert the new node.  We look for the
1078a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	 * place *after* the last match of the node name, since
1079a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	 * order matters.
1080a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	 */
108141438398c13be01ec53c3ad6b08a6cab47e96735Jim Grosbach	for (p=section->first_child, last = 0; p; last = p, p = p->next) {
1082a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		int cmp;
1083a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		cmp = strcmp(p->name, name);
1084a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		if (cmp > 0)
1085a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach			break;
1086a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	}
1087a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	retval = profile_create_node(name, value, &new);
1088a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	if (retval)
1089a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		return retval;
1090a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	new->group_level = section->group_level+1;
1091a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	new->deleted = 0;
1092a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	new->parent = section;
1093a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	new->prev = last;
1094a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	new->next = p;
1095a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	if (p)
1096a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		p->prev = new;
1097a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach	if (last)
1098a4c34ab54485f64d3b962a499526825a7a0d4bbcJim Grosbach		last->next = new;
1099616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach	else
1100616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach		section->first_child = new;
1101616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach	if (ret_node)
1102616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach		*ret_node = new;
1103616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach	return 0;
1104616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach}
1105616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach
1106616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach/*
1107616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * Iterate through the section, returning the nodes which match
1108616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * the given name.  If name is NULL, then interate through all the
1109616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * nodes in the section.  If section_flag is non-zero, only return the
1110616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * section which matches the name; don't return relations.  If value
1111616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * is non-NULL, then only return relations which match the requested
1112616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * value.  (The value argument is ignored if section_flag is non-zero.)
1113616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach *
1114616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * The first time this routine is called, the state pointer must be
1115616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * null.  When this profile_find_node_relation() returns, if the state
1116616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * pointer is non-NULL, then this routine should be called again.
1117616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach * (This won't happen if section_flag is non-zero, obviously.)
1118616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach *
1119616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach */
1120616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbacherrcode_t profile_find_node(struct profile_node *section, const char *name,
1121616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach			    const char *value, int section_flag, void **state,
1122616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach			    struct profile_node **node)
1123616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach{
1124616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach	struct profile_node *p;
1125616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach
1126616fbdf987170addd0d8f75f4fd677589d54cd75Jim Grosbach	CHECK_MAGIC(section);
112786fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	p = *state;
112886fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	if (p) {
112986fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		CHECK_MAGIC(p);
113086fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	} else
113186fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		p = section->first_child;
113286fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach
113386fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	for (; p; p = p->next) {
113486fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		if (name && (strcmp(p->name, name)))
113586fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			continue;
113686fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		if (section_flag) {
113786fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			if (p->value)
113886fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach				continue;
113986fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		} else {
114086fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			if (!p->value)
114186fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach				continue;
114286fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			if (value && (strcmp(p->value, value)))
114386fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach				continue;
114486fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		}
114586fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		if (p->deleted)
114686fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		    continue;
114786fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		/* A match! */
114886fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		if (node)
114986fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			*node = p;
115086fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		break;
115186fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	}
115286fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	if (p == 0) {
115386fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		*state = 0;
115486fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION;
115586fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	}
115686fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	/*
115786fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	 * OK, we've found one match; now let's try to find another
115886fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	 * one.  This way, if we return a non-zero state pointer,
115986fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	 * there's guaranteed to be another match that's returned.
116086fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	 */
116186fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	for (p = p->next; p; p = p->next) {
116286fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		if (name && (strcmp(p->name, name)))
116386fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			continue;
116486fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		if (section_flag) {
116586fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			if (p->value)
116686fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach				continue;
116786fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		} else {
116886fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			if (!p->value)
116986fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach				continue;
117086fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach			if (value && (strcmp(p->value, value)))
117186fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach				continue;
117286fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		}
117386fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		/* A match! */
117486fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach		break;
117586fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	}
117686fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	*state = p;
117786fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	return 0;
117886fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach}
117986fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach
118086fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach/*
118186fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach * This is a general-purpose iterator for returning all nodes that
1182f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach * match the specified name array.
1183f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach */
1184f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbachstruct profile_iterator {
1185f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	prf_magic_t		magic;
1186f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	profile_t		profile;
1187f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	int			flags;
1188f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	const char 		*const *names;
1189f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	const char		*name;
1190f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	prf_file_t		file;
1191f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	int			file_serial;
1192f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	int			done_idx;
1193f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	struct profile_node 	*node;
1194f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	int			num;
1195f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach};
1196f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach
1197f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbacherrcode_t
1198f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbachprofile_iterator_create(profile_t profile, const char *const *names, int flags,
1199f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach			void **ret_iter)
1200f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach{
1201f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	struct profile_iterator *iter;
1202f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	int	done_idx = 0;
1203f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach
1204f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	if (profile == 0)
1205f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach		return PROF_NO_PROFILE;
1206f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	if (profile->magic != PROF_MAGIC_PROFILE)
1207f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach		return PROF_MAGIC_PROFILE;
1208f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	if (!names)
1209f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach		return PROF_BAD_NAMESET;
1210f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	if (!(flags & PROFILE_ITER_LIST_SECTION)) {
1211f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach		if (!names[0])
1212f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach			return PROF_BAD_NAMESET;
1213f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach		done_idx = 1;
1214f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	}
1215f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach
1216f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	if ((iter = malloc(sizeof(struct profile_iterator))) == NULL)
1217f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach		return ENOMEM;
1218f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach
1219f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->magic = PROF_MAGIC_ITERATOR;
1220f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->profile = profile;
1221f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->names = names;
1222f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->flags = flags;
1223f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->file = profile->first_file;
1224f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->done_idx = done_idx;
1225f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->node = 0;
1226f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	iter->num = 0;
1227f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	*ret_iter = iter;
1228f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	return 0;
1229f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach}
1230f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach
1231f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbachvoid profile_iterator_free(void **iter_p)
1232f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach{
1233f790193aec11747bb35206d2c79e0c5ffbc6dc7fJim Grosbach	struct profile_iterator *iter;
12348ae45af7941dc3e78859ba3624676081590c435dJim Grosbach
12358ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	if (!iter_p)
12368ae45af7941dc3e78859ba3624676081590c435dJim Grosbach		return;
12378ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	iter = *iter_p;
12388ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
12398ae45af7941dc3e78859ba3624676081590c435dJim Grosbach		return;
12408ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	free(iter);
12418ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	*iter_p = 0;
12428ae45af7941dc3e78859ba3624676081590c435dJim Grosbach}
12438ae45af7941dc3e78859ba3624676081590c435dJim Grosbach
12448ae45af7941dc3e78859ba3624676081590c435dJim Grosbach/*
12458ae45af7941dc3e78859ba3624676081590c435dJim Grosbach * Note: the returned character strings in ret_name and ret_value
12468ae45af7941dc3e78859ba3624676081590c435dJim Grosbach * points to the stored character string in the parse string.  Before
12478ae45af7941dc3e78859ba3624676081590c435dJim Grosbach * this string value is returned to a calling application
12488ae45af7941dc3e78859ba3624676081590c435dJim Grosbach * (profile_node_iterator is not an exported interface), it should be
12498ae45af7941dc3e78859ba3624676081590c435dJim Grosbach * strdup()'ed.
12508ae45af7941dc3e78859ba3624676081590c435dJim Grosbach */
12518ae45af7941dc3e78859ba3624676081590c435dJim Grosbacherrcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node,
12528ae45af7941dc3e78859ba3624676081590c435dJim Grosbach				char **ret_name, char **ret_value)
12538ae45af7941dc3e78859ba3624676081590c435dJim Grosbach{
12548ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	struct profile_iterator 	*iter = *iter_p;
12558ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	struct profile_node 		*section, *p;
12568ae45af7941dc3e78859ba3624676081590c435dJim Grosbach	const char			*const *cpp;
125786fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	errcode_t			retval;
125886fdff0fa79b2c00cb68a2961cca0466eb50d666Jim Grosbach	int				skip_num = 0;
12598409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach
12608409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
12618409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		return PROF_MAGIC_ITERATOR;
12628409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	if (iter->file && iter->file->magic != PROF_MAGIC_FILE)
12638409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	    return PROF_MAGIC_FILE;
12648409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	/*
12658409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	 * If the file has changed, then the node pointer is invalid,
12668409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	 * so we'll have search the file again looking for it.
12678409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	 */
12688409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	if (iter->node && (iter->file &&
12698409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			   iter->file->upd_serial != iter->file_serial)) {
12708409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		iter->flags &= ~PROFILE_ITER_FINAL_SEEN;
12718409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		skip_num = iter->num;
12728409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		iter->node = 0;
12738409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	}
12748409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	if (iter->node && iter->node->magic != PROF_MAGIC_NODE) {
12758409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	    return PROF_MAGIC_NODE;
12768409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	}
12778409f047312da0318af2a2fce162810ca3a95da3Jim Grosbachget_new_file:
12788409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach	if (iter->node == 0) {
12798409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		if (iter->file == 0 ||
12808409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		    (iter->flags & PROFILE_ITER_FINAL_SEEN)) {
12818409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			profile_iterator_free(iter_p);
12828409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			if (ret_node)
12838409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach				*ret_node = 0;
12848409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			if (ret_name)
12858409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach				*ret_name = 0;
12868409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			if (ret_value)
12878409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach				*ret_value =0;
12888409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			return 0;
12898409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		}
12908409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		if ((retval = profile_update_file(iter->file))) {
12918409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		    if (retval == ENOENT || retval == EACCES) {
12928409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			/* XXX memory leak? */
12938409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			iter->file = iter->file->next;
12948409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			skip_num = 0;
12958409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			retval = 0;
12968409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			goto get_new_file;
12978409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		    } else {
12988409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			profile_iterator_free(iter_p);
12998409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			return retval;
13008409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		    }
13018409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		}
13028409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		iter->file_serial = iter->file->upd_serial;
13038409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		/*
13048409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		 * Find the section to list if we are a LIST_SECTION,
13058409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		 * or find the containing section if not.
13068409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		 */
13078409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		section = iter->file->root;
13088409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach		for (cpp = iter->names; cpp[iter->done_idx]; cpp++) {
13098409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach			for (p=section->first_child; p; p = p->next) {
13108409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach				if (!strcmp(p->name, *cpp) && !p->value)
13118409f047312da0318af2a2fce162810ca3a95da3Jim Grosbach					break;
1312fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach			}
1313fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach			if (!p) {
1314fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach				section = 0;
1315fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach				break;
1316fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach			}
1317fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach			section = p;
1318fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach			if (p->final)
1319fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach				iter->flags |= PROFILE_ITER_FINAL_SEEN;
1320fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach		}
1321fb8989e64024547e4ad5ab6fe4d94fe146a7899fJim Grosbach		if (!section) {
13229076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach			iter->file = iter->file->next;
13239076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach			skip_num = 0;
13249076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach			goto get_new_file;
13259076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach		}
13269076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach		iter->name = *cpp;
13279076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach		iter->node = section->first_child;
13289076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach	}
13299076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach	/*
13309076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach	 * OK, now we know iter->node is set up correctly.  Let's do
13319076b6e8f43c7eade7e0b667081f94df097e85c3Jim Grosbach	 * the search.
1332c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach	 */
1333c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach	for (p = iter->node; p; p = p->next) {
1334c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach		if (iter->name && strcmp(p->name, iter->name))
1335c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach			continue;
1336c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach		if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) &&
1337fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach		    p->value)
1338fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach			continue;
1339c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach		if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) &&
1340c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach		    !p->value)
1341c27d4f9ea0cb9064d3e2cadb384d73e95e9de449Jim Grosbach			continue;
1342248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		if (skip_num > 0) {
1343248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach			skip_num--;
1344248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach			continue;
1345248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		}
1346248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		if (p->deleted)
1347248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach			continue;
1348248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		break;
1349248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	}
1350248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	iter->num++;
1351248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	if (!p) {
1352248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		iter->file = iter->file->next;
1353248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		iter->node = 0;
1354248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		skip_num = 0;
1355248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		goto get_new_file;
1356248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	}
1357248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	if ((iter->node = p->next) == NULL)
1358248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		iter->file = iter->file->next;
1359248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	if (ret_node)
1360248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		*ret_node = p;
1361248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	if (ret_name)
1362248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		*ret_name = p->name;
1363248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	if (ret_value)
1364248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		*ret_value = p->value;
1365248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	return 0;
1366248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach}
1367248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach
1368248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach
1369248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach/*
1370248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach * prof_get.c --- routines that expose the public interfaces for
1371248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach * 	querying items from the profile.
1372248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach *
1373248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach */
1374248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach
1375248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach/*
1376248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach * This function only gets the first value from the file; it is a
1377248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach * helper function for profile_get_string, profile_get_integer, etc.
1378248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach */
1379248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbacherrcode_t profile_get_value(profile_t profile, const char *name,
1380248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach			    const char *subname, const char *subsubname,
1381248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach			    const char **ret_value)
1382248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach{
1383248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	errcode_t		retval;
1384248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	void			*state;
1385248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	char			*value;
1386248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach	const char		*names[4];
13877c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach
13887c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach	names[0] = name;
13897c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach	names[1] = subname;
13907c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach	names[2] = subsubname;
13917c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach	names[3] = 0;
13927c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach
13937c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach	if ((retval = profile_iterator_create(profile, names,
13947c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach					      PROFILE_ITER_RELATIONS_ONLY,
13957c9fbc0340aff9e20fd9009be23ffd279c1c0a7dJim Grosbach					      &state)))
13960ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach		return retval;
13970ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach
13980ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach	if ((retval = profile_node_iterator(&state, 0, 0, &value)))
13990ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach		goto cleanup;
14000ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach
14010ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach	if (value)
14020ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach		*ret_value = value;
14030ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach	else
14040ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach		retval = PROF_NO_RELATION;
14050ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach
14060ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbachcleanup:
14070ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach	profile_iterator_free(&state);
14080ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach	return retval;
14090ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach}
14100ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach
14110ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbacherrcode_t
14120ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbachprofile_get_string(profile_t profile, const char *name, const char *subname,
14130ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach		   const char *subsubname, const char *def_val,
14140ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach		   char **ret_string)
14150ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach{
14160ffd4a09dfb1ee56ec335fed0d15954f92cfa5b3Jim Grosbach	const char	*value;
1417b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach	errcode_t	retval;
1418b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach
1419b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach	if (profile) {
1420b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach		retval = profile_get_value(profile, name, subname,
1421b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach					   subsubname, &value);
1422b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach		if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION)
1423b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach			value = def_val;
1424b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach		else if (retval)
1425b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach			return retval;
1426b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach	} else
1427b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach		value = def_val;
1428b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach
1429b206daaec1a2ec25e99fbdc413cd0866cec160b2Jim Grosbach	if (value) {
1430248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		*ret_string = malloc(strlen(value)+1);
1431248e6c328c06afc2a6af6b95a1a8a41c1b53055cJim Grosbach		if (*ret_string == 0)
1432ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach			return ENOMEM;
1433b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach		strcpy(*ret_string, value);
1434b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach	} else
1435b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach		*ret_string = 0;
1436b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach	return 0;
1437b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach}
1438b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach
1439b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbacherrcode_t
1440b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbachprofile_get_integer(profile_t profile, const char *name, const char *subname,
1441b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach		    const char *subsubname, int def_val, int *ret_int)
1442b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach{
1443b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach	const char	*value;
1444b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach	errcode_t	retval;
1445b544f68b70475f06a8ec39c874297549edc0f695Jim Grosbach	char            *end_value;
1446ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	long		ret_long;
1447ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach
1448ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	*ret_int = def_val;
1449ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	if (profile == 0)
1450ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach		return 0;
1451ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach
1452ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	retval = profile_get_value(profile, name, subname, subsubname, &value);
1453ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
1454ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach		*ret_int = def_val;
1455ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach		return 0;
1456ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	} else if (retval)
1457ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach		return retval;
1458ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach
1459ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	if (value[0] == 0)
1460ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	    /* Empty string is no good.  */
1461ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	    return PROF_BAD_INTEGER;
1462ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	errno = 0;
1463ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	ret_long = strtol (value, &end_value, 10);
1464ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach
1465ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	/* Overflow or underflow.  */
1466ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0)
1467ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	    return PROF_BAD_INTEGER;
1468ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	/* Value outside "int" range.  */
1469ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	if ((long) (int) ret_long != ret_long)
1470ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	    return PROF_BAD_INTEGER;
1471ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	/* Garbage in string.  */
1472ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	if (end_value != value + strlen (value))
1473ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	    return PROF_BAD_INTEGER;
1474ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach
1475ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach
1476ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	*ret_int = ret_long;
1477ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach	return 0;
1478ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach}
1479ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbach
1480ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbacherrcode_t
1481ce501030d9b0213d951fbf05f928ac75b06b5a3aJim Grosbachprofile_get_uint(profile_t profile, const char *name, const char *subname,
148244a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach		 const char *subsubname, unsigned int def_val,
148344a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach		 unsigned int *ret_int)
148444a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach{
148544a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	const char	*value;
148644a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	errcode_t	retval;
148744a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	char            *end_value;
148844a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	unsigned long	ret_long;
148944a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach
149044a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	*ret_int = def_val;
149144a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	if (profile == 0)
149244a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach		return 0;
149344a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach
149444a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	retval = profile_get_value(profile, name, subname, subsubname, &value);
149544a456332f1f41d1e0b2815d93e47a88d501ee6eJim Grosbach	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
14966808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		*ret_int = def_val;
14976808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		return 0;
14986808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	} else if (retval)
14996808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		return retval;
15006808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15016808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	if (value[0] == 0)
15026808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	    /* Empty string is no good.  */
15036808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	    return PROF_BAD_INTEGER;
15046808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	errno = 0;
15056808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	ret_long = strtoul (value, &end_value, 10);
15066808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15076808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	/* Overflow or underflow.  */
15086808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	if ((ret_long == ULONG_MAX) && errno != 0)
15096808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	    return PROF_BAD_INTEGER;
15106808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	/* Value outside "int" range.  */
15116808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	if ((unsigned long) (unsigned int) ret_long != ret_long)
15126808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	    return PROF_BAD_INTEGER;
15136808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	/* Garbage in string.  */
15146808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	if (end_value != value + strlen (value))
15156808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	    return PROF_BAD_INTEGER;
15166808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15176808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	*ret_int = ret_long;
15186808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	return 0;
15196808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach}
15206808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15216808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbachstatic const char *const conf_yes[] = {
15226808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    "y", "yes", "true", "t", "1", "on",
15236808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    0,
15246808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach};
15256808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15266808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbachstatic const char *const conf_no[] = {
15276808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    "n", "no", "false", "nil", "0", "off",
15286808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    0,
15296808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach};
15306808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15316808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbachstatic errcode_t
15326808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbachprofile_parse_boolean(const char *s, int *ret_boolean)
15336808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach{
15346808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    const char *const *p;
15356808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15366808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    if (ret_boolean == NULL)
15376808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    	return PROF_EINVAL;
15386808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15396808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    for(p=conf_yes; *p; p++) {
15406808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		if (!strcasecmp(*p,s)) {
15416808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach			*ret_boolean = 1;
15426808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	    	return 0;
15436808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		}
15446808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    }
15456808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15466808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    for(p=conf_no; *p; p++) {
15476808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		if (!strcasecmp(*p,s)) {
15486808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach			*ret_boolean = 0;
15496808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach			return 0;
15506808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		}
15516808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach    }
15526808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15536808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	return PROF_BAD_BOOLEAN;
15546808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach}
15556808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15566808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbacherrcode_t
15576808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbachprofile_get_boolean(profile_t profile, const char *name, const char *subname,
15586808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		    const char *subsubname, int def_val, int *ret_boolean)
15596808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach{
15606808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	const char	*value;
15616808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	errcode_t	retval;
15626808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15636808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	if (profile == 0) {
15646808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		*ret_boolean = def_val;
15656808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		return 0;
15666808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	}
15676808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15686808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	retval = profile_get_value(profile, name, subname, subsubname, &value);
15696808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
15706808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		*ret_boolean = def_val;
15716808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		return 0;
15726808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	} else if (retval)
15736808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach		return retval;
15746808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
15756808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	return profile_parse_boolean (value, ret_boolean);
15766808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach}
15776808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach
1578bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbacherrcode_t
1579bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbachprofile_iterator(void **iter_p, char **ret_name, char **ret_value)
1580bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach{
1581bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach	char *name, *value;
1582bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach	errcode_t	retval;
1583bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach
1584bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach	retval = profile_node_iterator(iter_p, 0, &name, &value);
1585bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach	if (retval)
1586bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach		return retval;
1587bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach
1588bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach	if (ret_name) {
1589bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach		if (name) {
1590bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach			*ret_name = malloc(strlen(name)+1);
1591bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach			if (!*ret_name)
1592bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach				return ENOMEM;
1593bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach			strcpy(*ret_name, name);
1594bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach		} else
1595bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach			*ret_name = 0;
1596bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach	}
1597bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach	if (ret_value) {
1598bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach		if (value) {
1599bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach			*ret_value = malloc(strlen(value)+1);
16000e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach			if (!*ret_value) {
1601bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach				if (ret_name) {
1602bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach					free(*ret_name);
1603bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach					*ret_name = 0;
1604bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach				}
1605bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach				return ENOMEM;
1606bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach			}
1607bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach			strcpy(*ret_value, value);
1608bf2845c0d8a77d24e9971871badeba8cee7b2648Jim Grosbach		} else
16090e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach			*ret_value = 0;
16100e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	}
16110e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	return 0;
16120e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach}
16130e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach
16140e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach#ifdef DEBUG_PROGRAM
16150e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach
16160e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach/*
16170e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach * test_profile.c --- testing program for the profile routine
16180e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach */
16190e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach
16200e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach#include "argv_parse.h"
16210e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach#include "profile_helpers.h"
16220e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach
16230e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbachconst char *program_name = "test_profile";
16240e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach
16250e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach#define PRINT_VALUE	1
16260e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach#define PRINT_VALUES	2
16270e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach
16280e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbachstatic void do_cmd(profile_t profile, char **argv)
16290e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach{
16300e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	errcode_t	retval;
16310e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	const char	**names, *value;
16320e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	char		**values, **cpp;
16330e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	char	*cmd;
16340e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	int		print_status;
16350e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach
16360e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	cmd = *(argv);
16370e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	names = (const char **) argv + 1;
16380e76edf8c05c5107acb687b898fea686ae756c38Jim Grosbach	print_status = 0;
16396808f21757f4f2be05a3b12a67d9360b4f9f62e2Jim Grosbach	retval = 0;
16406ab4e3dd2375c3dcee06dde37437dc0c5a99aa24Jim Grosbach	if (cmd == 0)
16416ab4e3dd2375c3dcee06dde37437dc0c5a99aa24Jim Grosbach		return;
1642580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach	if (!strcmp(cmd, "query")) {
1643580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach		retval = profile_get_values(profile, names, &values);
1644580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach		print_status = PRINT_VALUES;
1645580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach	} else if (!strcmp(cmd, "query1")) {
1646580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach		const char *name = 0;
1647fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach		const char *subname = 0;
1648fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach		const char *subsubname = 0;
1649fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach
1650fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach		name = names[0];
1651fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach		if (name)
1652580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach			subname = names[1];
1653580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach		if (subname)
1654580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach			subsubname = names[2];
1655580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach		if (subsubname && names[3]) {
1656580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach			fprintf(stderr,
1657580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach				"Only 3 levels are allowed with query1\n");
1658580f4a9c1c2fcbb8877463f873c6e9ca2a5ccf9fJim Grosbach			retval = EINVAL;
1659f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach		} else
1660f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach			retval = profile_get_value(profile, name, subname,
1661f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach						   subsubname, &value);
1662f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach		print_status = PRINT_VALUE;
1663fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach	} else if (!strcmp(cmd, "list_sections")) {
1664fc2eb31a3c054f9611a2e88238fbb5a8842064a6Jim Grosbach		retval = profile_get_subsection_names(profile, names,
1665f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach						      &values);
1666f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach		print_status = PRINT_VALUES;
1667f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach	} else if (!strcmp(cmd, "list_relations")) {
1668f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach		retval = profile_get_relation_names(profile, names,
1669f49433523e8a39db6d83503e312ae55160eed90aJim Grosbach						    &values);
16706ab4e3dd2375c3dcee06dde37437dc0c5a99aa24Jim Grosbach		print_status = PRINT_VALUES;
1671185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach	} else if (!strcmp(cmd, "dump")) {
1672185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		retval = profile_write_tree_file
1673185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach			(profile->first_file->root, stdout);
1674185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach#if 0
1675185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach	} else if (!strcmp(cmd, "clear")) {
1676185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		retval = profile_clear_relation(profile, names);
1677185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach	} else if (!strcmp(cmd, "update")) {
1678185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		retval = profile_update_relation(profile, names+2,
1679185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach						 *names, *(names+1));
1680185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach#endif
1681185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach	} else if (!strcmp(cmd, "verify")) {
1682185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		retval = profile_verify_node
1683185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach			(profile->first_file->root);
1684185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach#if 0
1685185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach	} else if (!strcmp(cmd, "rename_section")) {
1686185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		retval = profile_rename_section(profile, names+1, *names);
1687185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach	} else if (!strcmp(cmd, "add")) {
1688185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		value = *names;
1689185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		if (strcmp(value, "NULL") == 0)
1690185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach			value = NULL;
1691185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		retval = profile_add_relation(profile, names+1, value);
1692185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach	} else if (!strcmp(cmd, "flush")) {
1693185f92e7d019bc52413a2b082d61e35c80f8b597Jim Grosbach		retval = profile_flush(profile);
16943b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach#endif
16953b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	} else {
16963b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach		printf("Invalid command.\n");
1697a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	}
1698a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	if (retval) {
1699a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach		com_err(cmd, retval, "");
1700a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach		print_status = 0;
1701a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	}
17023b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	switch (print_status) {
17033b14a5c5469176effb921d91d4494f0aa2919fd0Jim Grosbach	case PRINT_VALUE:
1704a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach		printf("%s\n", value);
1705a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach		break;
1706a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	case PRINT_VALUES:
1707a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach		for (cpp = values; *cpp; cpp++)
1708a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach			printf("%s\n", *cpp);
1709a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach		profile_free_list(values);
1710a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach		break;
1711a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	}
1712a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach}
1713a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach
1714a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbachstatic void do_batchmode(profile_t profile)
1715a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach{
1716a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	int		argc, ret;
1717a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	char		**argv;
1718a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach	char		buf[256];
1719a46c658c6619e979a54ec1e4dc919b3a0319129aJim Grosbach
1720873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	while (!feof(stdin)) {
1721873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach		if (fgets(buf, sizeof(buf), stdin) == NULL)
1722873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach			break;
1723873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach		printf(">%s", buf);
1724873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach		ret = argv_parse(buf, &argc, &argv);
172536711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		if (ret != 0) {
172636711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach			printf("Argv_parse returned %d!\n", ret);
172736711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach			continue;
172836711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		}
172936711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		do_cmd(profile, argv);
173036711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		printf("\n");
173136711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach		argv_free(argv);
173236711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	}
173336711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	profile_release(profile);
173436711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach	exit(0);
173536711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach
173636711e4a3c0b53000ea594233bd619dbf252558cJim Grosbach}
1737873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1738873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbachvoid syntax_err_report(const char *filename, long err, int line_num)
1739873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach{
1740873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	fprintf(stderr, "Syntax error in %s, line number %d: %s\n",
1741873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach		filename, line_num, error_message(err));
1742873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	exit(1);
1743873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach}
1744873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1745873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbachint main(int argc, char **argv)
1746873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach{
1747873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    profile_t	profile;
1748873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    long	retval;
1749873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    char	*cmd;
1750873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1751873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    if (argc < 2) {
1752873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	    fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name);
1753873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	    exit(1);
1754873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    }
1755873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1756873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    initialize_prof_error_table();
1757873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1758873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    profile_set_syntax_err_cb(syntax_err_report);
1759873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1760873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    retval = profile_init_path(argv[1], &profile);
1761873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    if (retval) {
1762873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	com_err(program_name, retval, "while initializing profile");
1763873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	exit(1);
1764873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    }
1765873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    cmd = *(argv+2);
1766873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    if (!cmd || !strcmp(cmd, "batch"))
1767873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	    do_batchmode(profile);
1768873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    else
1769873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach	    do_cmd(profile, argv+2);
1770873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    profile_release(profile);
1771873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1772873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach    return 0;
1773873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach}
1774873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach
1775873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach#endif
1776873db3eebae3cf1e0931149896f262d17a4dc79dJim Grosbach