~ubuntu-branches/ubuntu/gutsy/ntp/gutsy

« back to all changes in this revision

Viewing changes to libopts/load.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-05-18 22:41:56 UTC
  • mfrom: (1.2.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20070518224156-563ruqxsxvqvoy8h
Tags: 1:4.2.4p0+dfsg-1ubuntu1
* Merge from Debian unstable.
* Remaining Ubuntu changes:
  - Update version in conflicts/replaces to that which was shipped in edgy,
    which was later than that in Debian (due to the ubuntuX).
  - Change default server to ntp.ubuntu.com.
  - Remove stop links from rc0 and rc6
  - Call dh_installinit with --error-handler
  - Set Ubuntu maintainer address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 *  $Id: load.c,v 4.14 2006/09/28 01:26:33 bkorb Exp $
 
4
 *  Time-stamp:      "2006-09-24 15:23:01 bkorb"
 
5
 *
 
6
 *  This file contains the routines that deal with processing text strings
 
7
 *  for options, either from a NUL-terminated string passed in or from an
 
8
 *  rc/ini file.
 
9
 */
 
10
 
 
11
/*
 
12
 *  Automated Options copyright 1992-2006 Bruce Korb
 
13
 *
 
14
 *  Automated Options is free software.
 
15
 *  You may redistribute it and/or modify it under the terms of the
 
16
 *  GNU General Public License, as published by the Free Software
 
17
 *  Foundation; either version 2, or (at your option) any later version.
 
18
 *
 
19
 *  Automated Options is distributed in the hope that it will be useful,
 
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 *  GNU General Public License for more details.
 
23
 *
 
24
 *  You should have received a copy of the GNU General Public License
 
25
 *  along with Automated Options.  See the file "COPYING".  If not,
 
26
 *  write to:  The Free Software Foundation, Inc.,
 
27
 *             51 Franklin Street, Fifth Floor,
 
28
 *             Boston, MA  02110-1301, USA.
 
29
 *
 
30
 * As a special exception, Bruce Korb gives permission for additional
 
31
 * uses of the text contained in his release of AutoOpts.
 
32
 *
 
33
 * The exception is that, if you link the AutoOpts library with other
 
34
 * files to produce an executable, this does not by itself cause the
 
35
 * resulting executable to be covered by the GNU General Public License.
 
36
 * Your use of that executable is in no way restricted on account of
 
37
 * linking the AutoOpts library code into it.
 
38
 *
 
39
 * This exception does not however invalidate any other reasons why
 
40
 * the executable file might be covered by the GNU General Public License.
 
41
 *
 
42
 * This exception applies only to the code released by Bruce Korb under
 
43
 * the name AutoOpts.  If you copy code from other sources under the
 
44
 * General Public License into a copy of AutoOpts, as the General Public
 
45
 * License permits, the exception does not apply to the code that you add
 
46
 * in this way.  To avoid misleading anyone as to the status of such
 
47
 * modified files, you must delete this exception notice from them.
 
48
 *
 
49
 * If you write modifications of your own for AutoOpts, it is your choice
 
50
 * whether to permit this exception to apply to your modifications.
 
51
 * If you do not wish that, delete this exception notice.
 
52
 */
 
53
 
 
54
/* = = = START-STATIC-FORWARD = = = */
 
55
/* static forward declarations maintained by :mkfwd */
 
56
static ag_bool
 
57
insertProgramPath(
 
58
    char*   pzBuf,
 
59
    int     bufSize,
 
60
    tCC*    pzName,
 
61
    tCC*    pzProgPath );
 
62
 
 
63
static ag_bool
 
64
insertEnvVal(
 
65
    char*   pzBuf,
 
66
    int     bufSize,
 
67
    tCC*    pzName,
 
68
    tCC*    pzProgPath );
 
69
 
 
70
static char*
 
71
assembleArgValue( char* pzTxt, tOptionLoadMode mode );
 
72
/* = = = END-STATIC-FORWARD = = = */
 
73
 
 
74
/*=export_func  optionMakePath
 
75
 * private:
 
76
 *
 
77
 * what:  translate and construct a path
 
78
 * arg:   + char*       + pzBuf      + The result buffer +
 
79
 * arg:   + int         + bufSize    + The size of this buffer +
 
80
 * arg:   + char const* + pzName     + The input name +
 
81
 * arg:   + char const* + pzProgPath + The full path of the current program +
 
82
 *
 
83
 * ret-type: ag_bool
 
84
 * ret-desc: AG_TRUE if the name was handled, otherwise AG_FALSE.
 
85
 *           If the name does not start with ``$'', then it is handled
 
86
 *           simply by copying the input name to the output buffer and
 
87
 *           resolving the name with either @code{canonicalize_file_name(3GLIBC)}
 
88
 *           or @code{realpath(3C)}.
 
89
 *
 
90
 * doc:
 
91
 *
 
92
 *  This routine will copy the @code{pzName} input name into the @code{pzBuf}
 
93
 *  output buffer, carefully not exceeding @code{bufSize} bytes.  If the
 
94
 *  first character of the input name is a @code{'$'} character, then there
 
95
 *  is special handling:
 
96
 *  @*
 
97
 *  @code{$$} is replaced with the directory name of the @code{pzProgPath},
 
98
 *  searching @code{$PATH} if necessary.
 
99
 *  @*
 
100
 *  @code{$NAME} is replaced by the contents of the @code{NAME} environment
 
101
 *  variable.
 
102
 *
 
103
 *  Please note: both @code{$$} and @code{$NAME} must be at the start of the
 
104
 *     @code{pzName} string and must either be the entire string or be followed
 
105
 *     by the @code{'/'} (backslash on windows) character.
 
106
 *
 
107
 * err:  @code{AG_FALSE} is returned if:
 
108
 *       @*
 
109
 *       @bullet{} The input name exceeds @code{bufSize} bytes.
 
110
 *       @*
 
111
 *       @bullet{} @code{$$} or @code{$NAME} is not the full string and
 
112
 *                 the next character is not '/'.
 
113
 *       @*
 
114
 *       @bullet{} @code{NAME} is not a known environment variable
 
115
 *       @*
 
116
 *       @bullet{} @code{canonicalize_file_name} or @code{realpath} return
 
117
 *                 errors (cannot resolve the resulting path).
 
118
=*/
 
119
ag_bool
 
120
optionMakePath(
 
121
    char*   pzBuf,
 
122
    int     bufSize,
 
123
    tCC*    pzName,
 
124
    tCC*    pzProgPath )
 
125
{
 
126
    ag_bool res = AG_TRUE;
 
127
 
 
128
    if (bufSize <= strlen( pzName ))
 
129
        return AG_FALSE;
 
130
 
 
131
    /*
 
132
     *  IF not an environment variable, just copy the data
 
133
     */
 
134
    if (*pzName != '$') {
 
135
        tCC*  pzS = pzName;
 
136
        char* pzD = pzBuf;
 
137
        int   ct  = bufSize;
 
138
 
 
139
        for (;;) {
 
140
            if ( (*(pzD++) = *(pzS++)) == NUL)
 
141
                break;
 
142
            if (--ct <= 0)
 
143
                return AG_FALSE;
 
144
        }
 
145
    }
 
146
 
 
147
    /*
 
148
     *  IF the name starts with "$$", then it must be "$$" or
 
149
     *  it must start with "$$/".  In either event, replace the "$$"
 
150
     *  with the path to the executable and append a "/" character.
 
151
     */
 
152
    else if (pzName[1] == '$')
 
153
        res = insertProgramPath( pzBuf, bufSize, pzName, pzProgPath );
 
154
    else
 
155
        res = insertEnvVal( pzBuf, bufSize, pzName, pzProgPath );
 
156
 
 
157
    if (! res)
 
158
        return AG_FALSE;
 
159
 
 
160
#if defined(HAVE_CANONICALIZE_FILE_NAME)
 
161
    {
 
162
        char* pz = canonicalize_file_name(pzBuf);
 
163
        if (pz == NULL)
 
164
            return AG_FALSE;
 
165
        if (strlen(pz) < bufSize)
 
166
            strcpy(pzBuf, pz);
 
167
        free(pz);
 
168
    }
 
169
 
 
170
#elif defined(HAVE_REALPATH)
 
171
    {
 
172
        char z[ PATH_MAX+1 ];
 
173
 
 
174
        if (realpath( pzBuf, z ) == NULL)
 
175
            return AG_FALSE;
 
176
 
 
177
        if (strlen(z) < bufSize)
 
178
            strcpy( pzBuf, z );
 
179
    }
 
180
#endif
 
181
 
 
182
    return AG_TRUE;
 
183
}
 
184
 
 
185
 
 
186
static ag_bool
 
187
insertProgramPath(
 
188
    char*   pzBuf,
 
189
    int     bufSize,
 
190
    tCC*    pzName,
 
191
    tCC*    pzProgPath )
 
192
{
 
193
    tCC*    pzPath;
 
194
    tCC*    pz;
 
195
    int     skip = 2;
 
196
 
 
197
    switch (pzName[2]) {
 
198
    case DIRCH:
 
199
        skip = 3;
 
200
    case NUL:
 
201
        break;
 
202
    default:
 
203
        return AG_FALSE;
 
204
    }
 
205
 
 
206
    /*
 
207
     *  See if the path is included in the program name.
 
208
     *  If it is, we're done.  Otherwise, we have to hunt
 
209
     *  for the program using "pathfind".
 
210
     */
 
211
    if (strchr( pzProgPath, DIRCH ) != NULL)
 
212
        pzPath = pzProgPath;
 
213
    else {
 
214
        pzPath = pathfind( getenv( "PATH" ), (char*)pzProgPath, "rx" );
 
215
 
 
216
        if (pzPath == NULL)
 
217
            return AG_FALSE;
 
218
    }
 
219
 
 
220
    pz = strrchr( pzPath, DIRCH );
 
221
 
 
222
    /*
 
223
     *  IF we cannot find a directory name separator,
 
224
     *  THEN we do not have a path name to our executable file.
 
225
     */
 
226
    if (pz == NULL)
 
227
        return AG_FALSE;
 
228
 
 
229
    pzName += skip;
 
230
 
 
231
    /*
 
232
     *  Concatenate the file name to the end of the executable path.
 
233
     *  The result may be either a file or a directory.
 
234
     */
 
235
    if ((pz - pzPath)+1 + strlen(pzName) >= bufSize)
 
236
        return AG_FALSE;
 
237
 
 
238
    memcpy( pzBuf, pzPath, (unsigned)((pz - pzPath)+1) );
 
239
    strcpy( pzBuf + (pz - pzPath) + 1, pzName );
 
240
 
 
241
    /*
 
242
     *  If the "pzPath" path was gotten from "pathfind()", then it was
 
243
     *  allocated and we need to deallocate it.
 
244
     */
 
245
    if (pzPath != pzProgPath)
 
246
        free( (void*)pzPath );
 
247
    return AG_TRUE;
 
248
}
 
249
 
 
250
 
 
251
static ag_bool
 
252
insertEnvVal(
 
253
    char*   pzBuf,
 
254
    int     bufSize,
 
255
    tCC*    pzName,
 
256
    tCC*    pzProgPath )
 
257
{
 
258
    char* pzDir = pzBuf;
 
259
 
 
260
    for (;;) {
 
261
        int ch = (int)*++pzName;
 
262
        if (! ISNAMECHAR( ch ))
 
263
            break;
 
264
        *(pzDir++) = (char)ch;
 
265
    }
 
266
 
 
267
    if (pzDir == pzBuf)
 
268
        return AG_FALSE;
 
269
 
 
270
    *pzDir = NUL;
 
271
 
 
272
    pzDir = getenv( pzBuf );
 
273
 
 
274
    /*
 
275
     *  Environment value not found -- skip the home list entry
 
276
     */
 
277
    if (pzDir == NULL)
 
278
        return AG_FALSE;
 
279
 
 
280
    if (strlen( pzDir ) + 1 + strlen( pzName ) >= bufSize)
 
281
        return AG_FALSE;
 
282
 
 
283
    sprintf( pzBuf, "%s%s", pzDir, pzName );
 
284
    return AG_TRUE;
 
285
}
 
286
 
 
287
 
 
288
LOCAL void
 
289
mungeString( char* pzTxt, tOptionLoadMode mode )
 
290
{
 
291
    char* pzE;
 
292
 
 
293
    if (mode == OPTION_LOAD_KEEP)
 
294
        return;
 
295
 
 
296
    if (isspace( (int)*pzTxt )) {
 
297
        char* pzS = pzTxt;
 
298
        char* pzD = pzTxt;
 
299
        while (isspace( (int)*++pzS ))  ;
 
300
        while ((*(pzD++) = *(pzS++)) != NUL)   ;
 
301
        pzE = pzD-1;
 
302
    } else
 
303
        pzE = pzTxt + strlen( pzTxt );
 
304
 
 
305
    while ((pzE > pzTxt) && isspace( (int)pzE[-1] ))  pzE--;
 
306
    *pzE = NUL;
 
307
 
 
308
    if (mode == OPTION_LOAD_UNCOOKED)
 
309
        return;
 
310
 
 
311
    switch (*pzTxt) {
 
312
    default: return;
 
313
    case '"':
 
314
    case '\'': break;
 
315
    }
 
316
 
 
317
    switch (pzE[-1]) {
 
318
    default: return;
 
319
    case '"':
 
320
    case '\'': break;
 
321
    }
 
322
 
 
323
    (void)ao_string_cook( pzTxt, NULL );
 
324
}
 
325
 
 
326
 
 
327
static char*
 
328
assembleArgValue( char* pzTxt, tOptionLoadMode mode )
 
329
{
 
330
    tSCC zBrk[] = " \t:=";
 
331
    char* pzEnd = strpbrk( pzTxt, zBrk );
 
332
    int   space_break;
 
333
 
 
334
    /*
 
335
     *  Not having an argument to a configurable name is okay.
 
336
     */
 
337
    if (pzEnd == NULL)
 
338
        return pzTxt + strlen(pzTxt);
 
339
 
 
340
    /*
 
341
     *  If we are keeping all whitespace, then the value starts with the
 
342
     *  character that follows the end of the configurable name, regardless
 
343
     *  of which character caused it.
 
344
     */
 
345
    if (mode == OPTION_LOAD_KEEP) {
 
346
        *(pzEnd++) = NUL;
 
347
        return pzEnd;
 
348
    }
 
349
 
 
350
    /*
 
351
     *  If the name ended on a white space character, remember that
 
352
     *  because we'll have to skip over an immediately following ':' or '='
 
353
     *  (and the white space following *that*).
 
354
     */
 
355
    space_break = isspace((int)*pzEnd);
 
356
    *(pzEnd++) = NUL;
 
357
    while (isspace((int)*pzEnd))  pzEnd++;
 
358
    if (space_break && ((*pzEnd == ':') || (*pzEnd == '=')))
 
359
        pzEnd++;
 
360
 
 
361
    mungeString( pzEnd, mode );
 
362
    return pzEnd;
 
363
}
 
364
 
 
365
 
 
366
/*
 
367
 *  Load an option from a block of text.  The text must start with the
 
368
 *  configurable/option name and be followed by its associated value.
 
369
 *  That value may be processed in any of several ways.  See "tOptionLoadMode"
 
370
 *  in autoopts.h.
 
371
 */
 
372
LOCAL void
 
373
loadOptionLine(
 
374
    tOptions*   pOpts,
 
375
    tOptState*  pOS,
 
376
    char*       pzLine,
 
377
    tDirection  direction,
 
378
    tOptionLoadMode   load_mode )
 
379
{
 
380
    while (isspace( (int)*pzLine ))  pzLine++;
 
381
 
 
382
    {
 
383
        char* pzArg = assembleArgValue( pzLine, load_mode );
 
384
 
 
385
        if (! SUCCESSFUL( longOptionFind( pOpts, pzLine, pOS )))
 
386
            return;
 
387
        if (pOS->flags & OPTST_NO_INIT)
 
388
            return;
 
389
        pOS->pzOptArg = pzArg;
 
390
    }
 
391
 
 
392
    switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) {
 
393
    case 0:
 
394
        /*
 
395
         *  The selected option has no immediate action.
 
396
         *  THEREFORE, if the direction is PRESETTING
 
397
         *  THEN we skip this option.
 
398
         */
 
399
        if (PRESETTING(direction))
 
400
            return;
 
401
        break;
 
402
 
 
403
    case OPTST_IMM:
 
404
        if (PRESETTING(direction)) {
 
405
            /*
 
406
             *  We are in the presetting direction with an option we handle
 
407
             *  immediately for enablement, but normally for disablement.
 
408
             *  Therefore, skip if disabled.
 
409
             */
 
410
            if ((pOS->flags & OPTST_DISABLED) == 0)
 
411
                return;
 
412
        } else {
 
413
            /*
 
414
             *  We are in the processing direction with an option we handle
 
415
             *  immediately for enablement, but normally for disablement.
 
416
             *  Therefore, skip if NOT disabled.
 
417
             */
 
418
            if ((pOS->flags & OPTST_DISABLED) != 0)
 
419
                return;
 
420
        }
 
421
        break;
 
422
 
 
423
    case OPTST_DISABLE_IMM:
 
424
        if (PRESETTING(direction)) {
 
425
            /*
 
426
             *  We are in the presetting direction with an option we handle
 
427
             *  immediately for disablement, but normally for disablement.
 
428
             *  Therefore, skip if NOT disabled.
 
429
             */
 
430
            if ((pOS->flags & OPTST_DISABLED) != 0)
 
431
                return;
 
432
        } else {
 
433
            /*
 
434
             *  We are in the processing direction with an option we handle
 
435
             *  immediately for disablement, but normally for disablement.
 
436
             *  Therefore, skip if disabled.
 
437
             */
 
438
            if ((pOS->flags & OPTST_DISABLED) == 0)
 
439
                return;
 
440
        }
 
441
        break;
 
442
 
 
443
    case OPTST_IMM|OPTST_DISABLE_IMM:
 
444
        /*
 
445
         *  The selected option is always for immediate action.
 
446
         *  THEREFORE, if the direction is PROCESSING
 
447
         *  THEN we skip this option.
 
448
         */
 
449
        if (PROCESSING(direction))
 
450
            return;
 
451
        break;
 
452
    }
 
453
 
 
454
    /*
 
455
     *  Fix up the args.
 
456
     */
 
457
    if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) {
 
458
        if (*pOS->pzOptArg != NUL)
 
459
            return;
 
460
        pOS->pzOptArg = NULL;
 
461
 
 
462
    } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) {
 
463
        if (*pOS->pzOptArg == NUL)
 
464
             pOS->pzOptArg = NULL;
 
465
        else AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
 
466
 
 
467
    } else {
 
468
        if (*pOS->pzOptArg == NUL)
 
469
             pOS->pzOptArg = zNil;
 
470
        else AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
 
471
    }
 
472
 
 
473
    handleOption( pOpts, pOS );
 
474
}
 
475
 
 
476
 
 
477
/*=export_func  optionLoadLine
 
478
 *
 
479
 * what:  process a string for an option name and value
 
480
 *
 
481
 * arg:   tOptions*,   pOpts,  program options descriptor
 
482
 * arg:   char const*, pzLine, NUL-terminated text
 
483
 *
 
484
 * doc:
 
485
 *
 
486
 *  This is a client program callable routine for setting options from, for
 
487
 *  example, the contents of a file that they read in.  Only one option may
 
488
 *  appear in the text.  It will be treated as a normal (non-preset) option.
 
489
 *
 
490
 *  When passed a pointer to the option struct and a string, it will find
 
491
 *  the option named by the first token on the string and set the option
 
492
 *  argument to the remainder of the string.  The caller must NUL terminate
 
493
 *  the string.  Any embedded new lines will be included in the option
 
494
 *  argument.  If the input looks like one or more quoted strings, then the
 
495
 *  input will be "cooked".  The "cooking" is identical to the string
 
496
 *  formation used in AutoGen definition files (@pxref{basic expression}),
 
497
 *  except that you may not use backquotes.
 
498
 *
 
499
 * err:   Invalid options are silently ignored.  Invalid option arguments
 
500
 *        will cause a warning to print, but the function should return.
 
501
=*/
 
502
void
 
503
optionLoadLine(
 
504
    tOptions*  pOpts,
 
505
    tCC*       pzLine )
 
506
{
 
507
    tOptState st = OPTSTATE_INITIALIZER(SET);
 
508
    char* pz;
 
509
    AGDUPSTR( pz, pzLine, "user option line" );
 
510
    loadOptionLine( pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED );
 
511
    AGFREE( pz );
 
512
}
 
513
/*
 
514
 * Local Variables:
 
515
 * mode: C
 
516
 * c-file-style: "stroustrup"
 
517
 * indent-tabs-mode: nil
 
518
 * End:
 
519
 * end of autoopts/load.c */