| /* Resolving ambiguity of argument lists: Information given through |
| command-line options. |
| 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-callshape.h" |
| |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "xalloc.h" |
| #include "xsize.h" |
| |
| |
| void |
| split_keywordspec (const char *spec, |
| const char **endp, struct callshape *shapep) |
| { |
| const char *p; |
| int argnum1 = 0; |
| int argnum2 = 0; |
| int argnumc = 0; |
| bool argnum1_glib_context = false; |
| bool argnum2_glib_context = false; |
| int argtotal = 0; |
| string_list_ty xcomments; |
| |
| string_list_init (&xcomments); |
| |
| /* Start parsing from the end. */ |
| p = spec + strlen (spec); |
| while (p > spec) |
| { |
| if (isdigit ((unsigned char) p[-1]) |
| || ((p[-1] == 'c' || p[-1] == 'g' || p[-1] == 't') |
| && p - 1 > spec && isdigit ((unsigned char) p[-2]))) |
| { |
| bool contextp = (p[-1] == 'c'); |
| bool glibp = (p[-1] == 'g'); |
| bool totalp = (p[-1] == 't'); |
| |
| do |
| p--; |
| while (p > spec && isdigit ((unsigned char) p[-1])); |
| |
| if (p > spec && (p[-1] == ',' || p[-1] == ':')) |
| { |
| char *dummy; |
| int arg = strtol (p, &dummy, 10); |
| |
| if (contextp) |
| { |
| if (argnumc != 0) |
| /* Only one context argument can be given. */ |
| break; |
| argnumc = arg; |
| } |
| else if (totalp) |
| { |
| if (argtotal != 0) |
| /* Only one total number of arguments can be given. */ |
| break; |
| argtotal = arg; |
| } |
| else |
| { |
| if (argnum2 != 0) |
| /* At most two normal arguments can be given. */ |
| break; |
| argnum2 = argnum1; |
| argnum2_glib_context = argnum1_glib_context; |
| argnum1 = arg; |
| argnum1_glib_context = glibp; |
| } |
| } |
| else |
| break; |
| } |
| else if (p[-1] == '"') |
| { |
| const char *xcomment_end; |
| |
| p--; |
| xcomment_end = p; |
| |
| while (p > spec && p[-1] != '"') |
| p--; |
| |
| if (p > spec /* && p[-1] == '"' */) |
| { |
| const char *xcomment_start; |
| |
| xcomment_start = p; |
| p--; |
| if (p > spec && (p[-1] == ',' || p[-1] == ':')) |
| { |
| size_t xcomment_len = xcomment_end - xcomment_start; |
| char *xcomment = XNMALLOC (xcomment_len + 1, char); |
| |
| memcpy (xcomment, xcomment_start, xcomment_len); |
| xcomment[xcomment_len] = '\0'; |
| string_list_append (&xcomments, xcomment); |
| } |
| else |
| break; |
| } |
| else |
| break; |
| } |
| else |
| break; |
| |
| /* Here an element of the comma-separated list has been parsed. */ |
| if (!(p > spec && (p[-1] == ',' || p[-1] == ':'))) |
| abort (); |
| p--; |
| if (*p == ':') |
| { |
| size_t i; |
| |
| if (argnum1 == 0 && argnum2 == 0) |
| /* At least one non-context argument must be given. */ |
| break; |
| if (argnumc != 0 |
| && (argnum1_glib_context || argnum2_glib_context)) |
| /* Incompatible ways to specify the context. */ |
| break; |
| *endp = p; |
| shapep->argnum1 = (argnum1 > 0 ? argnum1 : 1); |
| shapep->argnum2 = argnum2; |
| shapep->argnumc = argnumc; |
| shapep->argnum1_glib_context = argnum1_glib_context; |
| shapep->argnum2_glib_context = argnum2_glib_context; |
| shapep->argtotal = argtotal; |
| /* Reverse the order of the xcomments. */ |
| string_list_init (&shapep->xcomments); |
| for (i = xcomments.nitems; i > 0; ) |
| string_list_append (&shapep->xcomments, xcomments.item[--i]); |
| string_list_destroy (&xcomments); |
| return; |
| } |
| } |
| |
| /* Couldn't parse the desired syntax. */ |
| *endp = spec + strlen (spec); |
| shapep->argnum1 = 1; |
| shapep->argnum2 = 0; |
| shapep->argnumc = 0; |
| shapep->argnum1_glib_context = false; |
| shapep->argnum2_glib_context = false; |
| shapep->argtotal = 0; |
| string_list_init (&shapep->xcomments); |
| string_list_destroy (&xcomments); |
| } |
| |
| |
| void |
| insert_keyword_callshape (hash_table *table, |
| const char *keyword, size_t keyword_len, |
| const struct callshape *shape) |
| { |
| void *old_value; |
| |
| if (hash_find_entry (table, keyword, keyword_len, &old_value)) |
| { |
| /* Create a one-element 'struct callshapes'. */ |
| struct callshapes *shapes = XMALLOC (struct callshapes); |
| shapes->nshapes = 1; |
| shapes->shapes[0] = *shape; |
| keyword = |
| (const char *) hash_insert_entry (table, keyword, keyword_len, shapes); |
| if (keyword == NULL) |
| abort (); |
| shapes->keyword = keyword; |
| shapes->keyword_len = keyword_len; |
| } |
| else |
| { |
| /* Found a 'struct callshapes'. See whether it already contains the |
| desired shape. */ |
| struct callshapes *old_shapes = (struct callshapes *) old_value; |
| bool found; |
| size_t i; |
| |
| found = false; |
| for (i = 0; i < old_shapes->nshapes; i++) |
| if (old_shapes->shapes[i].argnum1 == shape->argnum1 |
| && old_shapes->shapes[i].argnum2 == shape->argnum2 |
| && old_shapes->shapes[i].argnumc == shape->argnumc |
| && old_shapes->shapes[i].argnum1_glib_context |
| == shape->argnum1_glib_context |
| && old_shapes->shapes[i].argnum2_glib_context |
| == shape->argnum2_glib_context |
| && old_shapes->shapes[i].argtotal == shape->argtotal) |
| { |
| old_shapes->shapes[i].xcomments = shape->xcomments; |
| found = true; |
| break; |
| } |
| |
| if (!found) |
| { |
| /* Replace the existing 'struct callshapes' with a new one. */ |
| struct callshapes *shapes = |
| (struct callshapes *) |
| xmalloc (xsum (sizeof (struct callshapes), |
| xtimes (old_shapes->nshapes, |
| sizeof (struct callshape)))); |
| |
| shapes->keyword = old_shapes->keyword; |
| shapes->keyword_len = old_shapes->keyword_len; |
| shapes->nshapes = old_shapes->nshapes + 1; |
| for (i = 0; i < old_shapes->nshapes; i++) |
| shapes->shapes[i] = old_shapes->shapes[i]; |
| shapes->shapes[i] = *shape; |
| if (hash_set_value (table, keyword, keyword_len, shapes)) |
| abort (); |
| free (old_shapes); |
| } |
| } |
| } |