#include "cups.h"
#include <stdlib.h>
#include <ctype.h>
#include "string.h"
#include "debug.h"
static int cups_compare_options(cups_option_t *a, cups_option_t *b);
static int cups_find_option(const char *name, int num_options,
cups_option_t *option, int prev, int *rdiff);
int
cupsAddOption(const char *name,
const char *value,
int num_options,
cups_option_t **options)
{
cups_option_t *temp;
int insert,
diff;
DEBUG_printf(("2cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, "
"options=%p)", name, value, num_options, options));
if (!name || !name[0] || !value || !options || num_options < 0)
{
DEBUG_printf(("3cupsAddOption: Returning %d", num_options));
return (num_options);
}
if (num_options == 0)
{
insert = 0;
diff = 1;
}
else
{
insert = cups_find_option(name, num_options, *options, num_options - 1,
&diff);
if (diff > 0)
insert ++;
}
if (diff)
{
DEBUG_printf(("4cupsAddOption: New option inserted at index %d...",
insert));
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)
{
DEBUG_puts("3cupsAddOption: Unable to expand option array, returning 0");
return (0);
}
*options = temp;
if (insert < num_options)
{
DEBUG_printf(("4cupsAddOption: Shifting %d options...",
(int)(num_options - insert)));
memmove(temp + insert + 1, temp + insert,
(num_options - insert) * sizeof(cups_option_t));
}
temp += insert;
temp->name = _cupsStrAlloc(name);
num_options ++;
}
else
{
DEBUG_printf(("4cupsAddOption: Option already exists at index %d...",
insert));
temp = *options + insert;
_cupsStrFree(temp->value);
}
temp->value = _cupsStrAlloc(value);
DEBUG_printf(("3cupsAddOption: Returning %d", num_options));
return (num_options);
}
void
cupsFreeOptions(
int num_options,
cups_option_t *options)
{
int i;
DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)", num_options,
options));
if (num_options <= 0 || !options)
return;
for (i = 0; i < num_options; i ++)
{
_cupsStrFree(options[i].name);
_cupsStrFree(options[i].value);
}
free(options);
}
const char *
cupsGetOption(const char *name,
int num_options,
cups_option_t *options)
{
int diff,
match;
DEBUG_printf(("2cupsGetOption(name=\"%s\", num_options=%d, options=%p)",
name, num_options, options));
if (!name || num_options <= 0 || !options)
{
DEBUG_puts("3cupsGetOption: Returning NULL");
return (NULL);
}
match = cups_find_option(name, num_options, options, -1, &diff);
if (!diff)
{
DEBUG_printf(("3cupsGetOption: Returning \"%s\"", options[match].value));
return (options[match].value);
}
DEBUG_puts("3cupsGetOption: Returning NULL");
return (NULL);
}
int
cupsParseOptions(
const char *arg,
int num_options,
cups_option_t **options)
{
char *copyarg,
*ptr,
*name,
*value,
sep,
quote;
DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)",
arg, num_options, options));
if (!arg)
{
DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
return (num_options);
}
if (!options || num_options < 0)
{
DEBUG_puts("1cupsParseOptions: Returning 0");
return (0);
}
if ((copyarg = strdup(arg)) == NULL)
{
DEBUG_puts("1cupsParseOptions: Unable to copy arg string");
DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
return (num_options);
}
if (*copyarg == '{')
{
if ((ptr = copyarg + strlen(copyarg) - 1) > copyarg && *ptr == '}')
{
*ptr = '\0';
ptr = copyarg + 1;
}
else
ptr = copyarg;
}
else
ptr = copyarg;
while (_cups_isspace(*ptr))
ptr ++;
while (*ptr != '\0')
{
name = ptr;
while (!strchr("\f\n\r\t\v =", *ptr) && *ptr)
ptr ++;
if (ptr == name)
break;
while (_cups_isspace(*ptr))
*ptr++ = '\0';
if ((sep = *ptr) == '=')
*ptr++ = '\0';
DEBUG_printf(("2cupsParseOptions: name=\"%s\"", name));
if (sep != '=')
{
if (!strncasecmp(name, "no", 2))
num_options = cupsAddOption(name + 2, "false", num_options,
options);
else
num_options = cupsAddOption(name, "true", num_options, options);
continue;
}
value = ptr;
while (*ptr && !_cups_isspace(*ptr))
{
if (*ptr == ',')
ptr ++;
else if (*ptr == '\'' || *ptr == '\"')
{
quote = *ptr;
_cups_strcpy(ptr, ptr + 1);
while (*ptr != quote && *ptr)
{
if (*ptr == '\\' && ptr[1])
_cups_strcpy(ptr, ptr + 1);
ptr ++;
}
if (*ptr)
_cups_strcpy(ptr, ptr + 1);
}
else if (*ptr == '{')
{
int depth;
for (depth = 0; *ptr; ptr ++)
{
if (*ptr == '{')
depth ++;
else if (*ptr == '}')
{
depth --;
if (!depth)
{
ptr ++;
break;
}
}
else if (*ptr == '\\' && ptr[1])
_cups_strcpy(ptr, ptr + 1);
}
}
else
{
while (*ptr && !_cups_isspace(*ptr))
{
if (*ptr == '\\' && ptr[1])
_cups_strcpy(ptr, ptr + 1);
ptr ++;
}
}
}
if (*ptr != '\0')
*ptr++ = '\0';
DEBUG_printf(("2cupsParseOptions: value=\"%s\"", value));
while (_cups_isspace(*ptr))
ptr ++;
num_options = cupsAddOption(name, value, num_options, options);
}
free(copyarg);
DEBUG_printf(("1cupsParseOptions: Returning %d", num_options));
return (num_options);
}
int
cupsRemoveOption(
const char *name,
int num_options,
cups_option_t **options)
{
int i;
cups_option_t *option;
DEBUG_printf(("2cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)",
name, num_options, options));
if (!name || num_options < 1 || !options)
{
DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options));
return (num_options);
}
for (i = num_options, option = *options; i > 0; i --, option ++)
if (!strcasecmp(name, option->name))
break;
if (i)
{
DEBUG_puts("4cupsRemoveOption: Found option, removing it...");
num_options --;
i --;
_cupsStrFree(option->name);
_cupsStrFree(option->value);
if (i > 0)
memmove(option, option + 1, i * sizeof(cups_option_t));
}
DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options));
return (num_options);
}
static int
cups_compare_options(cups_option_t *a,
cups_option_t *b)
{
return (strcasecmp(a->name, b->name));
}
static int
cups_find_option(
const char *name,
int num_options,
cups_option_t *options,
int prev,
int *rdiff)
{
int left,
right,
current,
diff;
cups_option_t key;
DEBUG_printf(("7cups_find_option(name=\"%s\", num_options=%d, options=%p, "
"prev=%d, rdiff=%p)", name, num_options, options, prev,
rdiff));
#ifdef DEBUG
for (left = 0; left < num_options; left ++)
DEBUG_printf(("9cups_find_option: options[%d].name=\"%s\", .value=\"%s\"",
left, options[left].name, options[left].value));
#endif
key.name = (char *)name;
if (prev >= 0)
{
if ((diff = cups_compare_options(&key, options + prev)) == 0 ||
(diff < 0 && prev == 0) ||
(diff > 0 && prev == (num_options - 1)))
{
*rdiff = diff;
return (prev);
}
else if (diff < 0)
{
left = 0;
right = prev;
}
else
{
left = prev;
right = num_options - 1;
}
}
else
{
left = 0;
right = num_options - 1;
}
do
{
current = (left + right) / 2;
diff = cups_compare_options(&key, options + current);
if (diff == 0)
break;
else if (diff < 0)
right = current;
else
left = current;
}
while ((right - left) > 1);
if (diff != 0)
{
if ((diff = cups_compare_options(&key, options + left)) <= 0)
current = left;
else
{
diff = cups_compare_options(&key, options + right);
current = right;
}
}
*rdiff = diff;
return (current);
}