Motr  M0
string.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2015-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #include "lib/errno.h"
24 #include "lib/assert.h"
25 #include "lib/memory.h"
26 #include "lib/arith.h" /* min64 */
27 #include "lib/string.h" /* sscanf */
28 
29 #include "xcode/xcode.h"
30 
31 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_XCODE
32 #include "lib/trace.h"
33 
40 /* xcode.c */
41 M0_EXTERN ssize_t
43  void *(*alloc)(struct m0_xcode_cursor *, size_t));
44 
45 M0_INTERNAL const char *space_skip(const char *str)
46 {
47  static const char space[] = " \t\v\n\r";
48  const char *s0;
49 
50  do {
51  s0 = str;
52  while (*str != 0 && strchr(space, *str) != NULL)
53  str++;
54 
55  if (*str == '#') {
56  while (*str != 0 && *str != '\n')
57  str++;
58  }
59  } while (s0 != str);
60  return str;
61 }
62 
63 static int string_literal(const struct m0_xcode_cursor *it,
64  struct m0_xcode_obj *obj, const char *str)
65 {
66  uint64_t len;
67  const char *eol;
68  char *mem;
69  const struct m0_xcode_type *count_type;
70 
71  count_type = obj->xo_type->xct_child[0].xf_type;
72  if (count_type == &M0_XT_VOID) {
73  /* fixed length string */
74  len = m0_xcode_tag(obj);
75  } else {
76  eol = strchr(str, '"');
77  if (eol == NULL)
78  return M0_ERR(-EPROTO);
79  len = eol - str;
80  switch (count_type->xct_atype) {
81  case M0_XAT_U8:
82  *M0_XCODE_VAL(obj, 0, 0, uint8_t) = (uint8_t)len;
83  break;
84  case M0_XAT_U32:
85  *M0_XCODE_VAL(obj, 0, 0, uint32_t) = (uint32_t)len;
86  break;
87  case M0_XAT_U64:
88  *M0_XCODE_VAL(obj, 0, 0, uint64_t) = (uint64_t)len;
89  break;
90  default:
91  M0_IMPOSSIBLE("Invalid counter type.");
92  }
93  }
94 
95  if (len == 0)
96  return 1; /* Including closing '"'. */
97 
98  *(void **)m0_xcode_addr(obj, 1, ~0ULL) = mem = m0_alloc(len);
99  if (mem != NULL) {
100  memcpy(mem, str, len);
101  return len + 1;
102  } else
103  return M0_ERR(-ENOMEM);
104 }
105 
106 static int (*field_reader(const struct m0_xcode_cursor *it))
107  (const struct m0_xcode_cursor *,
108  struct m0_xcode_obj *, const char *)
109 {
110  const struct m0_xcode_field *field = m0_xcode_cursor_field(it);
111  return field != NULL ? field->xf_read : NULL;
112 }
113 
114 static int char_check(const char **str, char ch)
115 {
116  if (ch != 0) {
117  if (**str != ch)
118  return M0_ERR_INFO(-EPROTO, "ch='%c' str=`%.80s...'",
119  ch, *str);
120  (*str)++;
121  *str = space_skip(*str);
122  }
123  return 0;
124 }
125 
126 static const char structure[M0_XA_NR][M0_XCODE_CURSOR_NR] = {
127  /* NONE PRE IN POST */
128  [M0_XA_RECORD] = { 0, '(', 0, ')' },
129  [M0_XA_UNION] = { 0, '{', 0, '}' },
130  [M0_XA_SEQUENCE] = { 0, '[', 0, ']' },
131  [M0_XA_ARRAY] = { 0, '<', 0, '>' },
132  [M0_XA_TYPEDEF] = { 0, 0, 0, 0 },
133  [M0_XA_OPAQUE] = { 0, 0, 0, 0 },
134  [M0_XA_ATOM] = { 0, 0, 0, 0 }
135 };
136 
137 static const char punctuation[M0_XA_NR][3] = {
138  /* 1st 2nd later */
139  [M0_XA_RECORD] = { 0, ',', ',' },
140  [M0_XA_UNION] = { 0, '|', 0 },
141  [M0_XA_SEQUENCE] = { 0, ':', ',' },
142  [M0_XA_ARRAY] = { 0, ',', ',' },
143  [M0_XA_TYPEDEF] = { 0, 0, 0 },
144  [M0_XA_OPAQUE] = { 0, 0, 0 },
145  [M0_XA_ATOM] = { 0, 0, 0 }
146 };
147 
148 static char punctchar(struct m0_xcode_cursor *it)
149 {
150  struct m0_xcode_cursor_frame *pre = m0_xcode_cursor_top(it) - 1;
151  enum m0_xcode_aggr par;
152  int order;
153 
154  if (it->xcu_depth > 0) {
155  order = min64(pre->s_datum++, ARRAY_SIZE(punctuation[0]) - 1);
156  par = pre->s_obj.xo_type->xct_aggr;
157  return punctuation[par][order];
158  } else
159  return 0;
160 }
161 
162 M0_INTERNAL int m0_xcode_read(struct m0_xcode_obj *obj, const char *str)
163 {
164  struct m0_xcode_cursor it;
165  int result;
166 
167  static const char *fmt[M0_XAT_NR] = {
168  [M0_XAT_VOID] = " %0c %n",
169  [M0_XAT_U8] = " %i %n",
170  [M0_XAT_U32] = " %i %n",
171  [M0_XAT_U64] = " %li %n"
172  };
173 
174  /* check that formats above are valid. */
175  M0_CASSERT(sizeof(uint64_t) == sizeof(unsigned long));
176  M0_CASSERT(sizeof(uint32_t) == sizeof(unsigned));
177 
179 
180  while ((result = m0_xcode_next(&it)) > 0) {
181  struct m0_xcode_cursor_frame *top = m0_xcode_cursor_top(&it);
182  struct m0_xcode_obj *cur = &top->s_obj;
183  enum m0_xcode_cursor_flag flag = top->s_flag;
184  const struct m0_xcode_type *xt = cur->xo_type;
185  enum m0_xcode_aggr aggr = xt->xct_aggr;
186 
187  str = space_skip(str);
188  if (flag == M0_XCODE_CURSOR_PRE) {
189  int (*custom)(const struct m0_xcode_cursor *,
190  struct m0_xcode_obj *, const char *);
191 
193  if (result != 0)
194  return result;
195  result = char_check(&str, punctchar(&it));
196  if (result != 0)
197  return result;
198  custom = *str == '"' && m0_xcode_is_byte_array(xt) ?
199  &string_literal :
200  *str == '^' && xt->xct_ops != NULL ?
201  xt->xct_ops->xto_read :
202  *str == '@' ? field_reader(&it) : NULL;
203  if (custom != NULL) {
204  /*
205  * A string literal (skip opening '"'), a custom
206  * type reader (skip opening '^') or a custom
207  * field reader (skip opening '@').
208  */
209  ++str;
210  result = custom(&it, cur, str);
211  if (result < 0)
212  return result;
213  str += result;
214  m0_xcode_skip(&it);
215  continue;
216  }
217  }
218  result = char_check(&str, structure[aggr][flag]);
219  if (result != 0)
220  return result;
221  if (flag == M0_XCODE_CURSOR_PRE && aggr == M0_XA_ATOM) {
222  int nob;
223  int nr;
224  unsigned bval = 0;
225  void *pval;
226 
227  /*
228  * according to format, a byte goes to 4-byte bval, but
229  * not directly to allocated buffer (i.e. cur->xo_ptr)
230  */
231  pval = xt->xct_atype == M0_XAT_U8 ? &bval : cur->xo_ptr;
232  nr = sscanf(str, fmt[xt->xct_atype], pval, &nob);
233  if (xt->xct_atype == M0_XAT_U8) {
234  if (bval < 0x100)
235  *(uint8_t *)cur->xo_ptr = (uint8_t)bval;
236  else
237  return M0_ERR(-EOVERFLOW);
238  }
239  /*
240  * WARNING
241  *
242  * The C standard says: "Execution of a %n directive
243  * does not increment the assignment count returned
244  * at the completion of execution" but the
245  * Corrigendum seems to contradict this. Probably
246  * it is wise not to make any assumptions on the
247  * effect of %n conversions on the return value.
248  *
249  * -- man 3 sscanf
250  *
251  * glibc-2.11.2 and Linux kernel do not increment. See
252  * NO_BUG_IN_ISO_C_CORRIGENDUM_1 in
253  * glibc/stdio-common/vfscanf.c.
254  */
255  if (nr != 1)
256  return M0_ERR(-EPROTO);
257  str += nob;
258  }
259  }
260  return *str == 0 ? 0 : M0_ERR(-EINVAL);
261 }
262 
263 static bool quoted_string(const struct m0_xcode_type *xt,
264  const struct m0_xcode_obj *obj,
265  struct m0_fop_str *qstr)
266 {
267  if (m0_xcode_is_byte_array(xt)) {
268  qstr->s_len = m0_xcode_tag(obj);
269  qstr->s_buf = m0_xcode_addr(obj, 1, 0);
270 
271  /* A crude printability check. */
272  return m0_forall(i, qstr->s_len,
273  qstr->s_buf[i] >= ' ' && qstr->s_buf[i] <= '~');
274  } else
275  return false;
276 }
277 
278 M0_INTERNAL int m0_xcode_print(const struct m0_xcode_obj *obj,
279  char *str, int nr)
280 {
281  struct m0_xcode_cursor it;
282  int result;
283  int nob = 0;
284 
286 
287 #define P(...) \
288  ({ nob += snprintf(str + nob, max64(nr - nob, 0), __VA_ARGS__); })
289 #define PCHAR(ch) ({ char _ch = (ch); if (_ch != 0) P("%c", _ch); })
290 
291  while ((result = m0_xcode_next(&it)) > 0) {
292  struct m0_xcode_cursor_frame *top = m0_xcode_cursor_top(&it);
293  struct m0_xcode_obj *cur = &top->s_obj;
294  enum m0_xcode_cursor_flag flag = top->s_flag;
295  const struct m0_xcode_type *xt = cur->xo_type;
296  enum m0_xcode_aggr aggr = xt->xct_aggr;
297  struct m0_fop_str qstr;
298 
299  if (flag == M0_XCODE_CURSOR_PRE)
300  PCHAR(punctchar(&it));
301 
302  if (quoted_string(xt, cur, &qstr)) {
303  P("\"%.*s\"", qstr.s_len, qstr.s_buf);
304  m0_xcode_skip(&it);
305  continue;
306  }
307  PCHAR(structure[aggr][flag]);
308 
309  if (flag == M0_XCODE_CURSOR_PRE && aggr == M0_XA_ATOM)
310  P("%#lx", (unsigned long)m0_xcode_atom(cur));
311  }
312  return result ?: nob;
313 #undef PCHAR
314 #undef P
315 }
316 
317 #undef M0_TRACE_SUBSYSTEM
318 
321 /*
322  * Local variables:
323  * c-indentation-style: "K&R"
324  * c-basic-offset: 8
325  * tab-width: 8
326  * fill-column: 80
327  * scroll-step: 1
328  * End:
329  */
M0_INTERNAL struct m0_xcode_cursor_frame * m0_xcode_cursor_top(struct m0_xcode_cursor *it)
Definition: cursor.c:41
M0_INTERNAL void * m0_xcode_addr(const struct m0_xcode_obj *obj, int fileno, uint64_t elno)
Definition: xcode.c:612
M0_INTERNAL int m0_xcode_print(const struct m0_xcode_obj *obj, char *str, int nr)
Definition: string.c:278
static size_t nr
Definition: dump.c:1505
M0_EXTERN ssize_t m0_xcode_alloc_obj(struct m0_xcode_cursor *it, void *(*alloc)(struct m0_xcode_cursor *, size_t))
Definition: xcode.c:228
#define NULL
Definition: misc.h:38
static struct buffer * cur(struct m0_addb2_mach *mach, m0_bcount_t space)
Definition: addb2.c:791
M0_INTERNAL int m0_xcode_read(struct m0_xcode_obj *obj, const char *str)
Definition: string.c:162
#define M0_CASSERT(cond)
m0_xcode_aggr
Definition: xcode.h:164
static char punctchar(struct m0_xcode_cursor *it)
Definition: string.c:148
static struct m0_be_emap_cursor it
Definition: extmap.c:46
Definition: xcode.c:59
const struct m0_xcode_type_ops * xct_ops
Definition: xcode.h:320
static struct m0_xcode_type ** xt[]
Definition: protocol.c:64
M0_INTERNAL const char * space_skip(const char *str)
Definition: string.c:45
static struct foo * obj
Definition: tlist.c:302
static int char_check(const char **str, char ch)
Definition: string.c:114
static bool quoted_string(const struct m0_xcode_type *xt, const struct m0_xcode_obj *obj, struct m0_fop_str *qstr)
Definition: string.c:263
int i
Definition: dir.c:1033
static int string_literal(const struct m0_xcode_cursor *it, struct m0_xcode_obj *obj, const char *str)
Definition: string.c:63
int(* xto_read)(const struct m0_xcode_cursor *it, struct m0_xcode_obj *obj, const char *str)
Definition: xcode.h:379
#define M0_ERR_INFO(rc, fmt,...)
Definition: trace.h:215
M0_INTERNAL bool m0_xcode_is_byte_array(const struct m0_xcode_type *xt)
Definition: xcode.c:221
return M0_ERR(-EOPNOTSUPP)
M0_INTERNAL uint64_t m0_xcode_tag(const struct m0_xcode_obj *obj)
Definition: xcode.c:679
uint8_t * s_buf
Definition: string.h:72
static int field(struct ff2c_context *ctx, struct ff2c_term *term)
Definition: parser.c:84
enum m0_xode_atom_type xct_atype
Definition: xcode.h:326
const struct m0_xcode_type M0_XT_VOID
Definition: xcode.c:916
static struct ff2c_term * alloc(void)
Definition: parser.c:37
char * fmt(const char *format,...) __attribute__((format(printf
void * m0_alloc(size_t size)
Definition: memory.c:126
M0_INTERNAL int m0_xcode_next(struct m0_xcode_cursor *it)
Definition: cursor.c:59
M0_INTERNAL void * m0_xcode_alloc(struct m0_xcode_cursor *it, size_t nob)
Definition: xcode.c:444
M0_INTERNAL uint64_t m0_xcode_atom(const struct m0_xcode_obj *obj)
Definition: xcode.c:652
#define m0_forall(var, nr,...)
Definition: misc.h:112
M0_INTERNAL void m0_xcode_cursor_init(struct m0_xcode_cursor *it, const struct m0_xcode_obj *obj)
Definition: cursor.c:33
enum m0_xcode_aggr xct_aggr
Definition: xcode.h:316
m0_xcode_cursor_flag
Definition: xcode.h:408
#define PCHAR(ch)
static int64_t min64(int64_t a, int64_t b)
Definition: arith.h:46
static bool flag
Definition: nucleus.c:266
#define P(...)
M0_INTERNAL void m0_xcode_skip(struct m0_xcode_cursor *it)
Definition: cursor.c:148
M0_INTERNAL const struct m0_xcode_field * m0_xcode_cursor_field(const struct m0_xcode_cursor *it)
Definition: cursor.c:48
uint32_t s_len
Definition: string.h:71
#define M0_XCODE_VAL(obj, fieldno, elno, __type)
Definition: xcode.h:821
static int(*)(const struct m0_xcode_cursor *, struct m0_xcode_obj *, const char *) field_reader(const struct m0_xcode_cursor *it)
Definition: string.c:106
static const char punctuation[M0_XA_NR][3]
Definition: string.c:137
#define ARRAY_SIZE(a)
Definition: misc.h:45
static const char structure[M0_XA_NR][M0_XCODE_CURSOR_NR]
Definition: string.c:126
#define M0_IMPOSSIBLE(fmt,...)