8ff3d59d280c54665d115bf272a388a72bb7cbae
[kai/samba.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
61 /* local variable pointing to passed filename */
62 static char *pszParmFile = NULL;
63 extern int DEBUGLEVEL;
64
65
66 /**************************************************************************
67 Strip all leading whitespace from a string.
68 **************************************************************************/
69 static void trimleft(char *psz)
70 {
71    char *pszDest;
72
73    pszDest = psz;
74    if (psz != NULL)
75    {
76       while (*psz != '\0' && isspace(*psz))
77          psz++;
78       while (*psz != '\0')
79          *pszDest++ = *psz++;
80       *pszDest = '\0';
81    }
82 }
83
84 /**************************************************************************
85 Strip all trailing whitespace from a string.
86 **************************************************************************/
87 static void trimright(char *psz)
88 {
89    char *pszTemp;
90
91    if (psz != NULL && psz[0] != '\0')
92    {
93       pszTemp = psz + strlen(psz) - 1;
94       while (isspace(*pszTemp))
95          *pszTemp-- = '\0';
96    }
97 }
98
99 /***********************************************************************
100 Collapse each whitespace area in a string to a single space.
101 ***********************************************************************/
102 static void collapse_spaces(char *psz)
103 {
104    while (*psz)
105       if (isspace(*psz))
106       {
107          *psz++ = ' ';
108          trimleft(psz);
109       }
110       else
111          psz++;
112 }
113
114 /**************************************************************************
115 Return the value of the first non-white character in the specified string.
116 The terminating NUL counts as non-white for the purposes of this function.
117 Note - no check for a NULL string! What would we return?
118 **************************************************************************/
119 static int firstnonwhite(char *psz)
120 {
121    while (isspace(*psz) && (*psz != '\0'))
122       psz++;
123    return (*psz);
124 }
125
126
127 /**************************************************************************
128 Identifies all parameters in the current section, calls the parameter
129 function for each. Ignores comment lines, stops and backs up in file when
130 a section is encountered. Returns True on success, False on error.
131 **************************************************************************/
132 static BOOL enumerate_parameters(FILE *fileIn, BOOL (*pfunc)(char *,char *))
133 {
134    pstring szBuf;
135    char *pszTemp;
136    BOOL bRetval;
137    long lFileOffset;
138    int  cTemp;
139    BOOL bParmFound;
140
141    bRetval = False;
142    bParmFound = False;
143    while (True)
144    {
145       /* first remember where we are */
146       if ((lFileOffset = ftell(fileIn)) >= 0L)
147       {
148          /* then get and check a line */
149          if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
150          {
151             /* stop - return OK unless file error */
152             bRetval = !ferror(fileIn);
153             if (!bRetval)
154               DEBUG(0,( "Read error on configuration file (enumerating parameters)!\n"));
155             break;   
156          }
157          else
158             /* if first non-white is a '[', stop (new section) */
159             if ((cTemp = firstnonwhite(szBuf)) == '[')
160             {
161                /* restore position to start of new section */
162                if (fseek(fileIn, lFileOffset, SEEK_SET) < 0L)
163                {
164                   DEBUG(0,( "Seek error on configuration file!\n"));
165                   break;
166                }
167
168                /* return success */
169                bRetval = True;
170                break;
171             }
172             else
173                /* if it's a semicolon or line is blank, ignore the line */
174                if (!cTemp || strchr(";#",cTemp))
175                {
176                   continue;
177                }
178                else
179                   /* if no equals sign and line contains non-whitespace */
180                   /* then line is badly formed */
181                   if ((pszTemp = strchr(szBuf, '=')) == NULL)
182                   {
183                      DEBUG(0,( "Ignoring badly formed line: %s", szBuf));
184                   }
185                   else
186                   {
187                      /* Note that we have found a parameter */
188                      bParmFound = True;
189                      /* cut line at the equals sign */
190                      *pszTemp++ = '\0';
191                      /* trim leading and trailing space from both halves */
192                      trimright(szBuf);
193                      trimleft(szBuf);
194                      trimright(pszTemp);
195                      trimleft(pszTemp);
196                      /* process the parameter iff passed pointer not NULL */
197                      if (pfunc != NULL)
198                         if (!pfunc(szBuf, pszTemp))
199                            break;
200                   }
201       }
202    }
203    return (bRetval);
204 }
205
206
207 /***********************************************************************
208 Close up s by n chars, at offset start.
209 ***********************************************************************/
210 static void closestr(char *s, int start, int n)
211 {
212    char *src;
213    char *dest;
214    int  len;
215
216    if (n > 0)
217       if ((src = dest = s) != NULL)
218       {
219          len = strlen(s);
220          if (start >= 0 && start < len - n)
221          {
222             src += start + n;
223             dest += start;
224   
225             while (*src)
226                *dest++ = *src++;
227             *dest = '\0';
228          }
229       }
230 }
231
232 /**************************************************************************
233 Identifies all sections in the parameter file, calls passed section_func()
234 for each, passing the section name, then calls enumerate_parameters(). 
235 Returns True on success, False on failure. Note that the section and 
236 parameter names will have all internal whitespace areas collapsed to a 
237 single space for processing.
238 **************************************************************************/
239 static BOOL enumerate_sections(FILE *fileIn,
240                                BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *))
241 {
242    pstring szBuf;
243    BOOL bRetval;
244    BOOL bSectionFound;
245
246    /* this makes sure we get include lines right */
247    enumerate_parameters(fileIn, pfunc);
248
249    bRetval = False;
250    bSectionFound = False;
251    while (True)
252    {
253       if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
254       {
255          /* stop - return OK unless file error */
256          bRetval = !ferror(fileIn);
257          if (!bRetval)
258            DEBUG(0,( "Read error on configuration file (enumerating sections)!\n"));
259          break;   
260       }
261       else
262       {
263          trimleft(szBuf);
264          trimright(szBuf);
265          if (szBuf[0] == '[')
266          {
267             closestr(szBuf, 0, 1);
268             if (strlen(szBuf) > 1)
269                if (szBuf[strlen(szBuf) - 1] == ']')
270                {  
271                   /* found a section - note the fact */
272                   bSectionFound = True;
273                   /* remove trailing metabracket */
274                   szBuf[strlen(szBuf) - 1] = '\0';
275                   /* remove leading and trailing whitespace from name */
276                   trimleft(szBuf);
277                   trimright(szBuf);
278                   /* reduce all internal whitespace to one space */
279                   collapse_spaces(szBuf);
280                   /* process it - stop if the processing fails */
281                   if (sfunc != NULL)
282                      if (!sfunc(szBuf))
283                         break;
284                   if (!enumerate_parameters(fileIn, pfunc))
285                      break;
286                }
287          }
288       }
289    }
290
291    return (bRetval);
292 }
293
294 /**************************************************************************
295 Process the passed parameter file.
296
297 Returns True if successful, else False.
298 **************************************************************************/
299 BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *))
300 {
301    FILE *fileIn;
302    BOOL bRetval;
303
304    bRetval = False;
305
306    /* record the filename for use in error messages one day... */
307    pszParmFile = pszFileName;
308
309    if (pszParmFile == NULL || strlen(pszParmFile) < 1)
310       DEBUG(0,( "No configuration filename specified!\n"));
311    else
312       if ((fileIn = fopen(pszParmFile, "r")) == NULL)
313          DEBUG(0,( "Unable to open configuration file \"%s\"!\n", pszParmFile));
314       else
315       {
316          DEBUG(2,( "Processing configuration file \"%s\"\n", pszParmFile));
317          bRetval = enumerate_sections(fileIn, sfunc, pfunc);
318          fclose(fileIn);
319       }
320
321    if (!bRetval)
322      DEBUG(0,("pm_process retuned false\n"));
323    return (bRetval);
324 }
325
326