Initial version imported to CVS
[sfrench/samba-autobuild/.git] / source3 / param / params.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Parameter loading utlities
5    Copyright (C) Karl Auer 1993,1994
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /**************************************************************************
23 PARAMS.C
24
25 Copyright (C) 1990, 1991, 1992, 1993, 1994 Karl Auer
26
27 This module provides for streamlines retrieval of information from a
28 Windows-like parameter files. There is a function which will search for
29 all sections in the file and call a specified function with each. There is
30 a similar function which will call a specified function for all parameters 
31 in a section. The idea is that you pass the addresses of suitable functions
32 to a single function in this module which will then enumerate all sections, 
33 and within each section all parameters, to your program. 
34
35 Parameter files contain text lines (newline delimited) which consist of
36 either a section name in square brackets or a parameter name, delimited
37 from the parameter value by an equals sign. Blank lines or lines where the
38 first non-whitespace character is a colon are ignored. All whitespace in
39 section names and parameter names is compressed to single spaces. Leading 
40 and trailing whitespace on parameter names and parameter values is stripped.
41
42 Only the first equals sign in a parameter line is significant - parameter
43 values may contain equals signs, square brackets and semicolons. Internal
44 whitespace is retained in parameter values. Parameter names may not start 
45 with a square bracket, an equals sign or a semicolon, for obvious reasons. 
46
47 A sample parameter file might look like this:
48
49 [things]
50 this=1
51 that=2
52 [other things]
53 the other = 3
54
55 **************************************************************************/
56
57 #include "includes.h"
58
59 #include "smb.h"
60 #include "params.h"
61
62 /* local variable pointing to passed filename */
63 static char *pszParmFile = NULL;
64 extern int DEBUGLEVEL;
65
66 /* local prototypes */
67 static BOOL enumerate_parameters(FILE *infile, PM_PARMFUNC pfunc);
68 static BOOL enumerate_sections(FILE *infile, 
69                                PM_SECFUNC sfunc, PM_PARMFUNC pfunc);
70
71 /* prototypes for local toolbox functions */
72 static void trimleft(char *psz);
73 static void trimright(char *psz);
74 static void collapse_spaces(char *psz);
75 static int  firstnonwhite(char *psz);
76
77 /**************************************************************************
78 Identifies all parameters in the current section, calls the parameter
79 function for each. Ignores comment lines, stops and backs up in file when
80 a section is encountered. Returns True on success, False on error.
81 **************************************************************************/
82 static BOOL enumerate_parameters(FILE *fileIn, PM_PARMFUNC pfunc)
83 {
84    pstring szBuf;
85    char *pszTemp;
86    BOOL bRetval;
87    long lFileOffset;
88    int  cTemp;
89    BOOL bParmFound;
90
91    bRetval = False;
92    bParmFound = False;
93    while (True)
94    {
95       /* first remember where we are */
96       if ((lFileOffset = ftell(fileIn)) >= 0L)
97       {
98          /* then get and check a line */
99          if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
100          {
101             /* stop - return OK unless file error */
102             bRetval = !ferror(fileIn);
103             if (!bRetval)
104               DEBUG(0,( "Read error on configuration file (enumerating parameters)!\n"));
105             break;   
106          }
107          else
108             /* if first non-white is a '[', stop (new section) */
109             if ((cTemp = firstnonwhite(szBuf)) == '[')
110             {
111                /* restore position to start of new section */
112                if (fseek(fileIn, lFileOffset, SEEK_SET) < 0L)
113                {
114                   DEBUG(0,( "Seek error on configuration file!\n"));
115                   break;
116                }
117
118                /* return success */
119                bRetval = True;
120                break;
121             }
122             else
123                /* if it's a semicolon or line is blank, ignore the line */
124                if (!cTemp || strchr(";#",cTemp))
125                {
126                   continue;
127                }
128                else
129                   /* if no equals sign and line contains non-whitespace */
130                   /* then line is badly formed */
131                   if ((pszTemp = strchr(szBuf, '=')) == NULL)
132                   {
133                      DEBUG(0,( "Ignoring badly formed line: %s", szBuf));
134                   }
135                   else
136                   {
137                      /* Note that we have found a parameter */
138                      bParmFound = True;
139                      /* cut line at the equals sign */
140                      *pszTemp++ = '\0';
141                      /* trim leading and trailing space from both halves */
142                      trimright(szBuf);
143                      trimleft(szBuf);
144                      trimright(pszTemp);
145                      trimleft(pszTemp);
146                      /* process the parameter iff passed pointer not NULL */
147                      if (pfunc != NULL)
148                         if (!pfunc(szBuf, pszTemp))
149                            break;
150                   }
151       }
152    }
153    return (bRetval);
154 }
155
156
157 /***********************************************************************
158 Close up s by n chars, at offset start.
159 ***********************************************************************/
160 static void closestr(char *s, int start, int n)
161 {
162    char *src;
163    char *dest;
164    int  len;
165
166    if (n > 0)
167       if ((src = dest = s) != NULL)
168       {
169          len = strlen(s);
170          if (start >= 0 && start < len - n)
171          {
172             src += start + n;
173             dest += start;
174   
175             while (*src)
176                *dest++ = *src++;
177             *dest = '\0';
178          }
179       }
180 }
181
182 /**************************************************************************
183 Identifies all sections in the parameter file, calls passed section_func()
184 for each, passing the section name, then calls enumerate_parameters(). 
185 Returns True on success, False on failure. Note that the section and 
186 parameter names will have all internal whitespace areas collapsed to a 
187 single space for processing.
188 **************************************************************************/
189 static BOOL enumerate_sections(FILE *fileIn, 
190                                PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
191 {
192    pstring szBuf;
193    BOOL bRetval;
194    BOOL bSectionFound;
195
196    /* this makes sure we get include lines right */
197    enumerate_parameters(fileIn, pfunc);
198
199    bRetval = False;
200    bSectionFound = False;
201    while (True)
202    {
203       if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
204       {
205          /* stop - return OK unless file error */
206          bRetval = !ferror(fileIn);
207          if (!bRetval)
208            DEBUG(0,( "Read error on configuration file (enumerating sections)!\n"));
209          break;   
210       }
211       else
212       {
213          trimleft(szBuf);
214          trimright(szBuf);
215          if (szBuf[0] == '[')
216          {
217             closestr(szBuf, 0, 1);
218             if (strlen(szBuf) > 1)
219                if (szBuf[strlen(szBuf) - 1] == ']')
220                {  
221                   /* found a section - note the fact */
222                   bSectionFound = True;
223                   /* remove trailing metabracket */
224                   szBuf[strlen(szBuf) - 1] = '\0';
225                   /* remove leading and trailing whitespace from name */
226                   trimleft(szBuf);
227                   trimright(szBuf);
228                   /* reduce all internal whitespace to one space */
229                   collapse_spaces(szBuf);
230                   /* process it - stop if the processing fails */
231                   if (sfunc != NULL)
232                      if (!sfunc(szBuf))
233                         break;
234                   if (!enumerate_parameters(fileIn, pfunc))
235                      break;
236                }
237          }
238       }
239    }
240
241    return (bRetval);
242 }
243
244 /**************************************************************************
245 Process the passed parameter file.
246
247 Returns True if successful, else False.
248 **************************************************************************/
249 BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
250 {
251    FILE *fileIn;
252    BOOL bRetval;
253
254    bRetval = False;
255
256    /* record the filename for use in error messages one day... */
257    pszParmFile = pszFileName;
258
259    if (pszParmFile == NULL || strlen(pszParmFile) < 1)
260       DEBUG(0,( "No configuration filename specified!\n"));
261    else
262       if ((fileIn = fopen(pszParmFile, "r")) == NULL)
263          DEBUG(0,( "Unable to open configuration file \"%s\"!\n", pszParmFile));
264       else
265       {
266          DEBUG(2,( "Processing configuration file \"%s\"\n", pszParmFile));
267          bRetval = enumerate_sections(fileIn, sfunc, pfunc);
268          fclose(fileIn);
269       }
270
271    if (!bRetval)
272      DEBUG(0,("pm_process retuned false\n"));
273    return (bRetval);
274 }
275
276
277 /**************************************************************************
278 Strip all leading whitespace from a string.
279 **************************************************************************/
280 static void trimleft(char *psz)
281 {
282    char *pszDest;
283
284    pszDest = psz;
285    if (psz != NULL)
286    {
287       while (*psz != '\0' && isspace(*psz))
288          psz++;
289       while (*psz != '\0')
290          *pszDest++ = *psz++;
291       *pszDest = '\0';
292    }
293 }
294
295 /**************************************************************************
296 Strip all trailing whitespace from a string.
297 **************************************************************************/
298 static void trimright(char *psz)
299 {
300    char *pszTemp;
301
302    if (psz != NULL && psz[0] != '\0')
303    {
304       pszTemp = psz + strlen(psz) - 1;
305       while (isspace(*pszTemp))
306          *pszTemp-- = '\0';
307    }
308 }
309
310 /***********************************************************************
311 Collapse each whitespace area in a string to a single space.
312 ***********************************************************************/
313 static void collapse_spaces(char *psz)
314 {
315    while (*psz)
316       if (isspace(*psz))
317       {
318          *psz++ = ' ';
319          trimleft(psz);
320       }
321       else
322          psz++;
323 }
324
325 /**************************************************************************
326 Return the value of the first non-white character in the specified string.
327 The terminating NUL counts as non-white for the purposes of this function.
328 Note - no check for a NULL string! What would we return?
329 **************************************************************************/
330 static int firstnonwhite(char *psz)
331 {
332    while (isspace(*psz) && (*psz != '\0'))
333       psz++;
334    return (*psz);
335 }