1 
2 #ifndef JCONF_H
3 #define JCONF_H
4 
5 /*
6  * JSON based configuration format class.
7  */
8 
9 /*************************************************************************
10  Copyright 2008 Graeme W. Gill
11 
12  Permission is hereby granted, free of charge, to any person obtaining a copy
13  of this software and associated documentation files (the "Software"), to deal
14  in the Software without restriction, including without limitation the rights
15  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  copies of the Software, and to permit persons to whom the Software is
17  furnished to do so, subject to the following conditions:
18 
19  The above copyright notice and this permission notice shall be included in
20  all copies or substantial portions of the Software.
21 
22  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28  THE SOFTWARE.
29 
30  *************************************************************************/
31 
32 
33 /* General description:
34 
35 	Key names are UNIX style '/' separated paths, stored
36 	in UTF8 format. The paths should not start with a '/'.
37 
38 	Duplicate key names are supported, but typically
39 	will be avoided by the library user.
40 
41 	Five types are supported, NULL, 32 bit boolean, 64 bit real,
42 	64 bit integer and string. Strings are always nul terminated.
43 
44  */
45 
46 /* jcnf error codes */
47 typedef enum {
48 	jc_ok		    = 0,		/* No error */
49 	jc_malloc,					/* malloc, calloc or realloc failed */
50 	jc_lock_error,				/* Error opening lock file */
51 	jc_locked,					/* File is locked by someone else */
52 	jc_unlock,					/* Unlock failed */
53 	jc_noexisting,				/* No existing file to read */
54 	jc_stat,					/* Unable to stat file */
55 	jc_changed,					/* File has changed since it was read */
56 	jc_read_fail,				/* Failure to read from the file */
57 	jc_parse_fail,				/* Failure to parse from the file */
58 	jc_write_open,				/* Failed to open file for writing */
59 	jc_write_fail,				/* Failed to write to file */
60 	jc_write_close,				/* Failed to close file after writing */
61 	jc_update_nomod,			/* Attempt to update file that wasn't opened for modifications */
62 	jc_bad_addkey_params,		/* Bad add_key() parameters */
63 	jc_unknown_key_type,		/* An unrecognisd key type was encountered */
64 	jc_ix_oorange,				/* Key index is out of range */
65 	jc_no_keyname,				/* No key name provided when it is expected */
66 	jc_string_not_terminated	/* String doesn't include nul */
67 } jc_error;
68 
69 /* Argument types */
70 typedef enum {
71 	jc_read		= 0,		/* Just read the config file */
72 	jc_modify	= 1			/* Read the config file in preparation to write it */
73 } jc_mod;
74 
75 typedef enum {
76 	jc_no_create	= 0,	/* Don't create the config if it doesn't exist */
77 	jc_create		= 1		/* Create the config if it doesn't exist */
78 } jc_crte;
79 
80 /* Internal jcnf structure */
81 
82 /* The different type of values supported */
83 typedef enum {
84 	jc_null		= 0,		/* Null value */
85 	jc_boolean	= 1,		/* Boolean */
86 	jc_real     = 2,		/* double floating point */
87 	jc_integer	= 3,		/* 64 bit integer */
88 	jc_string	= 4			/* UTF8 string, nul terminated */
89 } jc_type;
90 
91 /* A value */
92 struct _jc_key {
93 	char *key;						/* Key path */
94 	jc_type type;					/* Type of value */
95 	char *c_comment;				/* C Comment */
96 	char *cpp_comment;				/* C++ Comment */
97 	unsigned char *data;			/* Pointer to data */
98 	size_t dataSize;				/* Size of data */
99 }; typedef struct _jc_key jc_key;
100 
101 /* A recursion depth record used during parsing */
102 struct _jc_recd {
103 	char *key;						/* Key name, or */
104 	int aix;						/* Array index, -2 = no array */
105 }; typedef struct _jc_recd jc_recd;
106 
107 /* jcnf Object, representing the keys in a jcnf file */
108 struct _jcnf {
109 	jc_key **keys;		/* Array of pointers to keys */
110 	int nkeys;			/* Number of valid key pointers */
111 	int akeys;			/* Number of allocated key poiters */
112 	jc_key *lk;			/* Last key created */
113 
114 	/* Parsing support, key recursion depth */
115 	jc_recd *recds;
116 	int nrecd;			/* Number of ised recd */
117 	int arecd;			/* Allocate rec depth */
118 
119 	/* Config & status */
120 	char *fname;		/* filename */
121 	FILE *fp;			/* opened, locked file */
122 	off_t rsize;		/* Size of file when read */
123 	time_t rtime;		/* Time the file was read */
124 	int modify;			/* Opened for modifications */
125 	int create;			/* Create if it doesn't exist */
126 	int locked;			/* nz if file is locked */
127 	int modified;		/* nz if keys have been modified */
128 
129 	/* Locate the index of the next key matching the key name, starting */
130 	/* at the given index. Update the index to the matching key. */
131 	/* Look for an exact match if exact != 0, or leading match if exact = 0 */
132 	/* Search backwards if bwd != 0 or forwards if bwd = 0 */
133 	/* Set *ix = -1 to begin search from the end. */
134 	/* Return jc_ix_oorange if no more matchs. */
135 	jc_error (*locate_key)(struct _jcnf *p, int *ix, char *key, int exact, int bwd);
136 
137 	/* Retrieve a keys information. Return pointers may be NULL. */
138 	/* If ix >= 0, return the key of the given index. */
139 	/* jc_ix_oorange is returned when past end. */
140 	/* If ix == -1, return the first from the beginning matching key name. */
141 	/* (Returned data is internal to jcnf object, so call must copy it). */
142 	jc_error (*get_key)(struct _jcnf *p, int ix, char **key, jc_type *type, unsigned char **data,
143                    size_t *dataSize, char **comment);
144 
145 	/* Set a keys information. */
146 	/* If ix >= 0, set the key of the given index. */
147 	/* jc_ix_oorange is returned when past end. */
148 	/* If ix == -1, overwrite an existing key with the same name, */
149 	/* or add a new key with that name at the end if there is no existing key. */
150 	jc_error (*set_key)(struct _jcnf *p, int ix, char *key, jc_type type, unsigned char *data,
151                    size_t dataSize, char *comment);
152 
153 	/* Add a key value to the jcnf at the end, irrespective of whether there is */
154 	/* an existing key with that name. */
155 	jc_error (*add_key)(struct _jcnf *p, char *key, jc_type type, unsigned char *data,
156 	               size_t dataSize, char *comment);
157 
158 	/* Delete a key. */
159 	/* If ix >= 0, delete the key of the given index. */
160 	/* jc_ix_oorange is returned when past end. */
161 	/* If ix == -1, delete the key with the given name. */
162 	jc_error (*delete_key)(struct _jcnf *p, int ix, char *key);
163 
164 	/* Diagnostic - Print the value of a key */
165 	jc_error (*print_key)(struct _jcnf *p, int ix, FILE *fp);
166 
167 	/* Switch from read only to update of the config file. */
168 	/* (This re-opens the file and checks that it hasn't been */
169 	/*  modified since it was read) */
170 	jc_error (*enable_modify)(struct _jcnf *p);
171 
172 	/* Save and changes out to the file, unlock it and and close it. */
173 	/* It can't be udated again after this. */
174 	jc_error (*update)(struct _jcnf *p);
175 
176 	/* Delete this object */
177 	void (*del)(struct _jcnf *p);
178 
179 }; typedef struct _jcnf jcnf;
180 
181 /* Create a new jcnf and read it's keys from the file. */
182 /* Return NULL on error */
183 jcnf *new_jcnf(
184 	jc_error *pev,		/* return error code on error */
185 	char *fname,		/* Corresponding filename */
186 	jc_mod modify,		/* Flag, nz to open for modification */
187 	jc_crte create		/* Flag, nz to create if it doesn't exist (modify must be set) */
188 );
189 
190 /* Utilities */
191 
192 /* Return a pointer to the nth element of the key name. */
193 /* Return null if it is out of range or malloc failed. */
194 /* Free the returned value when done. */
195 char *jc_get_nth_elem(char *path, int n);
196 
197 #endif /* JCNF_H */
198 
199 
200