visitor-generate-ir.c: automatically map specific fields to trace's clock class
[babeltrace.git] / common / common.c
CommitLineData
1670bffd
PP
1/*
2 * Babeltrace common functions
3 *
4 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
290725f7 25#include <unistd.h>
1670bffd
PP
26#include <string.h>
27#include <sys/types.h>
1670bffd
PP
28#include <unistd.h>
29#include <assert.h>
db0f160a 30#include <ctype.h>
1670bffd 31#include <glib.h>
108e5a1e 32#include <stdlib.h>
1670bffd 33#include <babeltrace/babeltrace-internal.h>
ad96d936 34#include <babeltrace/common-internal.h>
108e5a1e 35#include <babeltrace/compat/unistd-internal.h>
1670bffd 36
2006c005
MJ
37#ifndef __MINGW32__
38#include <pwd.h>
39#endif
40
1670bffd
PP
41#define SYSTEM_PLUGIN_PATH INSTALL_LIBDIR "/babeltrace/plugins"
42#define HOME_ENV_VAR "HOME"
43#define HOME_PLUGIN_SUBPATH "/.local/lib/babeltrace/plugins"
44
6c4a0731
PP
45static const char *bt_common_color_code_reset = "";
46static const char *bt_common_color_code_bold = "";
47static const char *bt_common_color_code_fg_default = "";
48static const char *bt_common_color_code_fg_red = "";
49static const char *bt_common_color_code_fg_green = "";
50static const char *bt_common_color_code_fg_yellow = "";
51static const char *bt_common_color_code_fg_blue = "";
52static const char *bt_common_color_code_fg_magenta = "";
53static const char *bt_common_color_code_fg_cyan = "";
54static const char *bt_common_color_code_fg_light_gray = "";
55static const char *bt_common_color_code_bg_default = "";
56static const char *bt_common_color_code_bg_red = "";
57static const char *bt_common_color_code_bg_green = "";
58static const char *bt_common_color_code_bg_yellow = "";
59static const char *bt_common_color_code_bg_blue = "";
60static const char *bt_common_color_code_bg_magenta = "";
61static const char *bt_common_color_code_bg_cyan = "";
62static const char *bt_common_color_code_bg_light_gray = "";
63
64static
65void __attribute__((constructor)) bt_common_color_ctor(void)
66{
67 if (bt_common_colors_supported()) {
68 bt_common_color_code_reset = BT_COMMON_COLOR_RESET;
69 bt_common_color_code_bold = BT_COMMON_COLOR_BOLD;
70 bt_common_color_code_fg_default = BT_COMMON_COLOR_FG_DEFAULT;
71 bt_common_color_code_fg_red = BT_COMMON_COLOR_FG_RED;
72 bt_common_color_code_fg_green = BT_COMMON_COLOR_FG_GREEN;
73 bt_common_color_code_fg_yellow = BT_COMMON_COLOR_FG_YELLOW;
74 bt_common_color_code_fg_blue = BT_COMMON_COLOR_FG_BLUE;
75 bt_common_color_code_fg_magenta = BT_COMMON_COLOR_FG_MAGENTA;
76 bt_common_color_code_fg_cyan = BT_COMMON_COLOR_FG_CYAN;
77 bt_common_color_code_fg_light_gray = BT_COMMON_COLOR_FG_LIGHT_GRAY;
78 bt_common_color_code_bg_default = BT_COMMON_COLOR_BG_DEFAULT;
79 bt_common_color_code_bg_red = BT_COMMON_COLOR_BG_RED;
80 bt_common_color_code_bg_green = BT_COMMON_COLOR_BG_GREEN;
81 bt_common_color_code_bg_yellow = BT_COMMON_COLOR_BG_YELLOW;
82 bt_common_color_code_bg_blue = BT_COMMON_COLOR_BG_BLUE;
83 bt_common_color_code_bg_magenta = BT_COMMON_COLOR_BG_MAGENTA;
84 bt_common_color_code_bg_cyan = BT_COMMON_COLOR_BG_CYAN;
85 bt_common_color_code_bg_light_gray = BT_COMMON_COLOR_BG_LIGHT_GRAY;
86 }
87}
88
1670bffd
PP
89BT_HIDDEN
90const char *bt_common_get_system_plugin_path(void)
91{
92 return SYSTEM_PLUGIN_PATH;
93}
94
a613ad68
MJ
95#ifdef __MINGW32__
96BT_HIDDEN
97bool bt_common_is_setuid_setgid(void)
98{
99 return false;
100}
101#else /* __MINGW32__ */
1670bffd
PP
102BT_HIDDEN
103bool bt_common_is_setuid_setgid(void)
104{
105 return (geteuid() != getuid() || getegid() != getgid());
106}
a613ad68 107#endif /* __MINGW32__ */
1670bffd 108
2006c005
MJ
109static
110char *bt_secure_getenv(const char *name)
1670bffd
PP
111{
112 if (bt_common_is_setuid_setgid()) {
113 printf_error("Disregarding %s environment variable for setuid/setgid binary",
114 name);
115 return NULL;
116 }
117 return getenv(name);
118}
119
2006c005
MJ
120#ifdef __MINGW32__
121static
122const char *bt_get_home_dir(void)
123{
124 return g_get_home_dir();
125}
126#else /* __MINGW32__ */
127static
128const char *bt_get_home_dir(void)
1670bffd
PP
129{
130 char *val = NULL;
131 struct passwd *pwd;
132
133 val = bt_secure_getenv(HOME_ENV_VAR);
134 if (val) {
135 goto end;
136 }
137 /* Fallback on password file. */
138 pwd = getpwuid(getuid());
139 if (!pwd) {
140 goto end;
141 }
142 val = pwd->pw_dir;
143end:
144 return val;
145}
2006c005 146#endif /* __MINGW32__ */
1670bffd
PP
147
148BT_HIDDEN
149char *bt_common_get_home_plugin_path(void)
150{
151 char *path = NULL;
152 const char *home_dir;
153
2006c005 154 home_dir = bt_get_home_dir();
1670bffd
PP
155 if (!home_dir) {
156 goto end;
157 }
158
159 if (strlen(home_dir) + strlen(HOME_PLUGIN_SUBPATH) + 1 >= PATH_MAX) {
160 printf_error("Home directory path is too long: `%s`\n",
161 home_dir);
162 goto end;
163 }
164
165 path = malloc(PATH_MAX);
166 if (!path) {
167 goto end;
168 }
169
170 strcpy(path, home_dir);
171 strcat(path, HOME_PLUGIN_SUBPATH);
172
173end:
174 return path;
175}
176
177BT_HIDDEN
178int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs)
179{
180 int ret = 0;
181 const char *at;
182 const char *end;
183 size_t init_dirs_len;
184
185 assert(dirs);
186 init_dirs_len = dirs->len;
187
188 if (!paths) {
189 /* Nothing to append */
190 goto end;
191 }
192
193 at = paths;
194 end = paths + strlen(paths);
195
196 while (at < end) {
197 GString *path;
198 const char *next_colon;
199
200 next_colon = strchr(at, ':');
201 if (next_colon == at) {
202 /*
203 * Empty path: try next character (supported
204 * to conform to the typical parsing of $PATH).
205 */
206 at++;
207 continue;
208 } else if (!next_colon) {
209 /* No more colon: use the remaining */
210 next_colon = paths + strlen(paths);
211 }
212
213 path = g_string_new(NULL);
214 if (!path) {
215 goto error;
216 }
217
218 g_string_append_len(path, at, next_colon - at);
219 at = next_colon + 1;
220 g_ptr_array_add(dirs, path);
221 }
222
223 goto end;
224
225error:
226 ret = -1;
227
228 /* Remove the new entries in dirs */
229 while (dirs->len > init_dirs_len) {
230 g_ptr_array_remove_index(dirs, init_dirs_len);
231 }
232
233end:
234 return ret;
235}
290725f7 236
ad96d936
PP
237BT_HIDDEN
238bool bt_common_colors_supported(void)
290725f7
PP
239{
240 static bool supports_colors = false;
241 static bool supports_colors_set = false;
242 const char *term;
62128320 243 const char *force;
290725f7
PP
244
245 if (supports_colors_set) {
246 goto end;
247 }
248
249 supports_colors_set = true;
250
62128320
PP
251 force = getenv("BABELTRACE_FORCE_COLORS");
252 if (force && strcmp(force, "1") == 0) {
253 supports_colors = true;
254 goto end;
255 }
256
290725f7
PP
257 term = getenv("TERM");
258 if (!term) {
259 goto end;
260 }
261
262 if (strncmp(term, "xterm", 5) != 0 &&
263 strncmp(term, "rxvt", 4) != 0 &&
264 strncmp(term, "konsole", 7) != 0 &&
69c72672
PP
265 strncmp(term, "gnome", 5) != 0 &&
266 strncmp(term, "screen", 5) != 0 &&
267 strncmp(term, "tmux", 4) != 0 &&
268 strncmp(term, "putty", 5) != 0) {
290725f7
PP
269 goto end;
270 }
271
272 if (!isatty(1)) {
273 goto end;
274 }
275
276 supports_colors = true;
277
278end:
279 return supports_colors;
280}
281
282BT_HIDDEN
283const char *bt_common_color_reset(void)
284{
6c4a0731 285 return bt_common_color_code_reset;
290725f7
PP
286}
287
288BT_HIDDEN
289const char *bt_common_color_bold(void)
290{
6c4a0731 291 return bt_common_color_code_bold;
290725f7
PP
292}
293
294BT_HIDDEN
295const char *bt_common_color_fg_default(void)
296{
6c4a0731 297 return bt_common_color_code_fg_default;
290725f7
PP
298}
299
300BT_HIDDEN
301const char *bt_common_color_fg_red(void)
302{
6c4a0731 303 return bt_common_color_code_fg_red;
290725f7
PP
304}
305
306BT_HIDDEN
307const char *bt_common_color_fg_green(void)
308{
6c4a0731 309 return bt_common_color_code_fg_green;
290725f7
PP
310}
311
312BT_HIDDEN
313const char *bt_common_color_fg_yellow(void)
314{
6c4a0731 315 return bt_common_color_code_fg_yellow;
290725f7
PP
316}
317
318BT_HIDDEN
319const char *bt_common_color_fg_blue(void)
320{
6c4a0731 321 return bt_common_color_code_fg_blue;
290725f7
PP
322}
323
324BT_HIDDEN
325const char *bt_common_color_fg_magenta(void)
326{
6c4a0731 327 return bt_common_color_code_fg_magenta;
290725f7
PP
328}
329
330BT_HIDDEN
331const char *bt_common_color_fg_cyan(void)
332{
6c4a0731 333 return bt_common_color_code_fg_cyan;
290725f7
PP
334}
335
336BT_HIDDEN
337const char *bt_common_color_fg_light_gray(void)
338{
6c4a0731 339 return bt_common_color_code_fg_light_gray;
290725f7
PP
340}
341
342BT_HIDDEN
343const char *bt_common_color_bg_default(void)
344{
6c4a0731 345 return bt_common_color_code_bg_default;
290725f7
PP
346}
347
348BT_HIDDEN
349const char *bt_common_color_bg_red(void)
350{
6c4a0731 351 return bt_common_color_code_bg_red;
290725f7
PP
352}
353
354BT_HIDDEN
355const char *bt_common_color_bg_green(void)
356{
6c4a0731 357 return bt_common_color_code_bg_green;
290725f7
PP
358}
359
360BT_HIDDEN
361const char *bt_common_color_bg_yellow(void)
362{
6c4a0731 363 return bt_common_color_code_bg_yellow;
290725f7
PP
364}
365
366BT_HIDDEN
367const char *bt_common_color_bg_blue(void)
368{
6c4a0731 369 return bt_common_color_code_bg_blue;
290725f7
PP
370}
371
372BT_HIDDEN
373const char *bt_common_color_bg_magenta(void)
374{
6c4a0731 375 return bt_common_color_code_bg_magenta;
290725f7
PP
376}
377
378BT_HIDDEN
379const char *bt_common_color_bg_cyan(void)
380{
6c4a0731 381 return bt_common_color_code_bg_cyan;
290725f7
PP
382}
383
384BT_HIDDEN
385const char *bt_common_color_bg_light_gray(void)
386{
6c4a0731 387 return bt_common_color_code_bg_light_gray;
290725f7 388}
db0f160a
PP
389
390BT_HIDDEN
391GString *bt_common_string_until(const char *input, const char *escapable_chars,
392 const char *end_chars, size_t *end_pos)
393{
394 GString *output = g_string_new(NULL);
395 const char *ch;
396 const char *es_char;
397 const char *end_char;
398
399 if (!output) {
400 goto error;
401 }
402
403 for (ch = input; *ch != '\0'; ch++) {
404 if (*ch == '\\') {
405 bool continue_loop = false;
406
407 if (ch[1] == '\0') {
408 /* `\` at the end of the string: append `\` */
409 g_string_append_c(output, *ch);
410 ch++;
411 goto set_end_pos;
412 }
413
414 for (es_char = escapable_chars; *es_char != '\0'; es_char++) {
415 if (ch[1] == *es_char) {
416 /*
417 * `\` followed by an escapable
418 * character: append the escaped
419 * character only.
420 */
421 g_string_append_c(output, ch[1]);
422 ch++;
423 continue_loop = true;
424 break;
425 }
426 }
427
428 if (continue_loop) {
429 continue;
430 }
431
432 /*
433 * `\` followed by a non-escapable character:
434 * append `\` and the character.
435 */
436 g_string_append_c(output, *ch);
437 g_string_append_c(output, ch[1]);
438 ch++;
439 continue;
440 } else {
441 for (end_char = end_chars; *end_char != '\0'; end_char++) {
442 if (*ch == *end_char) {
443 /*
444 * End character found:
445 * terminate this loop.
446 */
447 goto set_end_pos;
448 }
449 }
450
451 /* Normal character: append */
452 g_string_append_c(output, *ch);
453 }
454 }
455
456set_end_pos:
457 if (end_pos) {
458 *end_pos = ch - input;
459 }
460
461 goto end;
462
463error:
464 if (output) {
465 g_string_free(output, TRUE);
466 }
467
468end:
469 return output;
470}
471
472BT_HIDDEN
36b405c6 473GString *bt_common_shell_quote(const char *input, bool with_single_quotes)
db0f160a
PP
474{
475 GString *output = g_string_new(NULL);
476 const char *ch;
477 bool no_quote = true;
478
479 if (!output) {
480 goto end;
481 }
482
483 if (strlen(input) == 0) {
36b405c6
PP
484 if (with_single_quotes) {
485 g_string_assign(output, "''");
486 }
487
db0f160a
PP
488 goto end;
489 }
490
491 for (ch = input; *ch != '\0'; ch++) {
492 const char c = *ch;
493
494 if (!g_ascii_isalpha(c) && !g_ascii_isdigit(c) && c != '_' &&
495 c != '@' && c != '%' && c != '+' && c != '=' &&
496 c != ':' && c != ',' && c != '.' && c != '/' &&
497 c != '-') {
498 no_quote = false;
499 break;
500 }
501 }
502
503 if (no_quote) {
504 g_string_assign(output, input);
505 goto end;
506 }
507
36b405c6
PP
508 if (with_single_quotes) {
509 g_string_assign(output, "'");
510 }
db0f160a
PP
511
512 for (ch = input; *ch != '\0'; ch++) {
513 if (*ch == '\'') {
514 g_string_append(output, "'\"'\"'");
515 } else {
516 g_string_append_c(output, *ch);
517 }
518 }
519
36b405c6
PP
520 if (with_single_quotes) {
521 g_string_append_c(output, '\'');
522 }
db0f160a
PP
523
524end:
525 return output;
526}
527
528BT_HIDDEN
529bool bt_common_string_is_printable(const char *input)
530{
531 const char *ch;
532 bool printable = true;
533 assert(input);
534
535 for (ch = input; *ch != '\0'; ch++) {
536 if (!isprint(*ch) && *ch != '\n' && *ch != '\r' &&
537 *ch != '\t' && *ch != '\v') {
538 printable = false;
539 goto end;
540 }
541 }
542
543end:
544 return printable;
545}
546
547BT_HIDDEN
548void bt_common_destroy_lttng_live_url_parts(
549 struct bt_common_lttng_live_url_parts *parts)
550{
551 if (!parts) {
552 goto end;
553 }
554
555 if (parts->proto) {
556 g_string_free(parts->proto, TRUE);
557 parts->proto = NULL;
558 }
559
560 if (parts->hostname) {
561 g_string_free(parts->hostname, TRUE);
562 parts->hostname = NULL;
563 }
564
565 if (parts->target_hostname) {
566 g_string_free(parts->target_hostname, TRUE);
567 parts->target_hostname = NULL;
568 }
569
570 if (parts->session_name) {
571 g_string_free(parts->session_name, TRUE);
572 parts->session_name = NULL;
573 }
574
575end:
576 return;
577}
578
579BT_HIDDEN
580struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
581 const char *url, char *error_buf, size_t error_buf_size)
582{
583 struct bt_common_lttng_live_url_parts parts;
584 const char *at = url;
585 size_t end_pos;
586
587 assert(url);
588 memset(&parts, 0, sizeof(parts));
589 parts.port = -1;
590
591 /* Protocol */
592 parts.proto = bt_common_string_until(at, "", ":", &end_pos);
593 if (!parts.proto || parts.proto->len == 0) {
594 if (error_buf) {
595 snprintf(error_buf, error_buf_size, "Missing protocol");
596 }
597
598 goto error;
599 }
600
601 if (strcmp(parts.proto->str, "net") == 0) {
602 g_string_assign(parts.proto, "net4");
603 }
604
605 if (strcmp(parts.proto->str, "net4") != 0 &&
606 strcmp(parts.proto->str, "net6") != 0) {
607 if (error_buf) {
608 snprintf(error_buf, error_buf_size,
609 "Unknown protocol: `%s`", parts.proto->str);
610 }
611
612 goto error;
613 }
614
615 if (at[end_pos] != ':') {
616 if (error_buf) {
617 snprintf(error_buf, error_buf_size,
618 "Expecting `:` after `%s`", parts.proto->str);
619 }
620
621 goto error;
622 }
623
624 at += end_pos;
625
626 /* :// */
627 if (strncmp(at, "://", 3) != 0) {
628 if (error_buf) {
629 snprintf(error_buf, error_buf_size,
630 "Expecting `://` after protocol");
631 }
632
633 goto error;
634 }
635
636 at += 3;
637
638 /* Hostname */
639 parts.hostname = bt_common_string_until(at, "", ":/", &end_pos);
640 if (!parts.hostname || parts.hostname->len == 0) {
641 if (error_buf) {
642 snprintf(error_buf, error_buf_size, "Missing hostname");
643 }
644
645 goto error;
646 }
647
648 if (at[end_pos] == ':') {
649 /* Port */
650 GString *port;
651
652 at += end_pos + 1;
653 port = bt_common_string_until(at, "", "/", &end_pos);
654 if (!port || port->len == 0) {
655 if (error_buf) {
656 snprintf(error_buf, error_buf_size, "Missing port");
657 }
658
659 goto error;
660 }
661
662 if (sscanf(port->str, "%d", &parts.port) != 1) {
663 if (error_buf) {
664 snprintf(error_buf, error_buf_size,
665 "Invalid port: `%s`", port->str);
666 }
667
668 g_string_free(port, TRUE);
669 goto error;
670 }
671
672 g_string_free(port, TRUE);
673
674 if (parts.port < 0 || parts.port >= 65536) {
675 if (error_buf) {
676 snprintf(error_buf, error_buf_size,
677 "Invalid port: %d", parts.port);
678 }
679
680 goto error;
681 }
682 }
683
684 if (at[end_pos] == '\0') {
685 goto end;
686 }
687
688 at += end_pos;
689
690 /* /host/ */
691 if (strncmp(at, "/host/", 6) != 0) {
692 if (error_buf) {
693 snprintf(error_buf, error_buf_size,
694 "Expecting `/host/` after hostname or port");
695 }
696
697 goto error;
698 }
699
700 at += 6;
701
702 /* Target hostname */
703 parts.target_hostname = bt_common_string_until(at, "", "/", &end_pos);
704 if (!parts.target_hostname || parts.target_hostname->len == 0) {
705 if (error_buf) {
706 snprintf(error_buf, error_buf_size,
707 "Missing target hostname");
708 }
709
710 goto error;
711 }
712
713 if (at[end_pos] == '\0') {
714 goto end;
715 }
716
717 at += end_pos + 1;
718
719 /* Session name */
720 parts.session_name = bt_common_string_until(at, "", "/", &end_pos);
721 if (!parts.session_name || parts.session_name->len == 0) {
722 if (error_buf) {
723 snprintf(error_buf, error_buf_size,
724 "Missing session name");
725 }
726
727 goto error;
728 }
729
730 if (at[end_pos] == '/') {
731 if (error_buf) {
732 snprintf(error_buf, error_buf_size,
733 "Unexpected `/` after session name (`%s`)",
734 parts.session_name->str);
735 }
736
737 goto error;
738 }
739
740 goto end;
741
742error:
743 bt_common_destroy_lttng_live_url_parts(&parts);
744
745end:
746 return parts;
747}
9009cc24
PP
748
749BT_HIDDEN
750void bt_common_normalize_star_glob_pattern(char *pattern)
751{
752 const char *p;
753 char *np;
754 bool got_star = false;
755
756 assert(pattern);
757
758 for (p = pattern, np = pattern; *p != '\0'; p++) {
759 switch (*p) {
760 case '*':
761 if (got_star) {
762 /* Avoid consecutive stars. */
763 continue;
764 }
765
766 got_star = true;
767 break;
768 case '\\':
769 /* Copy backslash character. */
770 *np = *p;
771 np++;
772 p++;
773
774 if (*p == '\0') {
775 goto end;
776 }
777
778 /* Fall through default case. */
779 default:
780 got_star = false;
781 break;
782 }
783
784 /* Copy single character. */
785 *np = *p;
786 np++;
787 }
788
789end:
790 *np = '\0';
791}
792
793static inline
794bool at_end_of_pattern(const char *p, const char *pattern, size_t pattern_len)
795{
796 return (p - pattern) == pattern_len || *p == '\0';
797}
798
799/*
800 * Globbing matching function with the star feature only (`?` and
801 * character sets are not supported). This matches `candidate` (plain
802 * string) against `pattern`. A literal star can be escaped with `\` in
803 * `pattern`.
804 *
805 * `pattern_len` or `candidate_len` can be greater than the actual
806 * string length of `pattern` or `candidate` if the string is
807 * null-terminated.
808 */
809BT_HIDDEN
810bool bt_common_star_glob_match(const char *pattern, size_t pattern_len,
811 const char *candidate, size_t candidate_len) {
812 const char *retry_c = candidate, *retry_p = pattern, *c, *p;
813 bool got_a_star = false;
814
815retry:
816 c = retry_c;
817 p = retry_p;
818
819 /*
820 * The concept here is to retry a match in the specific case
821 * where we already got a star. The retry position for the
822 * pattern is just after the most recent star, and the retry
823 * position for the candidate is the character following the
824 * last try's first character.
825 *
826 * Example:
827 *
828 * candidate: hi ev every onyx one
829 * ^
830 * pattern: hi*every*one
831 * ^
832 *
833 * candidate: hi ev every onyx one
834 * ^
835 * pattern: hi*every*one
836 * ^
837 *
838 * candidate: hi ev every onyx one
839 * ^
840 * pattern: hi*every*one
841 * ^
842 *
843 * candidate: hi ev every onyx one
844 * ^
845 * pattern: hi*every*one
846 * ^ MISMATCH
847 *
848 * candidate: hi ev every onyx one
849 * ^
850 * pattern: hi*every*one
851 * ^
852 *
853 * candidate: hi ev every onyx one
854 * ^^
855 * pattern: hi*every*one
856 * ^^
857 *
858 * candidate: hi ev every onyx one
859 * ^ ^
860 * pattern: hi*every*one
861 * ^ ^ MISMATCH
862 *
863 * candidate: hi ev every onyx one
864 * ^
865 * pattern: hi*every*one
866 * ^ MISMATCH
867 *
868 * candidate: hi ev every onyx one
869 * ^
870 * pattern: hi*every*one
871 * ^ MISMATCH
872 *
873 * candidate: hi ev every onyx one
874 * ^
875 * pattern: hi*every*one
876 * ^
877 *
878 * candidate: hi ev every onyx one
879 * ^^
880 * pattern: hi*every*one
881 * ^^
882 *
883 * candidate: hi ev every onyx one
884 * ^ ^
885 * pattern: hi*every*one
886 * ^ ^
887 *
888 * candidate: hi ev every onyx one
889 * ^ ^
890 * pattern: hi*every*one
891 * ^ ^
892 *
893 * candidate: hi ev every onyx one
894 * ^ ^
895 * pattern: hi*every*one
896 * ^ ^
897 *
898 * candidate: hi ev every onyx one
899 * ^
900 * pattern: hi*every*one
901 * ^
902 *
903 * candidate: hi ev every onyx one
904 * ^
905 * pattern: hi*every*one
906 * ^ MISMATCH
907 *
908 * candidate: hi ev every onyx one
909 * ^
910 * pattern: hi*every*one
911 * ^
912 *
913 * candidate: hi ev every onyx one
914 * ^^
915 * pattern: hi*every*one
916 * ^^
917 *
918 * candidate: hi ev every onyx one
919 * ^ ^
920 * pattern: hi*every*one
921 * ^ ^ MISMATCH
922 *
923 * candidate: hi ev every onyx one
924 * ^
925 * pattern: hi*every*one
926 * ^ MISMATCH
927 *
928 * candidate: hi ev every onyx one
929 * ^
930 * pattern: hi*every*one
931 * ^ MISMATCH
932 *
933 * candidate: hi ev every onyx one
934 * ^
935 * pattern: hi*every*one
936 * ^ MISMATCH
937 *
938 * candidate: hi ev every onyx one
939 * ^
940 * pattern: hi*every*one
941 * ^ MISMATCH
942 *
943 * candidate: hi ev every onyx one
944 * ^
945 * pattern: hi*every*one
946 * ^
947 *
948 * candidate: hi ev every onyx one
949 * ^^
950 * pattern: hi*every*one
951 * ^^
952 *
953 * candidate: hi ev every onyx one
954 * ^ ^
955 * pattern: hi*every*one
956 * ^ ^
957 *
958 * candidate: hi ev every onyx one
959 * ^ ^
960 * pattern: hi*every*one
961 * ^ ^ SUCCESS
962 */
963 while ((c - candidate) < candidate_len && *c != '\0') {
964 assert(*c);
965
966 if (at_end_of_pattern(p, pattern, pattern_len)) {
967 goto end_of_pattern;
968 }
969
970 switch (*p) {
971 case '*':
972 got_a_star = true;
973
974 /*
975 * Our first try starts at the current candidate
976 * character and after the star in the pattern.
977 */
978 retry_c = c;
979 retry_p = p + 1;
980
981 if (at_end_of_pattern(retry_p, pattern, pattern_len)) {
982 /*
983 * Star at the end of the pattern at
984 * this point: automatic match.
985 */
986 return true;
987 }
988
989 goto retry;
990 case '\\':
991 /* Go to escaped character. */
992 p++;
993
994 /*
995 * Fall through the default case which compares
996 * the escaped character now.
997 */
998 default:
999 if (at_end_of_pattern(p, pattern, pattern_len) ||
1000 *c != *p) {
1001end_of_pattern:
1002 /* Character mismatch OR end of pattern. */
1003 if (!got_a_star) {
1004 /*
1005 * We didn't get any star yet,
1006 * so this first mismatch
1007 * automatically makes the whole
1008 * test fail.
1009 */
1010 return false;
1011 }
1012
1013 /*
1014 * Next try: next candidate character,
1015 * original pattern character (following
1016 * the most recent star).
1017 */
1018 retry_c++;
1019 goto retry;
1020 }
1021 break;
1022 }
1023
1024 /* Next pattern and candidate characters. */
1025 c++;
1026 p++;
1027 }
1028
1029 /*
1030 * We checked every candidate character and we're still in a
1031 * success state: the only pattern character allowed to remain
1032 * is a star.
1033 */
1034 if (at_end_of_pattern(p, pattern, pattern_len)) {
1035 return true;
1036 }
1037
1038 p++;
1039 return p[-1] == '*' && at_end_of_pattern(p, pattern, pattern_len);
1040}
e49a18d1
PP
1041
1042static
1043void append_path_parts(const char *path, GPtrArray *parts)
1044{
1045 const char *ch = path;
1046 const char *last = path;
1047
1048 while (true) {
1049 if (*ch == G_DIR_SEPARATOR || *ch == '\0') {
1050 if (ch - last > 0) {
1051 GString *part = g_string_new(NULL);
1052
1053 assert(part);
1054 g_string_append_len(part, last, ch - last);
1055 g_ptr_array_add(parts, part);
1056 }
1057
1058 if (*ch == '\0') {
1059 break;
1060 }
1061
1062 last = ch + 1;
1063 }
1064
1065 ch++;
1066 }
1067}
1068
1069static
1070void destroy_gstring(void *gstring)
1071{
1072 (void) g_string_free(gstring, TRUE);
1073}
1074
1075BT_HIDDEN
1076GString *bt_common_normalize_path(const char *path, const char *wd)
1077{
1078 size_t i;
1079 GString *norm_path;
1080 GPtrArray *parts = NULL;
1081
1082 assert(path);
1083 norm_path = g_string_new(G_DIR_SEPARATOR_S);
1084 if (!norm_path) {
1085 goto error;
1086 }
1087
1088 parts = g_ptr_array_new_with_free_func(destroy_gstring);
1089 if (!parts) {
1090 goto error;
1091 }
1092
1093 if (path[0] != G_DIR_SEPARATOR) {
1094 /* Relative path: start with working directory */
1095 if (wd) {
1096 append_path_parts(wd, parts);
1097 } else {
1098 gchar *cd = g_get_current_dir();
1099
1100 append_path_parts(cd, parts);
1101 g_free(cd);
1102 }
1103 }
1104
1105 /* Append parts of the path parameter */
1106 append_path_parts(path, parts);
1107
1108 /* Resolve special `..` and `.` parts */
1109 for (i = 0; i < parts->len; i++) {
1110 GString *part = g_ptr_array_index(parts, i);
1111
1112 if (strcmp(part->str, "..") == 0) {
1113 if (i == 0) {
1114 /*
1115 * First part of absolute path is `..`:
1116 * this is invalid.
1117 */
1118 goto error;
1119 }
1120
1121 /* Remove `..` and previous part */
1122 g_ptr_array_remove_index(parts, i - 1);
1123 g_ptr_array_remove_index(parts, i - 1);
1124 i -= 2;
1125 } else if (strcmp(part->str, ".") == 0) {
1126 /* Remove `.` */
1127 g_ptr_array_remove_index(parts, i);
1128 i -= 1;
1129 }
1130 }
1131
1132 /* Create normalized path with what's left */
1133 for (i = 0; i < parts->len; i++) {
1134 GString *part = g_ptr_array_index(parts, i);
1135
1136 g_string_append(norm_path, part->str);
1137
1138 if (i < parts->len - 1) {
1139 g_string_append_c(norm_path, G_DIR_SEPARATOR);
1140 }
1141 }
1142
1143 goto end;
1144
1145error:
1146 if (norm_path) {
1147 g_string_free(norm_path, TRUE);
1148 norm_path = NULL;
1149 }
1150
1151end:
1152 if (parts) {
1153 g_ptr_array_free(parts, TRUE);
1154 }
1155
1156 return norm_path;
1157}
108e5a1e
MJ
1158
1159BT_HIDDEN
1160size_t bt_common_get_page_size(void)
1161{
1162 int page_size;
1163
1164 page_size = bt_sysconf(_SC_PAGESIZE);
1165 if (page_size < 0) {
1166 printf_error("Cannot get system page size.");
1167 abort();
1168 }
1169
1170 return page_size;
1171}
This page took 0.071438 seconds and 4 git commands to generate.