1181834Sroberto 2181834Sroberto/* 3181834Sroberto * $Id: load.c,v 4.20 2007/02/04 22:17:39 bkorb Exp $ 4181834Sroberto * Time-stamp: "2007-02-04 11:54:57 bkorb" 5181834Sroberto * 6181834Sroberto * This file contains the routines that deal with processing text strings 7181834Sroberto * for options, either from a NUL-terminated string passed in or from an 8181834Sroberto * rc/ini file. 9181834Sroberto */ 10181834Sroberto 11181834Sroberto/* 12181834Sroberto * Automated Options copyright 1992-2007 Bruce Korb 13181834Sroberto * 14181834Sroberto * Automated Options is free software. 15181834Sroberto * You may redistribute it and/or modify it under the terms of the 16181834Sroberto * GNU General Public License, as published by the Free Software 17181834Sroberto * Foundation; either version 2, or (at your option) any later version. 18181834Sroberto * 19181834Sroberto * Automated Options is distributed in the hope that it will be useful, 20181834Sroberto * but WITHOUT ANY WARRANTY; without even the implied warranty of 21181834Sroberto * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22181834Sroberto * GNU General Public License for more details. 23181834Sroberto * 24181834Sroberto * You should have received a copy of the GNU General Public License 25181834Sroberto * along with Automated Options. See the file "COPYING". If not, 26181834Sroberto * write to: The Free Software Foundation, Inc., 27181834Sroberto * 51 Franklin Street, Fifth Floor, 28181834Sroberto * Boston, MA 02110-1301, USA. 29181834Sroberto * 30181834Sroberto * As a special exception, Bruce Korb gives permission for additional 31181834Sroberto * uses of the text contained in his release of AutoOpts. 32181834Sroberto * 33181834Sroberto * The exception is that, if you link the AutoOpts library with other 34181834Sroberto * files to produce an executable, this does not by itself cause the 35181834Sroberto * resulting executable to be covered by the GNU General Public License. 36181834Sroberto * Your use of that executable is in no way restricted on account of 37181834Sroberto * linking the AutoOpts library code into it. 38181834Sroberto * 39181834Sroberto * This exception does not however invalidate any other reasons why 40181834Sroberto * the executable file might be covered by the GNU General Public License. 41181834Sroberto * 42181834Sroberto * This exception applies only to the code released by Bruce Korb under 43181834Sroberto * the name AutoOpts. If you copy code from other sources under the 44181834Sroberto * General Public License into a copy of AutoOpts, as the General Public 45181834Sroberto * License permits, the exception does not apply to the code that you add 46181834Sroberto * in this way. To avoid misleading anyone as to the status of such 47181834Sroberto * modified files, you must delete this exception notice from them. 48181834Sroberto * 49181834Sroberto * If you write modifications of your own for AutoOpts, it is your choice 50181834Sroberto * whether to permit this exception to apply to your modifications. 51181834Sroberto * If you do not wish that, delete this exception notice. 52181834Sroberto */ 53181834Sroberto 54181834SrobertotOptionLoadMode option_load_mode = OPTION_LOAD_UNCOOKED; 55181834Sroberto 56181834Sroberto/* = = = START-STATIC-FORWARD = = = */ 57181834Sroberto/* static forward declarations maintained by :mkfwd */ 58181834Srobertostatic ag_bool 59181834SrobertoinsertProgramPath( 60181834Sroberto char* pzBuf, 61181834Sroberto int bufSize, 62181834Sroberto tCC* pzName, 63181834Sroberto tCC* pzProgPath ); 64181834Sroberto 65181834Srobertostatic ag_bool 66181834SrobertoinsertEnvVal( 67181834Sroberto char* pzBuf, 68181834Sroberto int bufSize, 69181834Sroberto tCC* pzName, 70181834Sroberto tCC* pzProgPath ); 71181834Sroberto 72181834Srobertostatic char* 73181834SrobertoassembleArgValue( char* pzTxt, tOptionLoadMode mode ); 74181834Sroberto/* = = = END-STATIC-FORWARD = = = */ 75181834Sroberto 76181834Sroberto/*=export_func optionMakePath 77181834Sroberto * private: 78181834Sroberto * 79181834Sroberto * what: translate and construct a path 80181834Sroberto * arg: + char* + pzBuf + The result buffer + 81181834Sroberto * arg: + int + bufSize + The size of this buffer + 82181834Sroberto * arg: + char const* + pzName + The input name + 83181834Sroberto * arg: + char const* + pzProgPath + The full path of the current program + 84181834Sroberto * 85181834Sroberto * ret-type: ag_bool 86181834Sroberto * ret-desc: AG_TRUE if the name was handled, otherwise AG_FALSE. 87181834Sroberto * If the name does not start with ``$'', then it is handled 88181834Sroberto * simply by copying the input name to the output buffer and 89181834Sroberto * resolving the name with either @code{canonicalize_file_name(3GLIBC)} 90181834Sroberto * or @code{realpath(3C)}. 91181834Sroberto * 92181834Sroberto * doc: 93181834Sroberto * 94181834Sroberto * This routine will copy the @code{pzName} input name into the @code{pzBuf} 95181834Sroberto * output buffer, carefully not exceeding @code{bufSize} bytes. If the 96181834Sroberto * first character of the input name is a @code{'$'} character, then there 97181834Sroberto * is special handling: 98181834Sroberto * @* 99181834Sroberto * @code{$$} is replaced with the directory name of the @code{pzProgPath}, 100181834Sroberto * searching @code{$PATH} if necessary. 101181834Sroberto * @* 102181834Sroberto * @code{$@} is replaced with the AutoGen package data installation directory 103181834Sroberto * (aka @code{pkgdatadir}). 104181834Sroberto * @* 105181834Sroberto * @code{$NAME} is replaced by the contents of the @code{NAME} environment 106181834Sroberto * variable. If not found, the search fails. 107181834Sroberto * 108181834Sroberto * Please note: both @code{$$} and @code{$NAME} must be at the start of the 109181834Sroberto * @code{pzName} string and must either be the entire string or be followed 110181834Sroberto * by the @code{'/'} (backslash on windows) character. 111181834Sroberto * 112181834Sroberto * err: @code{AG_FALSE} is returned if: 113181834Sroberto * @* 114181834Sroberto * @bullet{} The input name exceeds @code{bufSize} bytes. 115181834Sroberto * @* 116181834Sroberto * @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string 117181834Sroberto * and the next character is not '/'. 118181834Sroberto * @* 119181834Sroberto * @bullet{} libopts was built without PKGDATADIR defined and @code{$@@} 120181834Sroberto * was specified. 121181834Sroberto * @* 122181834Sroberto * @bullet{} @code{NAME} is not a known environment variable 123181834Sroberto * @* 124181834Sroberto * @bullet{} @code{canonicalize_file_name} or @code{realpath} return 125181834Sroberto * errors (cannot resolve the resulting path). 126181834Sroberto=*/ 127181834Srobertoag_bool 128181834SrobertooptionMakePath( 129181834Sroberto char* pzBuf, 130181834Sroberto int bufSize, 131181834Sroberto tCC* pzName, 132181834Sroberto tCC* pzProgPath ) 133181834Sroberto{ 134181834Sroberto size_t name_len = strlen( pzName ); 135181834Sroberto 136181834Sroberto# ifndef PKGDATADIR 137181834Sroberto# define PKGDATADIR "" 138181834Sroberto# endif 139181834Sroberto 140181834Sroberto tSCC pkgdatadir[] = PKGDATADIR; 141181834Sroberto 142181834Sroberto ag_bool res = AG_TRUE; 143181834Sroberto 144181834Sroberto if (bufSize <= name_len) 145181834Sroberto return AG_FALSE; 146181834Sroberto 147181834Sroberto /* 148181834Sroberto * IF not an environment variable, just copy the data 149181834Sroberto */ 150181834Sroberto if (*pzName != '$') { 151181834Sroberto tCC* pzS = pzName; 152181834Sroberto char* pzD = pzBuf; 153181834Sroberto int ct = bufSize; 154181834Sroberto 155181834Sroberto for (;;) { 156181834Sroberto if ( (*(pzD++) = *(pzS++)) == NUL) 157181834Sroberto break; 158181834Sroberto if (--ct <= 0) 159181834Sroberto return AG_FALSE; 160181834Sroberto } 161181834Sroberto } 162181834Sroberto 163181834Sroberto /* 164181834Sroberto * IF the name starts with "$$", then it must be "$$" or 165181834Sroberto * it must start with "$$/". In either event, replace the "$$" 166181834Sroberto * with the path to the executable and append a "/" character. 167181834Sroberto */ 168181834Sroberto else switch (pzName[1]) { 169181834Sroberto case NUL: 170181834Sroberto return AG_FALSE; 171181834Sroberto 172181834Sroberto case '$': 173181834Sroberto res = insertProgramPath( pzBuf, bufSize, pzName, pzProgPath ); 174181834Sroberto break; 175181834Sroberto 176181834Sroberto case '@': 177181834Sroberto if (pkgdatadir[0] == NUL) 178181834Sroberto return AG_FALSE; 179181834Sroberto 180181834Sroberto if (name_len + sizeof (pkgdatadir) > bufSize) 181181834Sroberto return AG_FALSE; 182181834Sroberto 183181834Sroberto strcpy(pzBuf, pkgdatadir); 184181834Sroberto strcpy(pzBuf + sizeof(pkgdatadir) - 1, pzName + 2); 185181834Sroberto break; 186181834Sroberto 187181834Sroberto default: 188181834Sroberto res = insertEnvVal( pzBuf, bufSize, pzName, pzProgPath ); 189181834Sroberto } 190181834Sroberto 191181834Sroberto if (! res) 192181834Sroberto return AG_FALSE; 193181834Sroberto 194181834Sroberto#if defined(HAVE_CANONICALIZE_FILE_NAME) 195181834Sroberto { 196181834Sroberto char* pz = canonicalize_file_name(pzBuf); 197181834Sroberto if (pz == NULL) 198181834Sroberto return AG_FALSE; 199181834Sroberto if (strlen(pz) < bufSize) 200181834Sroberto strcpy(pzBuf, pz); 201181834Sroberto free(pz); 202181834Sroberto } 203181834Sroberto 204181834Sroberto#elif defined(HAVE_REALPATH) 205181834Sroberto { 206181834Sroberto char z[ PATH_MAX+1 ]; 207181834Sroberto 208181834Sroberto if (realpath( pzBuf, z ) == NULL) 209181834Sroberto return AG_FALSE; 210181834Sroberto 211181834Sroberto if (strlen(z) < bufSize) 212181834Sroberto strcpy( pzBuf, z ); 213181834Sroberto } 214181834Sroberto#endif 215181834Sroberto 216181834Sroberto return AG_TRUE; 217181834Sroberto} 218181834Sroberto 219181834Sroberto 220181834Srobertostatic ag_bool 221181834SrobertoinsertProgramPath( 222181834Sroberto char* pzBuf, 223181834Sroberto int bufSize, 224181834Sroberto tCC* pzName, 225181834Sroberto tCC* pzProgPath ) 226181834Sroberto{ 227181834Sroberto tCC* pzPath; 228181834Sroberto tCC* pz; 229181834Sroberto int skip = 2; 230181834Sroberto 231181834Sroberto switch (pzName[2]) { 232181834Sroberto case DIRCH: 233181834Sroberto skip = 3; 234181834Sroberto case NUL: 235181834Sroberto break; 236181834Sroberto default: 237181834Sroberto return AG_FALSE; 238181834Sroberto } 239181834Sroberto 240181834Sroberto /* 241181834Sroberto * See if the path is included in the program name. 242181834Sroberto * If it is, we're done. Otherwise, we have to hunt 243181834Sroberto * for the program using "pathfind". 244181834Sroberto */ 245181834Sroberto if (strchr( pzProgPath, DIRCH ) != NULL) 246181834Sroberto pzPath = pzProgPath; 247181834Sroberto else { 248181834Sroberto pzPath = pathfind( getenv( "PATH" ), (char*)pzProgPath, "rx" ); 249181834Sroberto 250181834Sroberto if (pzPath == NULL) 251181834Sroberto return AG_FALSE; 252181834Sroberto } 253181834Sroberto 254181834Sroberto pz = strrchr( pzPath, DIRCH ); 255181834Sroberto 256181834Sroberto /* 257181834Sroberto * IF we cannot find a directory name separator, 258181834Sroberto * THEN we do not have a path name to our executable file. 259181834Sroberto */ 260181834Sroberto if (pz == NULL) 261181834Sroberto return AG_FALSE; 262181834Sroberto 263181834Sroberto pzName += skip; 264181834Sroberto 265181834Sroberto /* 266181834Sroberto * Concatenate the file name to the end of the executable path. 267181834Sroberto * The result may be either a file or a directory. 268181834Sroberto */ 269181834Sroberto if ((pz - pzPath)+1 + strlen(pzName) >= bufSize) 270181834Sroberto return AG_FALSE; 271181834Sroberto 272181834Sroberto memcpy( pzBuf, pzPath, (size_t)((pz - pzPath)+1) ); 273181834Sroberto strcpy( pzBuf + (pz - pzPath) + 1, pzName ); 274181834Sroberto 275181834Sroberto /* 276181834Sroberto * If the "pzPath" path was gotten from "pathfind()", then it was 277181834Sroberto * allocated and we need to deallocate it. 278181834Sroberto */ 279181834Sroberto if (pzPath != pzProgPath) 280181834Sroberto free( (void*)pzPath ); 281181834Sroberto return AG_TRUE; 282181834Sroberto} 283181834Sroberto 284181834Sroberto 285181834Srobertostatic ag_bool 286181834SrobertoinsertEnvVal( 287181834Sroberto char* pzBuf, 288181834Sroberto int bufSize, 289181834Sroberto tCC* pzName, 290181834Sroberto tCC* pzProgPath ) 291181834Sroberto{ 292181834Sroberto char* pzDir = pzBuf; 293181834Sroberto 294181834Sroberto for (;;) { 295181834Sroberto int ch = (int)*++pzName; 296181834Sroberto if (! ISNAMECHAR( ch )) 297181834Sroberto break; 298181834Sroberto *(pzDir++) = (char)ch; 299181834Sroberto } 300181834Sroberto 301181834Sroberto if (pzDir == pzBuf) 302181834Sroberto return AG_FALSE; 303181834Sroberto 304181834Sroberto *pzDir = NUL; 305181834Sroberto 306181834Sroberto pzDir = getenv( pzBuf ); 307181834Sroberto 308181834Sroberto /* 309181834Sroberto * Environment value not found -- skip the home list entry 310181834Sroberto */ 311181834Sroberto if (pzDir == NULL) 312181834Sroberto return AG_FALSE; 313181834Sroberto 314181834Sroberto if (strlen( pzDir ) + 1 + strlen( pzName ) >= bufSize) 315181834Sroberto return AG_FALSE; 316181834Sroberto 317181834Sroberto sprintf( pzBuf, "%s%s", pzDir, pzName ); 318181834Sroberto return AG_TRUE; 319181834Sroberto} 320181834Sroberto 321181834Sroberto 322181834SrobertoLOCAL void 323181834SrobertomungeString( char* pzTxt, tOptionLoadMode mode ) 324181834Sroberto{ 325181834Sroberto char* pzE; 326181834Sroberto 327181834Sroberto if (mode == OPTION_LOAD_KEEP) 328181834Sroberto return; 329181834Sroberto 330181834Sroberto if (isspace( (int)*pzTxt )) { 331181834Sroberto char* pzS = pzTxt; 332181834Sroberto char* pzD = pzTxt; 333181834Sroberto while (isspace( (int)*++pzS )) ; 334181834Sroberto while ((*(pzD++) = *(pzS++)) != NUL) ; 335181834Sroberto pzE = pzD-1; 336181834Sroberto } else 337181834Sroberto pzE = pzTxt + strlen( pzTxt ); 338181834Sroberto 339181834Sroberto while ((pzE > pzTxt) && isspace( (int)pzE[-1] )) pzE--; 340181834Sroberto *pzE = NUL; 341181834Sroberto 342181834Sroberto if (mode == OPTION_LOAD_UNCOOKED) 343181834Sroberto return; 344181834Sroberto 345181834Sroberto switch (*pzTxt) { 346181834Sroberto default: return; 347181834Sroberto case '"': 348181834Sroberto case '\'': break; 349181834Sroberto } 350181834Sroberto 351181834Sroberto switch (pzE[-1]) { 352181834Sroberto default: return; 353181834Sroberto case '"': 354181834Sroberto case '\'': break; 355181834Sroberto } 356181834Sroberto 357181834Sroberto (void)ao_string_cook( pzTxt, NULL ); 358181834Sroberto} 359181834Sroberto 360181834Sroberto 361181834Srobertostatic char* 362181834SrobertoassembleArgValue( char* pzTxt, tOptionLoadMode mode ) 363181834Sroberto{ 364181834Sroberto tSCC zBrk[] = " \t:="; 365181834Sroberto char* pzEnd = strpbrk( pzTxt, zBrk ); 366181834Sroberto int space_break; 367181834Sroberto 368181834Sroberto /* 369181834Sroberto * Not having an argument to a configurable name is okay. 370181834Sroberto */ 371181834Sroberto if (pzEnd == NULL) 372181834Sroberto return pzTxt + strlen(pzTxt); 373181834Sroberto 374181834Sroberto /* 375181834Sroberto * If we are keeping all whitespace, then the modevalue starts with the 376181834Sroberto * character that follows the end of the configurable name, regardless 377181834Sroberto * of which character caused it. 378181834Sroberto */ 379181834Sroberto if (mode == OPTION_LOAD_KEEP) { 380181834Sroberto *(pzEnd++) = NUL; 381181834Sroberto return pzEnd; 382181834Sroberto } 383181834Sroberto 384181834Sroberto /* 385181834Sroberto * If the name ended on a white space character, remember that 386181834Sroberto * because we'll have to skip over an immediately following ':' or '=' 387181834Sroberto * (and the white space following *that*). 388181834Sroberto */ 389181834Sroberto space_break = isspace((int)*pzEnd); 390181834Sroberto *(pzEnd++) = NUL; 391181834Sroberto while (isspace((int)*pzEnd)) pzEnd++; 392181834Sroberto if (space_break && ((*pzEnd == ':') || (*pzEnd == '='))) 393181834Sroberto while (isspace((int)*++pzEnd)) ; 394181834Sroberto 395181834Sroberto return pzEnd; 396181834Sroberto} 397181834Sroberto 398181834Sroberto 399181834Sroberto/* 400181834Sroberto * Load an option from a block of text. The text must start with the 401181834Sroberto * configurable/option name and be followed by its associated value. 402181834Sroberto * That value may be processed in any of several ways. See "tOptionLoadMode" 403181834Sroberto * in autoopts.h. 404181834Sroberto */ 405181834SrobertoLOCAL void 406181834SrobertoloadOptionLine( 407181834Sroberto tOptions* pOpts, 408181834Sroberto tOptState* pOS, 409181834Sroberto char* pzLine, 410181834Sroberto tDirection direction, 411181834Sroberto tOptionLoadMode load_mode ) 412181834Sroberto{ 413181834Sroberto while (isspace( (int)*pzLine )) pzLine++; 414181834Sroberto 415181834Sroberto { 416181834Sroberto char* pzArg = assembleArgValue( pzLine, load_mode ); 417181834Sroberto 418181834Sroberto if (! SUCCESSFUL( longOptionFind( pOpts, pzLine, pOS ))) 419181834Sroberto return; 420181834Sroberto if (pOS->flags & OPTST_NO_INIT) 421181834Sroberto return; 422181834Sroberto pOS->pzOptArg = pzArg; 423181834Sroberto } 424181834Sroberto 425181834Sroberto switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) { 426181834Sroberto case 0: 427181834Sroberto /* 428181834Sroberto * The selected option has no immediate action. 429181834Sroberto * THEREFORE, if the direction is PRESETTING 430181834Sroberto * THEN we skip this option. 431181834Sroberto */ 432181834Sroberto if (PRESETTING(direction)) 433181834Sroberto return; 434181834Sroberto break; 435181834Sroberto 436181834Sroberto case OPTST_IMM: 437181834Sroberto if (PRESETTING(direction)) { 438181834Sroberto /* 439181834Sroberto * We are in the presetting direction with an option we handle 440181834Sroberto * immediately for enablement, but normally for disablement. 441181834Sroberto * Therefore, skip if disabled. 442181834Sroberto */ 443181834Sroberto if ((pOS->flags & OPTST_DISABLED) == 0) 444181834Sroberto return; 445181834Sroberto } else { 446181834Sroberto /* 447181834Sroberto * We are in the processing direction with an option we handle 448181834Sroberto * immediately for enablement, but normally for disablement. 449181834Sroberto * Therefore, skip if NOT disabled. 450181834Sroberto */ 451181834Sroberto if ((pOS->flags & OPTST_DISABLED) != 0) 452181834Sroberto return; 453181834Sroberto } 454181834Sroberto break; 455181834Sroberto 456181834Sroberto case OPTST_DISABLE_IMM: 457181834Sroberto if (PRESETTING(direction)) { 458181834Sroberto /* 459181834Sroberto * We are in the presetting direction with an option we handle 460181834Sroberto * immediately for disablement, but normally for disablement. 461181834Sroberto * Therefore, skip if NOT disabled. 462181834Sroberto */ 463181834Sroberto if ((pOS->flags & OPTST_DISABLED) != 0) 464181834Sroberto return; 465181834Sroberto } else { 466181834Sroberto /* 467181834Sroberto * We are in the processing direction with an option we handle 468181834Sroberto * immediately for disablement, but normally for disablement. 469181834Sroberto * Therefore, skip if disabled. 470181834Sroberto */ 471181834Sroberto if ((pOS->flags & OPTST_DISABLED) == 0) 472181834Sroberto return; 473181834Sroberto } 474181834Sroberto break; 475181834Sroberto 476181834Sroberto case OPTST_IMM|OPTST_DISABLE_IMM: 477181834Sroberto /* 478181834Sroberto * The selected option is always for immediate action. 479181834Sroberto * THEREFORE, if the direction is PROCESSING 480181834Sroberto * THEN we skip this option. 481181834Sroberto */ 482181834Sroberto if (PROCESSING(direction)) 483181834Sroberto return; 484181834Sroberto break; 485181834Sroberto } 486181834Sroberto 487181834Sroberto /* 488181834Sroberto * Fix up the args. 489181834Sroberto */ 490181834Sroberto if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) { 491181834Sroberto if (*pOS->pzOptArg != NUL) 492181834Sroberto return; 493181834Sroberto pOS->pzOptArg = NULL; 494181834Sroberto 495181834Sroberto } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) { 496181834Sroberto if (*pOS->pzOptArg == NUL) 497181834Sroberto pOS->pzOptArg = NULL; 498181834Sroberto else { 499181834Sroberto AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" ); 500181834Sroberto pOS->flags |= OPTST_ALLOC_ARG; 501181834Sroberto } 502181834Sroberto 503181834Sroberto } else { 504181834Sroberto if (*pOS->pzOptArg == NUL) 505181834Sroberto pOS->pzOptArg = zNil; 506181834Sroberto else { 507181834Sroberto AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" ); 508181834Sroberto pOS->flags |= OPTST_ALLOC_ARG; 509181834Sroberto } 510181834Sroberto } 511181834Sroberto 512181834Sroberto { 513181834Sroberto tOptionLoadMode sv = option_load_mode; 514181834Sroberto option_load_mode = load_mode; 515181834Sroberto handleOption( pOpts, pOS ); 516181834Sroberto option_load_mode = sv; 517181834Sroberto } 518181834Sroberto} 519181834Sroberto 520181834Sroberto 521181834Sroberto/*=export_func optionLoadLine 522181834Sroberto * 523181834Sroberto * what: process a string for an option name and value 524181834Sroberto * 525181834Sroberto * arg: tOptions*, pOpts, program options descriptor 526181834Sroberto * arg: char const*, pzLine, NUL-terminated text 527181834Sroberto * 528181834Sroberto * doc: 529181834Sroberto * 530181834Sroberto * This is a client program callable routine for setting options from, for 531181834Sroberto * example, the contents of a file that they read in. Only one option may 532181834Sroberto * appear in the text. It will be treated as a normal (non-preset) option. 533181834Sroberto * 534181834Sroberto * When passed a pointer to the option struct and a string, it will find 535181834Sroberto * the option named by the first token on the string and set the option 536181834Sroberto * argument to the remainder of the string. The caller must NUL terminate 537181834Sroberto * the string. Any embedded new lines will be included in the option 538181834Sroberto * argument. If the input looks like one or more quoted strings, then the 539181834Sroberto * input will be "cooked". The "cooking" is identical to the string 540181834Sroberto * formation used in AutoGen definition files (@pxref{basic expression}), 541181834Sroberto * except that you may not use backquotes. 542181834Sroberto * 543181834Sroberto * err: Invalid options are silently ignored. Invalid option arguments 544181834Sroberto * will cause a warning to print, but the function should return. 545181834Sroberto=*/ 546181834Srobertovoid 547181834SrobertooptionLoadLine( 548181834Sroberto tOptions* pOpts, 549181834Sroberto tCC* pzLine ) 550181834Sroberto{ 551181834Sroberto tOptState st = OPTSTATE_INITIALIZER(SET); 552181834Sroberto char* pz; 553181834Sroberto AGDUPSTR( pz, pzLine, "user option line" ); 554181834Sroberto loadOptionLine( pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED ); 555181834Sroberto AGFREE( pz ); 556181834Sroberto} 557181834Sroberto/* 558181834Sroberto * Local Variables: 559181834Sroberto * mode: C 560181834Sroberto * c-file-style: "stroustrup" 561181834Sroberto * indent-tabs-mode: nil 562181834Sroberto * End: 563181834Sroberto * end of autoopts/load.c */ 564