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 #include "fop/wire.h" /* m0_fop_str */
31 
32 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_XCODE
33 #include "lib/trace.h"
34 
41 /* xcode.c */
42 M0_EXTERN ssize_t
44  void *(*alloc)(struct m0_xcode_cursor *, size_t));
45 
46 M0_INTERNAL const char *space_skip(const char *str)
47 {
48  static const char space[] = " \t\v\n\r";
49  const char *s0;
50 
51  do {
52  s0 = str;
53  while (*str != 0 && strchr(space, *str) != NULL)
54  str++;
55 
56  if (*str == '#') {
57  while (*str != 0 && *str != '\n')
58  str++;
59  }
60  } while (s0 != str);
61  return str;
62 }
63 
64 static int string_literal(const struct m0_xcode_cursor *it,
65  struct m0_xcode_obj *obj, const char *str)
66 {
67  uint64_t len;
68  const char *eol;
69  char *mem;
70  const struct m0_xcode_type *count_type;
71 
72  count_type = obj->xo_type->xct_child[0].xf_type;
73  if (count_type == &M0_XT_VOID) {
74  /* fixed length string */
75  len = m0_xcode_tag(obj);
76  } else {
77  eol = strchr(str, '"');
78  if (eol == NULL)
79  return M0_ERR(-EPROTO);
80  len = eol - str;
81  switch (count_type->xct_atype) {
82  case M0_XAT_U8:
83  *M0_XCODE_VAL(obj, 0, 0, uint8_t) = (uint8_t)len;
84  break;
85  case M0_XAT_U32:
86  *M0_XCODE_VAL(obj, 0, 0, uint32_t) = (uint32_t)len;
87  break;
88  case M0_XAT_U64:
89  *M0_XCODE_VAL(obj, 0, 0, uint64_t) = (uint64_t)len;
90  break;
91  default:
92  M0_IMPOSSIBLE("Invalid counter type.");
93  }
94  }
95 
96  if (len == 0)
97  return 1; /* Including closing '"'. */
98 
99  *(void **)m0_xcode_addr(obj, 1, ~0ULL) = mem = m0_alloc(len);
100  if (mem != NULL) {
101  memcpy(mem, str, len);
102  return len + 1;
103  } else
104  return M0_ERR(-ENOMEM);
105 }
106 
107 static int (*field_reader(const struct m0_xcode_cursor *it))
108  (const struct m0_xcode_cursor *,
109  struct m0_xcode_obj *, const char *)
110 {
111  const struct m0_xcode_field *field = m0_xcode_cursor_field(it);
112  return field != NULL ? field->xf_read : NULL;
113 }
114 
115 static int char_check(const char **str, char ch)
116 {
117  if (ch != 0) {
118  if (**str != ch)
119  return M0_ERR_INFO(-EPROTO, "ch='%c' str=`%.80s...'",
120  ch, *str);
121  (*str)++;
122  *str = space_skip(*str);
123  }
124  return 0;
125 }
126 
127 static const char structure[M0_XA_NR][M0_XCODE_CURSOR_NR] = {
128  /* NONE PRE IN POST */
129  [M0_XA_RECORD] = { 0, '(', 0, ')' },
130  [M0_XA_UNION] = { 0, '{', 0, '}' },
131  [M0_XA_SEQUENCE] = { 0, '[', 0, ']' },
132  [M0_XA_ARRAY] = { 0, '<', 0, '>' },
133  [M0_XA_TYPEDEF] = { 0, 0, 0, 0 },
134  [M0_XA_OPAQUE] = { 0, 0, 0, 0 },
135  [M0_XA_ATOM] = { 0, 0, 0, 0 }
136 };
137 
138 static const char punctuation[M0_XA_NR][3] = {
139  /* 1st 2nd later */
140  [M0_XA_RECORD] = { 0, ',', ',' },
141  [M0_XA_UNION] = { 0, '|', 0 },
142  [M0_XA_SEQUENCE] = { 0, ':', ',' },
143  [M0_XA_ARRAY] = { 0, ',', ',' },
144  [M0_XA_TYPEDEF] = { 0, 0, 0 },
145  [M0_XA_OPAQUE] = { 0, 0, 0 },
146  [M0_XA_ATOM] = { 0, 0, 0 }
147 };
148 
149 static char punctchar(struct m0_xcode_cursor *it)
150 {
151  struct m0_xcode_cursor_frame *pre = m0_xcode_cursor_top(it) - 1;
152  enum m0_xcode_aggr par;
153  int order;
154 
155  if (it->xcu_depth > 0) {
156  order = min64(pre->s_datum++, ARRAY_SIZE(punctuation[0]) - 1);
157  par = pre->s_obj.xo_type->xct_aggr;
158  return punctuation[par][order];
159  } else
160  return 0;
161 }
162 
163 M0_INTERNAL int m0_xcode_read(struct m0_xcode_obj *obj, const char *str)
164 {
165  struct m0_xcode_cursor it;
166  int result;
167 
168  static const char *fmt[M0_XAT_NR] = {
169  [M0_XAT_VOID] = " %0c %n",
170  [M0_XAT_U8] = " %i %n",
171  [M0_XAT_U32] = " %i %n",
172  [M0_XAT_U64] = " %li %n"
173  };
174 
175  /* check that formats above are valid. */
176  M0_CASSERT(sizeof(uint64_t) == sizeof(unsigned long));
177  M0_CASSERT(sizeof(uint32_t) == sizeof(unsigned));
178 
180 
181  while ((result = m0_xcode_next(&it)) > 0) {
182  struct m0_xcode_cursor_frame *top = m0_xcode_cursor_top(&it);
183  struct m0_xcode_obj *cur = &top->s_obj;
184  enum m0_xcode_cursor_flag flag = top->s_flag;
185  const struct m0_xcode_type *xt = cur->xo_type;
186  enum m0_xcode_aggr aggr = xt->xct_aggr;
187 
188  str = space_skip(str);
189  if (flag == M0_XCODE_CURSOR_PRE) {
190  int (*custom)(const struct m0_xcode_cursor *,
191  struct m0_xcode_obj *, const char *);
192 
194  if (result != 0)
195  return result;
196  result = char_check(&str, punctchar(&it));
197  if (result != 0)
198  return result;
199  custom = *str == '"' && m0_xcode_is_byte_array(xt) ?
200  &string_literal :
201  *str == '^' && xt->xct_ops != NULL ?
202  xt->xct_ops->xto_read :
203  *str == '@' ? field_reader(&it) : NULL;
204  if (custom != NULL) {
205  /*
206  * A string literal (skip opening '"'), a custom
207  * type reader (skip opening '^') or a custom
208  * field reader (skip opening '@').
209  */
210  ++str;
211  result = custom(&it, cur, str);
212  if (result < 0)
213  return result;
214  str += result;
215  m0_xcode_skip(&it);
216  continue;
217  }
218  }
219  result = char_check(&str, structure[aggr][flag]);
220  if (result != 0)
221  return result;
222  if (flag == M0_XCODE_CURSOR_PRE && aggr == M0_XA_ATOM) {
223  int nob;
224  int nr;
225  unsigned bval = 0;
226  void *pval;
227 
228  /*
229  * according to format, a byte goes to 4-byte bval, but
230  * not directly to allocated buffer (i.e. cur->xo_ptr)
231  */
232  pval = xt->xct_atype == M0_XAT_U8 ? &bval : cur->xo_ptr;
233  nr = sscanf(str, fmt[xt->xct_atype], pval, &nob);
234  if (xt->xct_atype == M0_XAT_U8) {
235  if (bval < 0x100)
236  *(uint8_t *)cur->xo_ptr = (uint8_t)bval;
237  else
238  return M0_ERR(-EOVERFLOW);
239  }
240  /*
241  * WARNING
242  *
243  * The C standard says: "Execution of a %n directive
244  * does not increment the assignment count returned
245  * at the completion of execution" but the
246  * Corrigendum seems to contradict this. Probably
247  * it is wise not to make any assumptions on the
248  * effect of %n conversions on the return value.
249  *
250  * -- man 3 sscanf
251  *
252  * glibc-2.11.2 and Linux kernel do not increment. See
253  * NO_BUG_IN_ISO_C_CORRIGENDUM_1 in
254  * glibc/stdio-common/vfscanf.c.
255  */
256  if (nr != 1)
257  return M0_ERR(-EPROTO);
258  str += nob;
259  }
260  }
261  return *str == 0 ? 0 : M0_ERR(-EINVAL);
262 }
263 
264 static bool quoted_string(const struct m0_xcode_type *xt,
265  const struct m0_xcode_obj *obj,
266  struct m0_fop_str *qstr)
267 {
268  if (m0_xcode_is_byte_array(xt)) {
269  qstr->s_len = m0_xcode_tag(obj);
270  qstr->s_buf = m0_xcode_addr(obj, 1, 0);
271 
272  /* A crude printability check. */
273  return m0_forall(i, qstr->s_len,
274  qstr->s_buf[i] >= ' ' && qstr->s_buf[i] <= '~');
275  } else
276  return false;
277 }
278 
279 M0_INTERNAL int m0_xcode_print(const struct m0_xcode_obj *obj,
280  char *str, int nr)
281 {
282  struct m0_xcode_cursor it;
283  int result;
284  int nob = 0;
285 
287 
288 #define P(...) \
289  ({ nob += snprintf(str + nob, max64(nr - nob, 0), __VA_ARGS__); })
290 #define PCHAR(ch) ({ char _ch = (ch); if (_ch != 0) P("%c", _ch); })
291 
292  while ((result = m0_xcode_next(&it)) > 0) {
293  struct m0_xcode_cursor_frame *top = m0_xcode_cursor_top(&it);
294  struct m0_xcode_obj *cur = &top->s_obj;
295  enum m0_xcode_cursor_flag flag = top->s_flag;
296  const struct m0_xcode_type *xt = cur->xo_type;
297  enum m0_xcode_aggr aggr = xt->xct_aggr;
298  struct m0_fop_str qstr;
299 
300  if (flag == M0_XCODE_CURSOR_PRE)
301  PCHAR(punctchar(&it));
302 
303  if (quoted_string(xt, cur, &qstr)) {
304  P("\"%.*s\"", qstr.s_len, qstr.s_buf);
305  m0_xcode_skip(&it);
306  continue;
307  }
308  PCHAR(structure[aggr][flag]);
309 
310  if (flag == M0_XCODE_CURSOR_PRE && aggr == M0_XA_ATOM)
311  P("%#lx", (unsigned long)m0_xcode_atom(cur));
312  }
313  return result ?: nob;
314 #undef PCHAR
315 #undef P
316 }
317 
318 #undef M0_TRACE_SUBSYSTEM
319 
322 /*
323  * Local variables:
324  * c-indentation-style: "K&R"
325  * c-basic-offset: 8
326  * tab-width: 8
327  * fill-column: 80
328  * scroll-step: 1
329  * End:
330  */
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:279
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:163
#define M0_CASSERT(cond)
m0_xcode_aggr
Definition: xcode.h:164
static char punctchar(struct m0_xcode_cursor *it)
Definition: string.c:149
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:46
static struct foo * obj
Definition: tlist.c:302
static int char_check(const char **str, char ch)
Definition: string.c:115
static bool quoted_string(const struct m0_xcode_type *xt, const struct m0_xcode_obj *obj, struct m0_fop_str *qstr)
Definition: string.c:264
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:64
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: wire.h:52
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: wire.h:51
#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:107
static const char punctuation[M0_XA_NR][3]
Definition: string.c:138
#define ARRAY_SIZE(a)
Definition: misc.h:45
static const char structure[M0_XA_NR][M0_XCODE_CURSOR_NR]
Definition: string.c:127
#define M0_IMPOSSIBLE(fmt,...)