Rizin
unix-like reverse engineering framework and cli tools
grep.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2009-2020 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2009-2020 nibble <nibble.ds@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_cons.h>
6 #include <rz_util/rz_print.h>
7 #include <sdb.h>
8 
9 #define I(x) rz_cons_singleton()->x
10 
11 static char *strchr_ns(char *s, const char ch) {
12  char *p = strchr(s, ch);
13  if (p && p > s) {
14  char *prev = p - 1;
15  if (*prev == '\\') {
16  memmove(prev, p, strlen(p) + 1);
17  return strchr_ns(p, ch);
18  }
19  }
20  return p;
21 }
22 
23 static const char *help_detail_tilde[] = {
24  "Usage: [command]~[modifier][word,word][endmodifier][[column]][:line]\n"
25  "modifier:",
26  "", "",
27  " &", "", "all words must match to grep the line",
28  " $[n]", "", "sort numerically / alphabetically the Nth column",
29  " $!", "", "sort in inverse order",
30  " ,", "", "token to define another keyword",
31  " +", "", "case insensitive grep (grep -i)",
32  " ^", "", "words must be placed at the beginning of line",
33  " <", "", "perform zoom operation on the buffer",
34  " !", "", "negate grep",
35  " ?", "", "count number of matching lines",
36  " ?.", "", "count number chars",
37  " ??", "", "show this help message",
38  " :s..e", "", "show lines s-e",
39  " ..", "", "internal 'less'",
40  " ...", "", "internal 'hud' (like V_)",
41  " {:", "", "human friendly indentation (yes, it's a smiley)",
42  " {:..", "", "less the output of {:",
43  " {:...", "", "hud the output of {:",
44  " {}", "", "json indentation",
45  " {}..", "", "less json indentation",
46  " {}...", "", "hud json indentation",
47  " {path}", "", "json path grep",
48  "endmodifier:", "", "",
49  " $", "", "words must be placed at the end of line",
50  "column:", "", "",
51  " [n]", "", "show only column n",
52  " [n-m]", "", "show column n to m",
53  " [n-]", "", "show all columns starting from column n",
54  " [i,j,k]", "", "show the columns i, j and k",
55  "Examples:", "", "",
56  " i~:0", "", "show first line of 'i' output",
57  " i~:-2", "", "show the second to last line of 'i' output",
58  " i~:0..3", "", "show first three lines of 'i' output",
59  " pd~mov", "", "disasm and grep for mov",
60  " pi~[0]", "", "show only opcode",
61  " i~0x400$", "", "show lines ending with 0x400",
62  NULL
63 };
64 
65 /* TODO: remove globals */
68 static int sorted_column = -1;
69 
72 }
73 
74 #define RZ_CONS_GREP_BUFSIZE 4096
75 
76 static void parse_grep_expression(const char *str) {
77  static char buf[RZ_CONS_GREP_BUFSIZE];
78  int wlen, len, is_range, num_is_parsed, fail = 0;
79  char *ptr, *optr, *ptr2, *ptr3, *end_ptr = NULL, last;
80  ut64 range_begin, range_end;
81 
82  if (!str || !*str) {
83  return;
84  }
85  RzCons *cons = rz_cons_singleton();
86  RzConsGrep *grep = &cons->context->grep;
87  sorted_column = 0;
88  bool first = true;
89  while (*str) {
90  switch (*str) {
91  case '.':
92  if (str[1] == '.') {
93  if (str[2] == '.') {
94  grep->less = 2;
95  } else {
96  grep->less = 1;
97  }
98  return;
99  }
100  str++;
101  break;
102  case '{':
103  if (str[1] == ':') {
104  grep->human = true; // human friendly indentation ij~{:
105  grep->json = 1;
106  if (!strncmp(str, "{:...", 5)) {
107  grep->hud = true;
108  } else if (!strncmp(str, "{:..", 4)) {
109  grep->less = 1;
110  }
111  } else if (str[1] == '}') {
112  // standard json indentation
113  grep->json = 1;
114  if (!strncmp(str, "{}...", 5)) {
115  grep->hud = true;
116  } else if (!strncmp(str, "{}..", 4)) {
117  grep->less = 1;
118  }
119  } else {
120  char *jsonPath = strdup(str + 1);
121  char *jsonPathEnd = strchr(jsonPath, '}');
122  if (jsonPathEnd) {
123  *jsonPathEnd = 0;
124  free(grep->json_path);
125  grep->json_path = jsonPath;
126  grep->json = 1;
127  } else {
128  free(jsonPath);
129  }
130  return;
131  }
132  str++;
133  break;
134  case '$':
135  str++;
136  if (*str == '!') {
137  grep->sort_invert = true;
138  str++;
139  } else {
140  grep->sort_invert = false;
141  }
142  grep->sort = atoi(str);
143  while (IS_DIGIT(*str)) {
144  str++;
145  }
146  if (*str == ':') {
147  grep->sort_row = atoi(++str);
148  str++;
149  }
150  break;
151  case '&':
152  str++;
153  grep->amp = 1;
154  break;
155  case '<':
156  grep->zoom = atoi(++str);
157  // grep->zoomy = atoi (arg);
158  break;
159  case '+':
160  if (first) {
161  str++;
162  grep->icase = 1;
163  } else {
164  goto while_end;
165  }
166  break;
167  case '^':
168  str++;
169  grep->begin = 1;
170  break;
171  case '!':
172  str++;
173  grep->neg = 1;
174  break;
175  case '?':
176  str++;
177  grep->counter = 1;
178  if (*str == '.') {
179  grep->charCounter = true;
180  str++;
181  } else if (*str == '?') {
182  cons->filter = true;
184  return;
185  }
186  break;
187  default:
188  goto while_end;
189  }
190  first = false;
191  }
192 while_end:
193 
194  len = strlen(str) - 1;
195  if (len > RZ_CONS_GREP_BUFSIZE - 1) {
196  eprintf("rz_cons_grep: too long!\n");
197  return;
198  }
199  if (len > 0 && str[len] == '?') {
200  grep->counter = 1;
201  strncpy(buf, str, RZ_MIN(len, sizeof(buf) - 1));
202  buf[len] = 0;
203  len--;
204  } else {
205  strncpy(buf, str, sizeof(buf) - 1);
206  }
207 
208  ptr = buf;
209  ptr2 = strchr(ptr, '[');
210  ptr3 = strchr(ptr, ']');
211  is_range = 0;
212  num_is_parsed = 0;
213  fail = 0;
214  range_begin = range_end = -1;
215 
216  if (ptr2 && ptr3) {
217  end_ptr = ptr2;
218  last = ptr3[1];
219  ptr3[1] = '\0';
220  ptr2++;
221  for (; ptr2 <= ptr3; ptr2++) {
222  if (fail) {
223  ZERO_FILL(grep->tokens);
224  grep->tokens_used = 0;
225  break;
226  }
227  switch (*ptr2) {
228  case '-':
229  is_range = 1;
230  num_is_parsed = 0;
231  range_end = -1;
232  break;
233  case ']': // fallthrough to handle ']' like ','
234  case ',':
235  for (; range_begin <= range_end; range_begin++) {
236  if (range_begin >= RZ_CONS_GREP_TOKENS) {
237  fail = 1;
238  break;
239  }
240  grep->tokens[range_begin] = 1;
241  grep->tokens_used = 1;
242  }
243  // case of [n-]
244  if (*ptr2 == ']' && is_range && !num_is_parsed) {
245  num_is_parsed = 1;
246  range_end = -1;
247  } else {
248  is_range = 0;
249  num_is_parsed = 0;
250  }
251  break;
252  default:
253  if (!num_is_parsed) {
254  if (is_range) {
255  range_end = rz_num_get(cons->num, ptr2);
256  // check for bad value, if range_end == 0, we check if ptr2 == '0'
257  if (range_end == 0 && *ptr != '0') {
258  range_end = -1; // this allow [n- ]
259  }
260  } else {
261  range_begin = range_end = rz_num_get(cons->num, ptr2);
262  }
263  num_is_parsed = 1;
264  }
265  }
266  }
267  ptr3[1] = last;
268  }
269 
270  ptr2 = strchr_ns(ptr, ':'); // line number
271  grep->range_line = 2; // there is not :
272  if (ptr2 && ptr2[1] != ':' && ptr2[1] && (IS_DIGIT(ptr2[1]) || ptr2[1] == '-' || ptr2[1] == '.')) {
273  end_ptr = end_ptr ? RZ_MIN(end_ptr, ptr2) : ptr2;
274  char *p, *token = ptr2 + 1;
275  p = strstr(token, "..");
276  if (!p) {
277  grep->line = rz_num_get(cons->num, ptr2 + 1);
278  grep->range_line = 0;
279  } else {
280  *p = '\0';
281  grep->range_line = 1;
282  if (*token) {
283  grep->f_line = rz_num_get(cons->num, token);
284  } else {
285  grep->f_line = 0;
286  }
287  if (p[2]) {
288  grep->l_line = rz_num_get(cons->num, p + 2);
289  } else {
290  grep->l_line = 0;
291  }
292  }
293  }
294  if (end_ptr) {
295  *end_ptr = '\0';
296  }
297 
298  len = strlen(buf) - 1;
299  if (len > 1 && buf[len] == '$' && buf[len - 1] != '\\') {
300  grep->end = 1;
301  buf[len] = '\0';
302  }
303 
304  free(grep->str);
305  if (*ptr) {
306  grep->str = (char *)strdup(ptr);
307  do {
308  optr = ptr;
309  ptr = strchr(ptr, ','); // grep keywords
310  if (ptr) {
311  *ptr++ = '\0';
312  }
313  wlen = strlen(optr);
314  if (!wlen) {
315  continue;
316  }
317  if (wlen >= RZ_CONS_GREP_WORD_SIZE - 1) {
318  eprintf("grep string too long\n");
319  continue;
320  }
321  grep->nstrings++;
322  if (grep->nstrings > RZ_CONS_GREP_WORDS - 1) {
323  eprintf("too many grep strings\n");
324  break;
325  }
326  rz_str_ncpy(grep->strings[grep->nstrings - 1],
327  optr, RZ_CONS_GREP_WORD_SIZE);
328  } while (ptr);
329  } else {
330  grep->str = strdup(ptr);
331  grep->nstrings++;
332  grep->strings[0][0] = 0;
333  }
334 }
335 
336 // Finds and returns next intgerp expression,
337 // unescapes escaped twiddles
338 static char *find_next_intgrep(char *cmd, const char *quotes) {
339  char *p;
340  do {
341  p = (char *)rz_str_firstbut(cmd, '~', quotes);
342  if (!p) {
343  break;
344  }
345  if (p == cmd || *(p - 1) != '\\') {
346  return (char *)p;
347  }
348  // twiddle unescape
349  memmove(p - 1, p, strlen(p) + 1);
350  cmd = p + 1;
351  } while (*cmd);
352  return NULL;
353 }
354 
355 /*
356  * Removes grep part from *cmd* and returns newly allocated string
357  * with reshaped grep expression.
358  *
359  * Function converts multiple twiddle expressions into internal representation.
360  * For example:
361  * converts "~str1~str2~str3~?" into "?&str1,str2,str3"
362  */
363 static char *preprocess_filter_expr(char *cmd, const char *quotes) {
364  char *p1, *p2, *ns = NULL;
365  const char *strsep = "&";
366  int len;
367  int i;
368 
369  p1 = find_next_intgrep(cmd, quotes);
370  if (!p1) {
371  return NULL;
372  }
373 
374  len = strlen(p1);
375  if (len > 4 && rz_str_endswith(p1, "~?") && p1[len - 3] != '\\') {
376  p1[len - 2] = '\0';
377  ns = rz_str_append(ns, "?");
378  }
379 
380  *p1 = '\0'; // remove grep part from cmd
381 
382  i = 0;
383  // parse words between '~'
384  while ((p2 = find_next_intgrep(p1 + 1, quotes))) {
385  ns = rz_str_append(ns, strsep);
386  ns = rz_str_appendlen(ns, p1 + 1, (int)(p2 - p1 - 1));
387  p1 = p2;
388  strsep = ",";
389  i++;
390  }
391 
392  if (i > 0) {
393  ns = rz_str_append(ns, ",");
394  }
395 
396  ns = rz_str_append(ns, p1 + 1);
397 
398  return ns;
399 }
400 
401 RZ_API void rz_cons_grep_parsecmd(char *cmd, const char *quotestr) {
402  rz_return_if_fail(cmd && quotestr);
403  char *ptr = preprocess_filter_expr(cmd, quotestr);
404  if (ptr) {
405  rz_str_trim(cmd);
407  free(ptr);
408  }
409 }
410 
411 RZ_API char *rz_cons_grep_strip(char *cmd, const char *quotestr) {
412  char *ptr = NULL;
413 
414  if (cmd) {
415  ptr = preprocess_filter_expr(cmd, quotestr);
416  rz_str_trim(cmd);
417  }
418  return ptr;
419 }
420 
421 RZ_API void rz_cons_grep_process(char *grep) {
422  if (grep) {
423  parse_grep_expression(grep);
424  free(grep);
425  }
426 }
427 
428 static int cmp(const void *a, const void *b) {
429  char *da = NULL;
430  char *db = NULL;
431  const char *ca = rz_str_trim_head_ro(a);
432  const char *cb = rz_str_trim_head_ro(b);
433  if (!a || !b) {
434  return (int)(size_t)((char *)a - (char *)b);
435  }
436  if (sorted_column > 0) {
437  da = strdup(ca);
438  db = strdup(cb);
439  int colsa = rz_str_word_set0(da);
440  int colsb = rz_str_word_set0(db);
441  ca = (colsa > sorted_column) ? rz_str_word_get0(da, sorted_column) : "";
442  cb = (colsb > sorted_column) ? rz_str_word_get0(db, sorted_column) : "";
443  }
444  if (IS_DIGIT(*ca) && IS_DIGIT(*cb)) {
445  ut64 na = rz_num_get(NULL, ca);
446  ut64 nb = rz_num_get(NULL, cb);
447  int ret = (na > nb) - (na < nb);
448  free(da);
449  free(db);
450  return ret;
451  }
452  if (da && db) {
453  int ret = strcmp(ca, cb);
454  free(da);
455  free(db);
456  return ret;
457  }
458  free(da);
459  free(db);
460  return strcmp(a, b);
461 }
462 
464  RzCons *cons = rz_cons_singleton();
465  cons->context->row = 0;
466  cons->context->col = 0;
467  cons->context->rowcol_calc_start = 0;
468  const char *buf = cons->context->buffer;
469  const int len = cons->context->buffer_len;
470  RzConsGrep *grep = &cons->context->grep;
471  const char *in = buf;
472  int ret, total_lines = 0, l = 0, tl = 0;
473  bool show = false;
474  if (cons->filter) {
475  cons->context->buffer_len = 0;
476  RZ_FREE(cons->context->buffer);
477  return;
478  }
479 
480  if ((!len || !buf || buf[0] == '\0') && (grep->json || grep->less)) {
481  grep->json = 0;
482  grep->less = 0;
483  grep->hud = 0;
484  return;
485  }
486 
487  if (grep->zoom) {
488  char *in = calloc(cons->context->buffer_len + 2, 4);
489  strcpy(in, cons->context->buffer);
490  char *out = rz_str_scale(in, grep->zoom * 2, grep->zoomy ? grep->zoomy : grep->zoom);
491  if (out) {
492  free(cons->context->buffer);
493  cons->context->buffer = out;
494  cons->context->buffer_len = strlen(out);
495  cons->context->buffer_sz = cons->context->buffer_len;
496  }
497  grep->zoom = 0;
498  grep->zoomy = 0;
499  free(in);
500  return;
501  }
502  if (grep->json) {
503  if (grep->json_path) {
504  RzJson *json = rz_json_parse(cons->context->buffer);
505  if (!json) {
506  RZ_FREE(grep->json_path);
507  return;
508  }
509  const RzJson *excerpt;
510  // To simplify grep syntax we omit brackets in `[0]` for JSON paths
511  if (*grep->json_path != '[' && *grep->json_path != '.') {
512  char *tmppath = rz_str_newf("[%s]", grep->json_path);
513  excerpt = rz_json_get_path(json, tmppath);
514  free(tmppath);
515  } else {
516  excerpt = rz_json_get_path(json, grep->json_path);
517  }
518  if (excerpt) {
519  // When we receive the path, it's fetched with the key name
520  // We should get only the value
521  char *u = rz_json_as_string(excerpt, false);
522  if (!u) {
523  RZ_FREE(grep->json_path);
524  return;
525  }
526  cons->context->buffer = u;
527  cons->context->buffer_len = strlen(u);
528  cons->context->buffer_sz = cons->context->buffer_len + 1;
529  grep->json = 0;
530  rz_cons_newline();
531  }
532  RZ_FREE(grep->json_path);
533  } else {
534  const char *palette[] = {
535  cons->context->pal.graph_false, // f
536  cons->context->pal.graph_true, // t
537  cons->context->pal.num, // k
538  cons->context->pal.comment, // v
539  Color_RESET,
540  NULL
541  };
542  char *bb = strdup(buf);
543  rz_str_ansi_filter(bb, NULL, NULL, -1);
544  char *out = (cons->context->grep.human)
545  ? rz_print_json_human(bb)
546  : rz_print_json_indent(bb, I(context->color_mode), " ", palette);
547  free(bb);
548  if (!out) {
549  return;
550  }
551  free(cons->context->buffer);
552  cons->context->buffer = out;
553  cons->context->buffer_len = strlen(out);
554  cons->context->buffer_sz = cons->context->buffer_len + 1;
555  grep->json = 0;
556  if (grep->hud) {
557  grep->hud = false;
559  } else if (grep->less) {
560  grep->less = 0;
562  }
563  }
564  return;
565  // cons->lines = ?? return 3;
566  }
567  if (grep->less) {
568  int less = grep->less;
569  grep->less = 0;
570  if (less == 2) {
571  char *res = rz_cons_hud_string(buf);
572  if (res) {
573  rz_cons_println(res);
574  free(res);
575  }
576  } else {
578  cons->context->buffer_len = 0;
579  if (cons->context->buffer) {
580  cons->context->buffer[0] = 0;
581  }
582  RZ_FREE(cons->context->buffer);
583  }
584  return;
585  }
586  if (!cons->context->buffer) {
587  cons->context->buffer_len = len + 20;
588  cons->context->buffer = malloc(cons->context->buffer_len);
589  cons->context->buffer[0] = 0;
590  }
591  RzStrBuf *ob = rz_strbuf_new("");
592  // if we modify cons->lines we should update I.context->buffer too
593  cons->lines = 0;
594  // used to count lines and change negative grep.line values
595  while ((int)(size_t)(in - buf) < len) {
596  char *p = strchr(in, '\n');
597  if (!p) {
598  break;
599  }
600  l = p - in;
601  if (l > 0) {
602  in += l + 1;
603  } else {
604  in++;
605  }
606  total_lines++;
607  }
608  if (!grep->range_line && grep->line < 0) {
609  grep->line = total_lines + grep->line;
610  }
611  if (grep->range_line == 1) {
612  if (grep->f_line < 0) {
613  grep->f_line = total_lines + grep->f_line;
614  }
615  if (grep->l_line <= 0) {
616  grep->l_line = total_lines + grep->l_line;
617  }
618  }
619  bool is_range_line_grep_only = grep->range_line != 2 && !*grep->str;
620  in = buf;
621  while ((int)(size_t)(in - buf) < len) {
622  char *p = strchr(in, '\n');
623  if (!p) {
624  break;
625  }
626  l = p - in;
627  if ((!l && is_range_line_grep_only) || l > 0) {
628  char *tline = rz_str_ndup(in, l);
629  if (cons->grep_color) {
630  tl = l;
631  } else {
632  tl = rz_str_ansi_filter(tline, NULL, NULL, l);
633  }
634  if (tl < 0) {
635  ret = -1;
636  } else {
637  ret = rz_cons_grep_line(tline, tl);
638  if (!grep->range_line) {
639  if (grep->line == cons->lines) {
640  show = true;
641  }
642  } else if (grep->range_line == 1) {
643  if (grep->f_line == cons->lines) {
644  show = true;
645  }
646  if (grep->l_line == cons->lines) {
647  show = false;
648  }
649  } else {
650  show = true;
651  }
652  }
653  if ((!ret && is_range_line_grep_only) || ret > 0) {
654  if (show) {
655  char *str = rz_str_ndup(tline, ret);
656  if (cons->grep_highlight) {
657  int i;
658  for (i = 0; i < grep->nstrings; i++) {
659  char *newstr = rz_str_newf(Color_INVERT "%s" Color_RESET, grep->strings[i]);
660  if (str && newstr) {
661  if (grep->icase) {
662  str = rz_str_replace_icase(str, grep->strings[i], newstr, 1, 1);
663  } else {
664  str = rz_str_replace(str, grep->strings[i], newstr, 1);
665  }
666  }
667  free(newstr);
668  }
669  }
670  if (str) {
671  rz_strbuf_append(ob, str);
672  rz_strbuf_append(ob, "\n");
673  }
674  free(str);
675  }
676  if (!grep->range_line) {
677  show = false;
678  }
679  cons->lines++;
680  } else if (ret < 0) {
681  free(tline);
682  return;
683  }
684  free(tline);
685  in += l + 1;
686  } else {
687  in++;
688  }
689  }
690 
691  cons->context->buffer_len = rz_strbuf_length(ob);
692  if (grep->counter) {
693  int cnt = grep->charCounter ? strlen(cons->context->buffer) : cons->lines;
694  if (cons->context->buffer_len < 10) {
695  cons->context->buffer_len = 10; // HACK
696  }
697  snprintf(cons->context->buffer, cons->context->buffer_len, "%d\n", cnt);
698  cons->context->buffer_len = strlen(cons->context->buffer);
699  cons->num->value = cons->lines;
700  rz_strbuf_free(ob);
701  return;
702  }
703 
704  const int ob_len = rz_strbuf_length(ob);
705  if (ob_len >= cons->context->buffer_sz) {
706  cons->context->buffer_sz = ob_len + 1;
707  cons->context->buffer = rz_strbuf_drain(ob);
708  } else {
709  memcpy(cons->context->buffer, rz_strbuf_getbin(ob, NULL), ob_len);
710  cons->context->buffer[ob_len] = 0;
711  rz_strbuf_free(ob);
712  }
713  cons->context->buffer_len = ob_len;
714 
715  if (grep->sort != -1) {
716 #define INSERT_LINES(list) \
717  do { \
718  rz_list_foreach (list, iter, str) { \
719  int len = strlen(str); \
720  memcpy(ptr, str, len); \
721  memcpy(ptr + len, "\n", 2); \
722  ptr += len + 1; \
723  nl++; \
724  } \
725  } while (false)
726 
727  RzListIter *iter;
728  int nl = 0;
729  char *ptr = cons->context->buffer;
730  char *str;
731  sorted_column = grep->sort;
733  if (grep->sort_invert) {
735  }
738  cons->lines = nl;
740  sorted_lines = NULL;
743  }
744 }
745 
746 RZ_API int rz_cons_grep_line(char *buf, int len) {
747  RzCons *cons = rz_cons_singleton();
748  RzConsGrep *grep = &cons->context->grep;
749  const char *delims = " |,;=\t";
750  char *tok = NULL;
751  bool hit = grep->neg;
752  int outlen = 0;
753  bool use_tok = false;
754  size_t i;
755 
756  char *in = calloc(1, len + 1);
757  if (!in) {
758  return 0;
759  }
760  char *out = calloc(1, len + 2);
761  if (!out) {
762  free(in);
763  return 0;
764  }
765  memcpy(in, buf, len);
766 
767  if (grep->nstrings > 0) {
768  int ampfail = grep->amp;
769  if (grep->icase) {
770  rz_str_case(in, false);
771  }
772  for (i = 0; i < grep->nstrings; i++) {
773  char *str = grep->strings[i];
774  if (grep->icase) {
775  rz_str_case(str, false);
776  }
777  const char *p = rz_strstr_ansi(in, grep->strings[i]);
778  if (!p) {
779  ampfail = 0;
780  continue;
781  }
782  if (grep->begin) {
783  hit = (p == in);
784  if (grep->neg) {
785  hit = !hit;
786  }
787  } else {
788  hit = !grep->neg;
789  }
790  // TODO: optimize without strlen without breaking t/feat_grep (grep end)
791  if (grep->end && (strlen(grep->strings[i]) != strlen(p))) {
792  hit = 0;
793  }
794  if (!grep->amp) {
795  break;
796  }
797  }
798  if (grep->amp) {
799  hit = ampfail;
800  }
801  } else {
802  hit = 1;
803  }
804 
805  if (hit) {
806  if (!grep->range_line) {
807  if (grep->line == cons->lines) {
808  use_tok = true;
809  }
810  } else if (grep->range_line == 1) {
811  use_tok = RZ_BETWEEN(grep->f_line, cons->lines, grep->l_line);
812  } else {
813  use_tok = true;
814  }
815  if (use_tok && grep->tokens_used) {
816  for (i = 0; i < RZ_CONS_GREP_TOKENS; i++) {
817  tok = strtok(i ? NULL : in, delims);
818  if (tok) {
819  if (grep->tokens[i]) {
820  int toklen = strlen(tok);
821  memcpy(out + outlen, tok, toklen);
822  memcpy(out + outlen + toklen, " ", 2);
823  outlen += toklen + 1;
824  if (!(*out)) {
825  free(in);
826  free(out);
827  return -1;
828  }
829  }
830  } else {
831  if ((*out)) {
832  break;
833  }
834  free(in);
835  free(out);
836  return 0;
837  }
838  }
839  outlen = outlen > 0 ? outlen - 1 : 0;
840  if (outlen > len) { // should never happen
841  eprintf("rz_cons_grep_line: how you have reached this?\n");
842  free(in);
843  free(out);
844  return -1;
845  }
846  memcpy(buf, out, len);
847  len = outlen;
848  }
849  } else {
850  len = 0;
851  }
852  free(in);
853  free(out);
854  if (grep->sort != -1) {
855  char ch = buf[len];
856  buf[len] = 0;
857  if (!sorted_lines) {
859  }
860  if (!unsorted_lines) {
862  }
863  if (cons->lines >= grep->sort_row) {
865  } else {
867  }
868  buf[len] = ch;
869  }
870 
871  return len;
872 }
873 
874 RZ_API void rz_cons_grep(const char *grep) {
875  parse_grep_expression(grep);
876  rz_cons_grepbuf();
877 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static RASN1String * newstr(const char *string)
Definition: astr.c:23
const lzma_allocator const uint8_t * in
Definition: block.h:527
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
RZ_API RzCons * rz_cons_singleton(void)
Definition: cons.c:300
RZ_API void rz_cons_newline(void)
Definition: cons.c:1274
RZ_API void rz_cons_cmd_help(const char *help[], bool use_color)
Definition: cons.c:1954
RZ_API void rz_cons_println(const char *str)
Definition: cons.c:233
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
Definition: sflib.h:79
static RzList * sorted_lines
Definition: grep.c:66
#define INSERT_LINES(list)
RZ_API void rz_cons_grep_help(void)
Definition: grep.c:70
RZ_API char * rz_cons_grep_strip(char *cmd, const char *quotestr)
Definition: grep.c:411
static const char * help_detail_tilde[]
Definition: grep.c:23
static char * find_next_intgrep(char *cmd, const char *quotes)
Definition: grep.c:338
RZ_API void rz_cons_grep_parsecmd(char *cmd, const char *quotestr)
Definition: grep.c:401
#define RZ_CONS_GREP_BUFSIZE
Definition: grep.c:74
static char * preprocess_filter_expr(char *cmd, const char *quotes)
Definition: grep.c:363
RZ_API int rz_cons_grep_line(char *buf, int len)
Definition: grep.c:746
#define I(x)
Definition: grep.c:9
static int cmp(const void *a, const void *b)
Definition: grep.c:428
static int sorted_column
Definition: grep.c:68
RZ_API void rz_cons_grep_process(char *grep)
Definition: grep.c:421
RZ_API void rz_cons_grep(const char *grep)
Definition: grep.c:874
static char * strchr_ns(char *s, const char ch)
Definition: grep.c:11
static void parse_grep_expression(const char *str)
Definition: grep.c:76
static RzList * unsorted_lines
Definition: grep.c:67
RZ_API void rz_cons_grepbuf(void)
Definition: grep.c:463
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API char * rz_cons_hud_string(const char *s)
Definition: hud.c:22
voidpf void * buf
Definition: ioapi.h:138
RZ_API char * rz_print_json_indent(const char *s, bool color, const char *tab, const char **palette)
Definition: json_indent.c:254
RZ_API char * rz_print_json_human(const char *s)
Definition: json_indent.c:155
snprintf
Definition: kernel.h:364
RZ_API int rz_cons_less_str(const char *str, const char *exitkeys)
Definition: less.c:10
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static int hit(RzSearchKeyword *kw, void *user, ut64 addr)
Definition: rz-find.c:58
RZ_API void rz_list_reverse(RZ_NONNULL RzList *list)
Reverses the list.
Definition: list.c:477
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define Color_RESET
Definition: rz_cons.h:617
#define RZ_CONS_GREP_WORDS
Definition: rz_cons.h:49
#define RZ_CONS_GREP_TOKENS
Definition: rz_cons.h:51
#define RZ_CONS_GREP_WORD_SIZE
Definition: rz_cons.h:50
#define Color_INVERT
Definition: rz_cons.h:606
RZ_API const RzJson * rz_json_get_path(const RzJson *json, const char *path)
Definition: json_parser.c:419
RZ_API RzJson * rz_json_parse(char *text)
Definition: json_parser.c:382
RZ_API RZ_OWN char * rz_json_as_string(const RzJson *json, bool with_key)
Definition: json_parser.c:546
RZ_API ut64 rz_num_get(RzNum *num, const char *str)
Definition: unum.c:172
RZ_API char * rz_str_replace_icase(char *str, const char *key, const char *val, int g, int keep_case)
Definition: str.c:1160
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_append(char *ptr, const char *string)
Definition: str.c:1063
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
RZ_API char * rz_str_scale(const char *r, int w, int h)
Definition: str.c:3921
RZ_API char * rz_str_appendlen(char *ptr, const char *string, int slen)
Definition: str.c:1043
RZ_API int rz_str_ansi_filter(char *str, char **out, int **cposs, int len)
Definition: str.c:2124
RZ_API void rz_str_case(char *str, bool up)
Definition: str.c:341
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t n)
Secure string copy with null terminator.
Definition: str.c:923
RZ_API const char * rz_str_trim_head_ro(const char *str)
Definition: str_trim.c:86
RZ_API char * rz_str_replace(char *str, const char *key, const char *val, int g)
Definition: str.c:1110
RZ_API const char * rz_str_firstbut(const char *s, char ch, const char *but)
Definition: str.c:2644
RZ_API int rz_str_word_set0(char *str)
Definition: str.c:423
RZ_API void rz_str_trim(RZ_NONNULL RZ_INOUT char *str)
Removes whitespace characters (space, tab, newline etc.) from the beginning and end of a string.
Definition: str_trim.c:190
RZ_API const char * rz_strstr_ansi(const char *a, const char *b)
Definition: str.c:2742
RZ_API const char * rz_str_word_get0(const char *str, int idx)
Definition: str.c:598
RZ_API bool rz_str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string ends with a specifc sequence of characters (case sensitive)
Definition: str.c:3329
#define IS_DIGIT(x)
Definition: rz_str_util.h:11
RZ_API RZ_OWN char * rz_strbuf_drain(RzStrBuf *sb)
Definition: strbuf.c:342
RZ_API bool rz_strbuf_append(RzStrBuf *sb, const char *s)
Definition: strbuf.c:222
RZ_API RzStrBuf * rz_strbuf_new(const char *s)
Definition: strbuf.c:8
RZ_API void rz_strbuf_free(RzStrBuf *sb)
Definition: strbuf.c:358
RZ_API ut8 * rz_strbuf_getbin(RzStrBuf *sb, int *len)
Definition: strbuf.c:326
RZ_API int rz_strbuf_length(RzStrBuf *sb)
Definition: strbuf.c:28
#define ZERO_FILL(x)
Definition: rz_types.h:281
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_MIN(x, y)
#define RZ_BETWEEN(x, y, z)
int size_t
Definition: sftypes.h:40
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
RzConsPrintablePalette pal
Definition: rz_cons.h:491
size_t buffer_sz
Definition: rz_cons.h:470
int rowcol_calc_start
Definition: rz_cons.h:496
RzConsGrep grep
Definition: rz_cons.h:466
size_t buffer_len
Definition: rz_cons.h:469
bool human
Definition: rz_cons.h:80
char * str
Definition: rz_cons.h:75
char * json_path
Definition: rz_cons.h:82
bool sort_invert
Definition: rz_cons.h:87
int tokens[RZ_CONS_GREP_TOKENS]
Definition: rz_cons.h:90
int nstrings
Definition: rz_cons.h:74
bool charCounter
Definition: rz_cons.h:77
char strings[RZ_CONS_GREP_WORDS][RZ_CONS_GREP_WORD_SIZE]
Definition: rz_cons.h:73
int tokens_used
Definition: rz_cons.h:91
int range_line
Definition: rz_cons.h:83
int sort_row
Definition: rz_cons.h:86
bool filter
Definition: rz_cons.h:569
RzNum * num
Definition: rz_cons.h:543
bool grep_highlight
Definition: rz_cons.h:568
bool grep_color
Definition: rz_cons.h:567
RzConsContext * context
Definition: rz_cons.h:502
int lines
Definition: rz_cons.h:507
ut64 value
Definition: rz_num.h:63
#define fail(test)
Definition: tests.h:29
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const char * cb[]
Definition: z80_tab.h:176