Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1186 | savelij | 1 | /* striter.c */ |
2 | /*****************************************************************************/ |
||
3 | /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ |
||
4 | /* */ |
||
5 | /* AS */ |
||
6 | /* */ |
||
7 | /* String Iteration */ |
||
8 | /* */ |
||
9 | /*****************************************************************************/ |
||
10 | |||
11 | #include "striter.h" |
||
12 | |||
13 | /* iterator state variables, used in loop */ |
||
14 | |||
15 | typedef struct |
||
16 | { |
||
17 | Boolean this_escaped, next_escaped; |
||
18 | } iter_data_t; |
||
19 | |||
20 | /*!------------------------------------------------------------------------ |
||
21 | * \fn iterate_quote_core(const char *p_run, as_quoted_iterator_cb_data_t *p_cb_data, iter_data_t *p_iter_data) |
||
22 | * \brief common quoting/escaping character handling while iterating string |
||
23 | * \param p_run current position in string |
||
24 | * \param p_cb_data, p_iter_data iteration callback |
||
25 | * \return True if this was a special character |
||
26 | * ------------------------------------------------------------------------ */ |
||
27 | |||
28 | static Boolean iterate_quote_core(const char *p_run, as_quoted_iterator_cb_data_t *p_cb_data, iter_data_t *p_iter_data) |
||
29 | { |
||
30 | p_iter_data->next_escaped = False; |
||
31 | switch(*p_run) |
||
32 | { |
||
33 | case '\\': |
||
34 | if ((p_cb_data->in_single_quote || p_cb_data->in_double_quote) && !p_iter_data->this_escaped) |
||
35 | p_iter_data->next_escaped = True; |
||
36 | return True; |
||
37 | case '\'': |
||
38 | if (p_cb_data->in_double_quote) { } |
||
39 | else if (!p_cb_data->in_single_quote && (!p_cb_data->qualify_quote || p_cb_data->qualify_quote(p_cb_data->p_str, p_run))) |
||
40 | p_cb_data->in_single_quote = True; |
||
41 | else if (!p_iter_data->this_escaped) /* skip escaped ' in '...' */ |
||
42 | p_cb_data->in_single_quote = False; |
||
43 | return True; |
||
44 | case '"': |
||
45 | if (p_cb_data->in_single_quote) { } |
||
46 | else if (!p_cb_data->in_double_quote) |
||
47 | p_cb_data->in_double_quote = True; |
||
48 | else if (!p_iter_data->this_escaped) /* skip escaped " in "..." */ |
||
49 | p_cb_data->in_double_quote = False; |
||
50 | return True; |
||
51 | default: |
||
52 | return False; |
||
53 | } |
||
54 | } |
||
55 | |||
56 | /*!------------------------------------------------------------------------ |
||
57 | * \fn as_iterate_str(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data) |
||
58 | * \brief iterate through string, detecting quoted areas |
||
59 | * \param p_str string to iterate through |
||
60 | * \param callback is called for all characters outside quoted areas |
||
61 | * \param p_cb_data callback data |
||
62 | * ------------------------------------------------------------------------ */ |
||
63 | |||
64 | void as_iterate_str(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data) |
||
65 | { |
||
66 | iter_data_t iter_data; |
||
67 | int n_extra_skip; |
||
68 | const char *p_run; |
||
69 | |||
70 | p_cb_data->p_str = p_str; |
||
71 | p_cb_data->in_single_quote = |
||
72 | p_cb_data->in_double_quote = False; |
||
73 | |||
74 | for (p_run = p_str, iter_data.this_escaped = False; |
||
75 | *p_run; |
||
76 | p_run += (1 + n_extra_skip), iter_data.this_escaped = iter_data.next_escaped) |
||
77 | { |
||
78 | n_extra_skip = 0; |
||
79 | |||
80 | (void)iterate_quote_core(p_run, p_cb_data, &iter_data); |
||
81 | n_extra_skip = callback(p_run, p_cb_data); |
||
82 | if (n_extra_skip < 0) |
||
83 | return; |
||
84 | } |
||
85 | } |
||
86 | |||
87 | /*!------------------------------------------------------------------------ |
||
88 | * \fn as_iterate_str_quoted(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data) |
||
89 | * \brief iterate through string, skipping quoted areas |
||
90 | * \param p_str string to iterate through |
||
91 | * \param callback is called for all characters outside quoted areas |
||
92 | * \param p_cb_data callback data |
||
93 | * ------------------------------------------------------------------------ */ |
||
94 | |||
95 | void as_iterate_str_quoted(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data) |
||
96 | { |
||
97 | iter_data_t iter_data; |
||
98 | int n_extra_skip; |
||
99 | const char *p_run; |
||
100 | |||
101 | p_cb_data->p_str = p_str; |
||
102 | p_cb_data->in_single_quote = |
||
103 | p_cb_data->in_double_quote = False; |
||
104 | |||
105 | for (p_run = p_str, iter_data.this_escaped = False; |
||
106 | *p_run; |
||
107 | p_run += (1 + n_extra_skip), iter_data.this_escaped = iter_data.next_escaped) |
||
108 | { |
||
109 | if (p_cb_data->callback_before && !p_cb_data->in_single_quote && !p_cb_data->in_double_quote) |
||
110 | { |
||
111 | n_extra_skip = callback(p_run, p_cb_data); |
||
112 | if (n_extra_skip < 0) |
||
113 | return; |
||
114 | } |
||
115 | else |
||
116 | n_extra_skip = 0; |
||
117 | |||
118 | if (!iterate_quote_core(p_run, p_cb_data, &iter_data) |
||
119 | && !p_cb_data->callback_before |
||
120 | && !p_cb_data->in_single_quote |
||
121 | && !p_cb_data->in_double_quote) |
||
122 | { |
||
123 | n_extra_skip = callback(p_run, p_cb_data); |
||
124 | if (n_extra_skip < 0) |
||
125 | return; |
||
126 | } |
||
127 | } |
||
128 | } |