blob: 4ffb39f8244aa05359fb4b0078b9cf18df6c1278 [file] [log] [blame]
/*
* "$Id: options.c 7278 2008-01-31 01:23:09Z mike $"
*
* Option routines for the Common UNIX Printing System (CUPS).
*
* Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
* which should have been included with this file. If this file is
* file is missing or damaged, see the license at "http://www.cups.org/".
*
* This file is subject to the Apple OS-Developed Software exception.
*
* Contents:
*
* cupsAddOption() - Add an option to an option array.
* cupsFreeOptions() - Free all memory used by options.
* cupsGetOption() - Get an option value.
* cupsParseOptions() - Parse options from a command-line argument.
* cupsRemoveOption() - Remove an option from an option array.
*/
/*
* Include necessary headers...
*/
#include "cups.h"
#include <stdlib.h>
#include <ctype.h>
#include "string.h"
#include "debug.h"
/*
* 'cupsAddOption()' - Add an option to an option array.
*
* New option arrays can be initialized simply by passing 0 for the
* "num_options" parameter.
*/
int /* O - Number of options */
cupsAddOption(const char *name, /* I - Name of option */
const char *value, /* I - Value of option */
int num_options,/* I - Number of options */
cups_option_t **options) /* IO - Pointer to options */
{
int i; /* Looping var */
cups_option_t *temp; /* Pointer to new option */
if (name == NULL || !name[0] || value == NULL ||
options == NULL || num_options < 0)
return (num_options);
/*
* Look for an existing option with the same name...
*/
for (i = 0, temp = *options; i < num_options; i ++, temp ++)
if (!strcasecmp(temp->name, name))
break;
if (i >= num_options)
{
/*
* No matching option name...
*/
if (num_options == 0)
temp = (cups_option_t *)malloc(sizeof(cups_option_t));
else
temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) *
(num_options + 1));
if (temp == NULL)
return (0);
*options = temp;
temp += num_options;
temp->name = _cupsStrAlloc(name);
num_options ++;
}
else
{
/*
* Match found; free the old value...
*/
_cupsStrFree(temp->value);
}
temp->value = _cupsStrAlloc(value);
return (num_options);
}
/*
* 'cupsFreeOptions()' - Free all memory used by options.
*/
void
cupsFreeOptions(
int num_options, /* I - Number of options */
cups_option_t *options) /* I - Pointer to options */
{
int i; /* Looping var */
if (num_options <= 0 || options == NULL)
return;
for (i = 0; i < num_options; i ++)
{
_cupsStrFree(options[i].name);
_cupsStrFree(options[i].value);
}
free(options);
}
/*
* 'cupsGetOption()' - Get an option value.
*/
const char * /* O - Option value or @code NULL@ */
cupsGetOption(const char *name, /* I - Name of option */
int num_options,/* I - Number of options */
cups_option_t *options) /* I - Options */
{
int i; /* Looping var */
if (name == NULL || num_options <= 0 || options == NULL)
return (NULL);
for (i = 0; i < num_options; i ++)
if (strcasecmp(options[i].name, name) == 0)
return (options[i].value);
return (NULL);
}
/*
* 'cupsParseOptions()' - Parse options from a command-line argument.
*
* This function converts space-delimited name/value pairs according
* to the PAPI text option ABNF specification. Collection values
* ("name={a=... b=... c=...}") are stored with the curley brackets
* intact - use @code cupsParseOptions@ on the value to extract the
* collection attributes.
*/
int /* O - Number of options found */
cupsParseOptions(
const char *arg, /* I - Argument to parse */
int num_options, /* I - Number of options */
cups_option_t **options) /* O - Options found */
{
char *copyarg, /* Copy of input string */
*ptr, /* Pointer into string */
*name, /* Pointer to name */
*value, /* Pointer to value */
quote; /* Quote character */
/*
* Range check input...
*/
if (!arg)
return (num_options);
if (!options || num_options < 0)
return (0);
/*
* Make a copy of the argument string and then divide it up...
*/
if ((copyarg = strdup(arg)) == NULL)
return (num_options);
ptr = copyarg;
/*
* Skip leading spaces...
*/
while (isspace(*ptr & 255))
ptr ++;
/*
* Loop through the string...
*/
while (*ptr != '\0')
{
/*
* Get the name up to a SPACE, =, or end-of-string...
*/
name = ptr;
while (!isspace(*ptr & 255) && *ptr != '=' && *ptr)
ptr ++;
/*
* Avoid an empty name...
*/
if (ptr == name)
break;
/*
* Skip trailing spaces...
*/
while (isspace(*ptr & 255))
*ptr++ = '\0';
if (*ptr != '=')
{
/*
* Boolean option...
*/
if (!strncasecmp(name, "no", 2))
num_options = cupsAddOption(name + 2, "false", num_options,
options);
else
num_options = cupsAddOption(name, "true", num_options, options);
continue;
}
/*
* Remove = and parse the value...
*/
*ptr++ = '\0';
if (*ptr == '\'' || *ptr == '\"')
{
/*
* Quoted string constant...
*/
quote = *ptr++;
value = ptr;
while (*ptr != quote && *ptr)
{
if (*ptr == '\\' && ptr[1])
_cups_strcpy(ptr, ptr + 1);
ptr ++;
}
if (*ptr != '\0')
*ptr++ = '\0';
}
else if (*ptr == '{')
{
/*
* Collection value...
*/
int depth;
value = ptr;
for (depth = 1; *ptr; ptr ++)
if (*ptr == '{')
depth ++;
else if (*ptr == '}')
{
depth --;
if (!depth)
{
ptr ++;
if (*ptr != ',')
break;
}
}
else if (*ptr == '\\' && ptr[1])
_cups_strcpy(ptr, ptr + 1);
if (*ptr != '\0')
*ptr++ = '\0';
}
else
{
/*
* Normal space-delimited string...
*/
value = ptr;
while (!isspace(*ptr & 255) && *ptr)
{
if (*ptr == '\\' && ptr[1])
_cups_strcpy(ptr, ptr + 1);
ptr ++;
}
}
/*
* Skip trailing whitespace...
*/
while (isspace(*ptr & 255))
*ptr++ = '\0';
/*
* Add the string value...
*/
num_options = cupsAddOption(name, value, num_options, options);
}
/*
* Free the copy of the argument we made and return the number of options
* found.
*/
free(copyarg);
return (num_options);
}
/*
* 'cupsRemoveOption()' - Remove an option from an option array.
*
* @since CUPS 1.2@
*/
int /* O - New number of options */
cupsRemoveOption(
const char *name, /* I - Option name */
int num_options, /* I - Current number of options */
cups_option_t **options) /* IO - Options */
{
int i; /* Looping var */
cups_option_t *option; /* Current option */
/*
* Range check input...
*/
if (!name || num_options < 1 || !options)
return (num_options);
/*
* Loop for the option...
*/
for (i = num_options, option = *options; i > 0; i --, option ++)
if (!strcasecmp(name, option->name))
break;
if (i)
{
/*
* Remove this option from the array...
*/
num_options --;
i --;
_cupsStrFree(option->name);
_cupsStrFree(option->value);
if (i > 0)
memmove(option, option + 1, i * sizeof(cups_option_t));
}
/*
* Return the new number of options...
*/
return (num_options);
}
/*
* End of "$Id: options.c 7278 2008-01-31 01:23:09Z mike $".
*/