2 * kp_str.c - ktap string data struction manipulation
4 * This file is part of ktap by Jovi Zhangwei.
6 * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
8 * Copyright (C) 1994-2013 Lua.org, PUC-Rio.
9 * - The part of code in this file is copied from lua initially.
10 * - lua's MIT license is compatible with GPL.
12 * ktap is free software; you can redistribute it and/or modify it
13 * under the terms and conditions of the GNU General Public License,
14 * version 2, as published by the Free Software Foundation.
16 * ktap is distributed in the hope it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21 * You should have received a copy of the GNU General Public License along with
22 * this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "../include/ktap_types.h"
31 #include <linux/ctype.h>
32 #include <linux/module.h>
33 #include <linux/kallsyms.h>
35 #include "kp_transport.h"
39 #define STRING_MAXSHORTLEN 40
41 int kp_tstring_cmp(const ktap_string *ls, const ktap_string *rs)
43 const char *l = getstr(ls);
44 size_t ll = ls->tsv.len;
45 const char *r = getstr(rs);
46 size_t lr = rs->tsv.len;
49 int temp = strcmp(l, r);
53 /* strings are equal up to a `\0' */
55 /* index of first `\0' in both strings */
56 size_t len = strlen(l);
60 return (len == ll) ? 0 : 1;
61 else if (len == ll) /* l is finished? */
65 * both strings longer than `len';
66 * go on comparing (after the `\0')
69 l += len; ll -= len; r += len; lr -= len;
75 * equality for long strings
77 int kp_tstring_eqlngstr(ktap_string *a, ktap_string *b)
79 size_t len = a->tsv.len;
81 return (a == b) || ((len == b->tsv.len) &&
82 (memcmp(getstr(a), getstr(b), len) == 0));
86 * equality for strings
88 int kp_tstring_eqstr(ktap_string *a, ktap_string *b)
90 return (a->tsv.tt == b->tsv.tt) &&
91 (a->tsv.tt == KTAP_TSHRSTR ? eqshrstr(a, b) :
92 kp_tstring_eqlngstr(a, b));
95 #define STRING_HASHLIMIT 5
96 unsigned int kp_string_hash(const char *str, size_t l, unsigned int seed)
98 unsigned int h = seed ^ l;
100 size_t step = (l >> STRING_HASHLIMIT) + 1;
102 for (l1 = l; l1 >= step; l1 -= step)
103 h = h ^ ((h<<5) + (h>>2) + (u8)(str[l1 - 1]));
110 * resizes the string table
112 void kp_tstring_resize(ktap_state *ks, int newsize)
115 ktap_stringtable *tb = &G(ks)->strt;
117 if (newsize > tb->size) {
118 kp_realloc(ks, tb->hash, tb->size, newsize, ktap_gcobject *);
120 for (i = tb->size; i < newsize; i++)
125 for (i = 0; i < tb->size; i++) {
126 ktap_gcobject *p = tb->hash[i];
130 ktap_gcobject *next = gch(p)->next;
131 unsigned int h = lmod(gco2ts(p)->hash, newsize);
133 gch(p)->next = tb->hash[h];
139 if (newsize < tb->size) {
140 /* shrinking slice must be empty */
141 kp_realloc(ks, tb->hash, tb->size, newsize, ktap_gcobject *);
148 * creates a new string object
150 static ktap_string *createstrobj(ktap_state *ks, const char *str, size_t l,
151 int tag, unsigned int h, ktap_gcobject **list)
154 size_t totalsize; /* total size of TString object */
156 totalsize = sizeof(ktap_string) + ((l + 1) * sizeof(char));
157 ts = &kp_newobject(ks, tag, totalsize, list)->ts;
161 memcpy(ts + 1, str, l * sizeof(char));
162 ((char *)(ts + 1))[l] = '\0'; /* ending 0 */
167 * creates a new short string, inserting it into string table
169 static ktap_string *newshrstr(ktap_state *ks, const char *str, size_t l,
172 ktap_gcobject **list;
173 ktap_stringtable *tb = &G(ks)->strt;
176 if (tb->nuse >= (int)tb->size)
177 kp_tstring_resize(ks, tb->size * 2); /* too crowded */
179 list = &tb->hash[lmod(h, tb->size)];
180 s = createstrobj(ks, str, l, KTAP_TSHRSTR, h, list);
186 * checks whether short string exists and reuses it or creates a new one
188 static ktap_string *internshrstr(ktap_state *ks, const char *str, size_t l)
191 ktap_global_state *g = G(ks);
193 unsigned int h = kp_string_hash(str, l, g->seed);
194 unsigned long __maybe_unused flags;
197 local_irq_save(flags);
198 arch_spin_lock(&G(ks)->str_lock);
201 for (o = g->strt.hash[lmod(h, g->strt.size)]; o != NULL;
205 if (h == ts->tsv.hash && ts->tsv.len == l &&
206 (memcmp(str, getstr(ts), l * sizeof(char)) == 0))
210 ts = newshrstr(ks, str, l, h); /* not found; create a new string */
214 arch_spin_unlock(&G(ks)->str_lock);
215 local_irq_restore(flags);
222 * new string (with explicit length)
224 ktap_string *kp_tstring_newlstr(ktap_state *ks, const char *str, size_t l)
227 if (l <= STRING_MAXSHORTLEN)
228 return internshrstr(ks, str, l);
230 return createstrobj(ks, str, l, KTAP_TLNGSTR, G(ks)->seed,
234 ktap_string *kp_tstring_newlstr_local(ktap_state *ks, const char *str, size_t l)
236 return createstrobj(ks, str, l, KTAP_TLNGSTR, G(ks)->seed,
241 * new zero-terminated string
243 ktap_string *kp_tstring_new(ktap_state *ks, const char *str)
245 return kp_tstring_newlstr(ks, str, strlen(str));
248 ktap_string *kp_tstring_new_local(ktap_state *ks, const char *str)
250 return createstrobj(ks, str, strlen(str), KTAP_TLNGSTR, G(ks)->seed,
254 void kp_tstring_freeall(ktap_state *ks)
256 ktap_global_state *g = G(ks);
259 for (h = 0; h < g->strt.size; h++) {
260 ktap_gcobject *o, *next;
267 g->strt.hash[h] = NULL;
270 kp_free(ks, g->strt.hash);
273 /* todo: dump long string, strt table only contain short string */
274 void kp_tstring_dump(ktap_state *ks)
277 ktap_global_state *g = G(ks);
280 kp_printf(ks, "tstring dump: strt size: %d, nuse: %d\n", g->strt.size,
282 for (h = 0; h < g->strt.size; h++) {
283 for (o = g->strt.hash[h]; o != NULL; o = gch(o)->next) {
284 ktap_string *ts = rawgco2ts(o);
285 kp_printf(ks, "%s [%d]\n", getstr(ts), (int)ts->tsv.len);
291 /* kp_str_fmt - printf implementation */
293 /* macro to `unsign' a character */
294 #define uchar(c) ((unsigned char)(c))
298 /* valid flags in a format specification */
299 #define FLAGS "-+ #0"
301 #define INTFRMLEN "ll"
302 #define INTFRM_T long long
305 * maximum size of each format specification (such as '%-099.99d')
306 * (+10 accounts for %99.99x plus margin of error)
308 #define MAX_FORMAT (sizeof(FLAGS) + sizeof(INTFRMLEN) + 10)
310 static const char *scanformat(ktap_state *ks, const char *strfrmt, char *form)
312 const char *p = strfrmt;
313 while (*p != '\0' && strchr(FLAGS, *p) != NULL)
314 p++; /* skip flags */
316 if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) {
317 kp_error(ks, "invalid format (repeated flags)\n");
321 if (isdigit(uchar(*p)))
322 p++; /* skip width */
324 if (isdigit(uchar(*p)))
325 p++; /* (2 digits at most) */
329 if (isdigit(uchar(*p)))
330 p++; /* skip precision */
331 if (isdigit(uchar(*p)))
332 p++; /* (2 digits at most) */
335 if (isdigit(uchar(*p))) {
336 kp_error(ks, "invalid format (width or precision too long)\n");
341 memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char));
342 form += p - strfrmt + 1;
349 * add length modifier into formats
351 static void addlenmod(char *form, const char *lenmod)
353 size_t l = strlen(form);
354 size_t lm = strlen(lenmod);
355 char spec = form[l - 1];
357 strcpy(form + l - 1, lenmod);
358 form[l + lm - 1] = spec;
363 static void ktap_argerror(ktap_state *ks, int narg, const char *extramsg)
365 kp_error(ks, "bad argument #%d: (%s)\n", narg, extramsg);
368 int kp_str_fmt(ktap_state *ks, struct trace_seq *seq)
372 ktap_value *arg_fmt = kp_arg(ks, 1);
373 int argnum = kp_arg_nr(ks);
374 const char *strfrmt, *strfrmt_end;
376 strfrmt = svalue(arg_fmt);
377 sfl = rawtsvalue(arg_fmt)->tsv.len;
378 strfrmt_end = strfrmt + sfl;
380 while (strfrmt < strfrmt_end) {
381 if (*strfrmt != L_ESC)
382 trace_seq_putc(seq, *strfrmt++);
383 else if (*++strfrmt == L_ESC)
384 trace_seq_putc(seq, *strfrmt++);
385 else { /* format item */
386 char form[MAX_FORMAT];
388 if (++arg > argnum) {
389 ktap_argerror(ks, arg, "no value");
393 strfrmt = scanformat(ks, strfrmt, form);
394 switch (*strfrmt++) {
396 trace_seq_printf(seq, form,
397 nvalue(kp_arg(ks, arg)));
399 case 'd': case 'i': {
400 ktap_number n = nvalue(kp_arg(ks, arg));
401 INTFRM_T ni = (INTFRM_T)n;
402 addlenmod(form, INTFRMLEN);
403 trace_seq_printf(seq, form, ni);
407 char str[KSYM_SYMBOL_LEN];
408 SPRINT_SYMBOL(str, nvalue(kp_arg(ks, arg)));
409 _trace_seq_puts(seq, str);
412 case 'o': case 'u': case 'x': case 'X': {
413 ktap_number n = nvalue(kp_arg(ks, arg));
414 unsigned INTFRM_T ni = (unsigned INTFRM_T)n;
415 addlenmod(form, INTFRMLEN);
416 trace_seq_printf(seq, form, ni);
420 ktap_value *v = kp_arg(ks, arg);
425 _trace_seq_puts(seq, "nil");
430 kp_event_tostring(ks, seq);
435 l = rawtsvalue(v)->tsv.len;
436 if (!strchr(form, '.') && l >= 100) {
438 * no precision and string is too long
440 * keep original string
442 _trace_seq_puts(seq, s);
445 trace_seq_printf(seq, form, s);
449 default: /* also treat cases `pnLlh' */
450 kp_error(ks, "invalid option " KTAP_QL("%%%c")
451 " to " KTAP_QL("format"),