/* 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 . */ #ifdef HAVE_CONFIG_H # include #endif /* Specification. */ #include "xg-arglist-context.h" #include #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; } } } }