blob: 68feba5824d1822e1498fc79dbb239a0f999ffe6 [file] [log] [blame]
/* Keeping track of the flags that apply to a string extracted
in a certain context.
Copyright (C) 2001-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/* Specification. */
#include "xg-arglist-context.h"
#include <stdlib.h>
#include "xalloc.h"
#include "xmalloca.h"
/* Null context. */
flag_context_ty null_context = { undecided, false, undecided, false };
/* Transparent context. */
flag_context_ty passthrough_context = { undecided, true, undecided, true };
flag_context_ty
inherited_context (flag_context_ty outer_context,
flag_context_ty modifier_context)
{
flag_context_ty result = modifier_context;
if (result.pass_format1)
{
result.is_format1 = outer_context.is_format1;
result.pass_format1 = false;
}
if (result.pass_format2)
{
result.is_format2 = outer_context.is_format2;
result.pass_format2 = false;
}
if (result.pass_format3)
{
result.is_format3 = outer_context.is_format3;
result.pass_format3 = false;
}
return result;
}
/* Null context list iterator. */
flag_context_list_iterator_ty null_context_list_iterator = { 1, NULL };
/* Transparent context list iterator. */
static flag_context_list_ty passthrough_context_circular_list =
{
1,
{ undecided, true, undecided, true },
&passthrough_context_circular_list
};
flag_context_list_iterator_ty passthrough_context_list_iterator =
{
1,
&passthrough_context_circular_list
};
flag_context_list_iterator_ty
flag_context_list_iterator (flag_context_list_ty *list)
{
flag_context_list_iterator_ty result;
result.argnum = 1;
result.head = list;
return result;
}
flag_context_ty
flag_context_list_iterator_advance (flag_context_list_iterator_ty *iter)
{
if (iter->head == NULL)
return null_context;
if (iter->argnum == iter->head->argnum)
{
flag_context_ty result = iter->head->flags;
/* Special casing of circular list. */
if (iter->head != iter->head->next)
{
iter->head = iter->head->next;
iter->argnum++;
}
return result;
}
else
{
iter->argnum++;
return null_context;
}
}
flag_context_list_ty *
flag_context_list_table_lookup (flag_context_list_table_ty *flag_table,
const void *key, size_t keylen)
{
void *entry;
if (flag_table->table != NULL
&& hash_find_entry (flag_table, key, keylen, &entry) == 0)
return (flag_context_list_ty *) entry;
else
return NULL;
}
void
flag_context_list_table_add (flag_context_list_table_ty *table,
unsigned int index,
const char *name_start, const char *name_end,
int argnum, enum is_format value, bool pass)
{
/* Insert the pair (VALUE, PASS) at INDEX in the element numbered ARGNUM
of the list corresponding to NAME in the TABLE. */
if (table->table == NULL)
hash_init (table, 100);
{
void *entry;
if (hash_find_entry (table, name_start, name_end - name_start, &entry) != 0)
{
/* Create new hash table entry. */
flag_context_list_ty *list = XMALLOC (flag_context_list_ty);
list->argnum = argnum;
memset (&list->flags, '\0', sizeof (list->flags));
switch (index)
{
case 0:
list->flags.is_format1 = value;
list->flags.pass_format1 = pass;
break;
case 1:
list->flags.is_format2 = value;
list->flags.pass_format2 = pass;
break;
case 2:
list->flags.is_format3 = value;
list->flags.pass_format3 = pass;
break;
default:
abort ();
}
list->next = NULL;
hash_insert_entry (table, name_start, name_end - name_start, list);
}
else
{
flag_context_list_ty *list = (flag_context_list_ty *)entry;
flag_context_list_ty **lastp = NULL;
/* Invariant: list == (lastp != NULL ? *lastp : entry). */
while (list != NULL && list->argnum < argnum)
{
lastp = &list->next;
list = *lastp;
}
if (list != NULL && list->argnum == argnum)
{
/* Add this flag to the current argument number. */
switch (index)
{
case 0:
list->flags.is_format1 = value;
list->flags.pass_format1 = pass;
break;
case 1:
list->flags.is_format2 = value;
list->flags.pass_format2 = pass;
break;
case 2:
list->flags.is_format3 = value;
list->flags.pass_format3 = pass;
break;
default:
abort ();
}
}
else if (lastp != NULL)
{
/* Add a new list entry for this argument number. */
list = XMALLOC (flag_context_list_ty);
list->argnum = argnum;
memset (&list->flags, '\0', sizeof (list->flags));
switch (index)
{
case 0:
list->flags.is_format1 = value;
list->flags.pass_format1 = pass;
break;
case 1:
list->flags.is_format2 = value;
list->flags.pass_format2 = pass;
break;
case 2:
list->flags.is_format3 = value;
list->flags.pass_format3 = pass;
break;
default:
abort ();
}
list->next = *lastp;
*lastp = list;
}
else
{
/* Add a new list entry for this argument number, at the beginning
of the list. Since we don't have an API for replacing the
value of a key in the hash table, we have to copy the first
list element. */
flag_context_list_ty *copy = XMALLOC (flag_context_list_ty);
*copy = *list;
list->argnum = argnum;
memset (&list->flags, '\0', sizeof (list->flags));
switch (index)
{
case 0:
list->flags.is_format1 = value;
list->flags.pass_format1 = pass;
break;
case 1:
list->flags.is_format2 = value;
list->flags.pass_format2 = pass;
break;
case 2:
list->flags.is_format3 = value;
list->flags.pass_format3 = pass;
break;
default:
abort ();
}
list->next = copy;
}
}
}
}