From 2456318bbe0ce49b4c235007d75c7186a3a42799 Mon Sep 17 00:00:00 2001
From: Sebastian Gniazdowski <sgniazdowski@gmail.com>
Date: Wed, 13 Jan 2021 22:00:56 -0600
Subject: [PATCH] Improve safety of previous char fetching string functions.
---
lib/strutil.h | 30 ++++++++---------
lib/strutil/strutil.c | 32 +++++++++---------
lib/strutil/strutil8bit.c | 4 ++-
lib/strutil/strutilascii.c | 4 ++-
lib/strutil/strutilutf8.c | 34 ++++++++++++++++---
lib/widget/input.c | 30 ++++++++++++-----
lib/widget/input_complete.c | 65 ++++++++++++++++++++++++-------------
src/help.c | 3 +-
src/usermenu.c | 46 ++++++++++++++------------
9 files changed, 156 insertions(+), 92 deletions(-)
diff --git a/lib/strutil.h b/lib/strutil.h
index a091c25aa..667f7df2e 100644
a
|
b
|
struct str_class |
110 | 110 | gboolean (*is_valid_string) (const char *); |
111 | 111 | /*I*/ int (*is_valid_char) (const char *, size_t); |
112 | 112 | /*I*/ void (*cnext_char) (const char **); |
113 | | void (*cprev_char) (const char **); |
| 113 | void (*cprev_char) (const char **, const char *begin); |
114 | 114 | void (*cnext_char_safe) (const char **); |
115 | | /*I*/ void (*cprev_char_safe) (const char **); |
| 115 | /*I*/ void (*cprev_char_safe) (const char **, const char *begin); |
116 | 116 | /*I*/ int (*cnext_noncomb_char) (const char **text); |
117 | 117 | /*I*/ int (*cprev_noncomb_char) (const char **text, const char *begin); |
118 | 118 | /*I*/ gboolean (*char_isspace) (const char *); |
… |
… |
int str_is_valid_char (const char *ch, size_t size); |
262 | 262 | char *str_get_next_char (char *text); |
263 | 263 | const char *str_cget_next_char (const char *text); |
264 | 264 | |
265 | | /* return previous characters before text, do not call on the start of strings |
| 265 | /* return previous characters before text |
266 | 266 | */ |
267 | | char *str_get_prev_char (char *text); |
268 | | const char *str_cget_prev_char (const char *text); |
| 267 | char *str_get_prev_char (char *text, const char *begin); |
| 268 | const char *str_cget_prev_char (const char *text, const char *begin); |
269 | 269 | |
270 | 270 | /* set text to next characters, do not call on the end of string |
271 | 271 | */ |
272 | 272 | void str_next_char (char **text); |
273 | 273 | void str_cnext_char (const char **text); |
274 | 274 | |
275 | | /* set text to previous characters, do not call on the start of strings |
| 275 | /* set text to previous characters |
276 | 276 | */ |
277 | | void str_prev_char (char **text); |
278 | | void str_cprev_char (const char **text); |
| 277 | void str_prev_char (char **text, const char *begin); |
| 278 | void str_cprev_char (const char **text, const char *begin); |
279 | 279 | |
280 | 280 | /* return next characters after text, do not call on the end of string |
281 | 281 | * works with invalid string |
… |
… |
void str_cprev_char (const char **text); |
284 | 284 | char *str_get_next_char_safe (char *text); |
285 | 285 | const char *str_cget_next_char_safe (const char *text); |
286 | 286 | |
287 | | /* return previous characters before text, do not call on the start of strings |
288 | | * works with invalid string |
| 287 | /* return previous characters before text, works with invalid string |
289 | 288 | * I |
290 | 289 | */ |
291 | | char *str_get_prev_char_safe (char *text); |
292 | | const char *str_cget_prev_char_safe (const char *text); |
| 290 | char *str_get_prev_char_safe (char *text, const char *begin); |
| 291 | const char *str_cget_prev_char_safe (const char *text, const char *begin); |
293 | 292 | |
294 | 293 | /* set text to next characters, do not call on the end of string |
295 | 294 | * works with invalid string |
… |
… |
const char *str_cget_prev_char_safe (const char *text); |
298 | 297 | void str_next_char_safe (char **text); |
299 | 298 | void str_cnext_char_safe (const char **text); |
300 | 299 | |
301 | | /* set text to previous characters, do not call on the start of strings |
302 | | * works with invalid string |
| 300 | /* set text to previous characters, works with invalid string |
303 | 301 | * I |
304 | 302 | */ |
305 | | void str_prev_char_safe (char **text); |
306 | | void str_cprev_char_safe (const char **text); |
| 303 | void str_prev_char_safe (char **text, const char *begin); |
| 304 | void str_cprev_char_safe (const char **text, const char *begin); |
307 | 305 | |
308 | 306 | /* set text to next noncombining characters, check the end of text |
309 | 307 | * return how many characters was skipped |
diff --git a/lib/strutil/strutil.c b/lib/strutil/strutil.c
index cf11d00d8..937256260 100644
a
|
b
|
str_cnext_char (const char **text) |
507 | 507 | /* --------------------------------------------------------------------------------------------- */ |
508 | 508 | |
509 | 509 | char * |
510 | | str_get_prev_char (char *text) |
| 510 | str_get_prev_char (char *text, const char *begin) |
511 | 511 | { |
512 | | used_class.cprev_char ((const char **) &text); |
| 512 | used_class.cprev_char ((const char **) &text, begin); |
513 | 513 | return text; |
514 | 514 | } |
515 | 515 | |
516 | 516 | /* --------------------------------------------------------------------------------------------- */ |
517 | 517 | |
518 | 518 | const char * |
519 | | str_cget_prev_char (const char *text) |
| 519 | str_cget_prev_char (const char *text, const char *begin) |
520 | 520 | { |
521 | | used_class.cprev_char (&text); |
| 521 | used_class.cprev_char (&text, begin); |
522 | 522 | return text; |
523 | 523 | } |
524 | 524 | |
525 | 525 | /* --------------------------------------------------------------------------------------------- */ |
526 | 526 | |
527 | 527 | void |
528 | | str_prev_char (char **text) |
| 528 | str_prev_char (char **text, const char *begin) |
529 | 529 | { |
530 | | used_class.cprev_char ((const char **) text); |
| 530 | used_class.cprev_char ((const char **) text, begin); |
531 | 531 | } |
532 | 532 | |
533 | 533 | /* --------------------------------------------------------------------------------------------- */ |
534 | 534 | |
535 | 535 | void |
536 | | str_cprev_char (const char **text) |
| 536 | str_cprev_char (const char **text, const char *begin) |
537 | 537 | { |
538 | | used_class.cprev_char (text); |
| 538 | used_class.cprev_char (text, begin); |
539 | 539 | } |
540 | 540 | |
541 | 541 | /* --------------------------------------------------------------------------------------------- */ |
… |
… |
str_cnext_char_safe (const char **text) |
575 | 575 | /* --------------------------------------------------------------------------------------------- */ |
576 | 576 | |
577 | 577 | char * |
578 | | str_get_prev_char_safe (char *text) |
| 578 | str_get_prev_char_safe (char *text, const char *begin) |
579 | 579 | { |
580 | | used_class.cprev_char_safe ((const char **) &text); |
| 580 | used_class.cprev_char_safe ((const char **) &text, begin); |
581 | 581 | return text; |
582 | 582 | } |
583 | 583 | |
584 | 584 | /* --------------------------------------------------------------------------------------------- */ |
585 | 585 | |
586 | 586 | const char * |
587 | | str_cget_prev_char_safe (const char *text) |
| 587 | str_cget_prev_char_safe (const char *text, const char *begin) |
588 | 588 | { |
589 | | used_class.cprev_char_safe (&text); |
| 589 | used_class.cprev_char_safe (&text, begin); |
590 | 590 | return text; |
591 | 591 | } |
592 | 592 | |
593 | 593 | /* --------------------------------------------------------------------------------------------- */ |
594 | 594 | |
595 | 595 | void |
596 | | str_prev_char_safe (char **text) |
| 596 | str_prev_char_safe (char **text, const char *begin) |
597 | 597 | { |
598 | | used_class.cprev_char_safe ((const char **) text); |
| 598 | used_class.cprev_char_safe ((const char **) text, begin); |
599 | 599 | } |
600 | 600 | |
601 | 601 | /* --------------------------------------------------------------------------------------------- */ |
602 | 602 | |
603 | 603 | void |
604 | | str_cprev_char_safe (const char **text) |
| 604 | str_cprev_char_safe (const char **text, const char *begin) |
605 | 605 | { |
606 | | used_class.cprev_char_safe (text); |
| 606 | used_class.cprev_char_safe (text, begin); |
607 | 607 | } |
608 | 608 | |
609 | 609 | /* --------------------------------------------------------------------------------------------- */ |
diff --git a/lib/strutil/strutil8bit.c b/lib/strutil/strutil8bit.c
index fa7bbf6a4..755a66ddb 100644
a
|
b
|
str_8bit_cnext_char (const char **text) |
112 | 112 | /* --------------------------------------------------------------------------------------------- */ |
113 | 113 | |
114 | 114 | static void |
115 | | str_8bit_cprev_char (const char **text) |
| 115 | str_8bit_cprev_char (const char **text, const char *begin) |
116 | 116 | { |
117 | 117 | (*text)--; |
| 118 | if (*text < begin) |
| 119 | *text = NULL; |
118 | 120 | } |
119 | 121 | |
120 | 122 | /* --------------------------------------------------------------------------------------------- */ |
diff --git a/lib/strutil/strutilascii.c b/lib/strutil/strutilascii.c
index 7a585303e..a18d34bd7 100644
a
|
b
|
str_ascii_cnext_char (const char **text) |
85 | 85 | /* --------------------------------------------------------------------------------------------- */ |
86 | 86 | |
87 | 87 | static void |
88 | | str_ascii_cprev_char (const char **text) |
| 88 | str_ascii_cprev_char (const char **text, const char *begin) |
89 | 89 | { |
90 | 90 | (*text)--; |
| 91 | if (*text < begin) |
| 92 | *text = NULL; |
91 | 93 | } |
92 | 94 | |
93 | 95 | /* --------------------------------------------------------------------------------------------- */ |
diff --git a/lib/strutil/strutilutf8.c b/lib/strutil/strutilutf8.c
index 5ac0015e6..37a24be62 100644
a
|
b
|
str_utf8_cnext_char (const char **text) |
117 | 117 | /* --------------------------------------------------------------------------------------------- */ |
118 | 118 | |
119 | 119 | static void |
120 | | str_utf8_cprev_char (const char **text) |
| 120 | str_utf8_cprev_char (const char **text, const char *begin) |
121 | 121 | { |
122 | | (*text) = g_utf8_prev_char (*text); |
| 122 | (*text) = g_utf8_find_prev_char (begin, *text); |
123 | 123 | } |
124 | 124 | |
125 | 125 | /* --------------------------------------------------------------------------------------------- */ |
… |
… |
str_utf8_cnext_char_safe (const char **text) |
136 | 136 | /* --------------------------------------------------------------------------------------------- */ |
137 | 137 | |
138 | 138 | static void |
139 | | str_utf8_cprev_char_safe (const char **text) |
| 139 | str_utf8_cprev_char_safe (const char **text, const char *begin) |
140 | 140 | { |
141 | 141 | const char *result, *t; |
142 | 142 | |
143 | | result = g_utf8_prev_char (*text); |
| 143 | result = g_utf8_find_prev_char (begin, *text); |
| 144 | /* Beginning of the string reached (if NULL)? */ |
| 145 | if (!result) |
| 146 | { |
| 147 | *text = NULL; |
| 148 | return; |
| 149 | } |
| 150 | |
144 | 151 | t = result; |
145 | 152 | str_utf8_cnext_char_safe (&t); |
146 | 153 | if (t == *text) |
147 | 154 | (*text) = result; |
148 | 155 | else |
149 | 156 | (*text)--; |
| 157 | |
| 158 | /* Additional check to ensure no buffer underruns. */ |
| 159 | if (*text && *text < begin) |
| 160 | *text = NULL; |
150 | 161 | } |
151 | 162 | |
152 | 163 | /* --------------------------------------------------------------------------------------------- */ |
… |
… |
str_utf8_cprev_noncomb_char (const char **text, const char *begin) |
262 | 273 | |
263 | 274 | while ((*text) != begin) |
264 | 275 | { |
265 | | str_utf8_cprev_char_safe (text); |
| 276 | str_utf8_cprev_char_safe (text, begin); |
266 | 277 | count++; |
267 | 278 | if (!str_utf8_iscombiningmark (*text)) |
268 | 279 | break; |
… |
… |
str_utf8_trunc (const char *text, int width) |
889 | 900 | } |
890 | 901 | |
891 | 902 | /* --------------------------------------------------------------------------------------------- */ |
| 903 | /* Converts a character index into a byte offset. */ |
892 | 904 | |
893 | 905 | static int |
894 | 906 | str_utf8_offset_to_pos (const char *text, size_t length) |
895 | 907 | { |
| 908 | glong size; |
| 909 | |
896 | 910 | if (str_utf8_is_valid_string (text)) |
| 911 | { |
| 912 | /* Limit index by string size. */ |
| 913 | size = g_utf8_strlen (text, -1); |
| 914 | if (size < (glong) length) |
| 915 | length = (size_t) size; |
897 | 916 | return g_utf8_offset_to_pointer (text, length) - text; |
| 917 | } |
898 | 918 | else |
899 | 919 | { |
900 | 920 | int result; |
… |
… |
str_utf8_offset_to_pos (const char *text, size_t length) |
902 | 922 | |
903 | 923 | buffer = g_string_new (text); |
904 | 924 | str_utf8_fix_string (buffer->str); |
| 925 | /* Limit index by string size. */ |
| 926 | size = g_utf8_strlen (buffer->str, -1); |
| 927 | if (size < (glong) length) |
| 928 | length = (size_t) size; |
905 | 929 | result = g_utf8_offset_to_pointer (buffer->str, length) - buffer->str; |
906 | 930 | g_string_free (buffer, TRUE); |
907 | 931 | return result; |
diff --git a/lib/widget/input.c b/lib/widget/input.c
index 625b394a9..d42623741 100644
a
|
b
|
backward_word (WInput * in) |
425 | 425 | { |
426 | 426 | const char *p; |
427 | 427 | |
| 428 | /* p is limited by strlen. */ |
428 | 429 | p = in->buffer + str_offset_to_pos (in->buffer, in->point); |
429 | 430 | |
430 | | while (p != in->buffer) |
| 431 | while (p && p != in->buffer) |
431 | 432 | { |
432 | 433 | const char *p_tmp; |
433 | 434 | |
434 | 435 | p_tmp = p; |
435 | | str_cprev_char (&p); |
436 | | if (!str_isspace (p) && !str_ispunct (p)) |
| 436 | str_cprev_char (&p, in->buffer); |
| 437 | if (p) |
437 | 438 | { |
438 | | p = p_tmp; |
439 | | break; |
| 439 | /* |
| 440 | * If preceding char isn't a word boundary (↔ we're ·in· a word), then undo last move and |
| 441 | * break from loop. |
| 442 | */ |
| 443 | |
| 444 | if (!str_isspace (p) && !str_ispunct (p)) |
| 445 | { |
| 446 | p = p_tmp; |
| 447 | break; |
| 448 | } |
| 449 | in->point--; |
440 | 450 | } |
441 | | in->point--; |
442 | 451 | } |
443 | | while (p != in->buffer) |
| 452 | |
| 453 | /* Further skip the ·word· chars, if not outside the string. */ |
| 454 | while (p && p != in->buffer) |
444 | 455 | { |
445 | | str_cprev_char (&p); |
446 | | if (str_isspace (p) || str_ispunct (p)) |
| 456 | str_cprev_char (&p, in->buffer); |
| 457 | /* Stop when a word boundary char is detected or when the string ends. */ |
| 458 | if (!p || str_isspace (p) || str_ispunct (p)) |
447 | 459 | break; |
448 | 460 | |
449 | 461 | in->point--; |
diff --git a/lib/widget/input_complete.c b/lib/widget/input_complete.c
index 59a994d62..22aeb2312 100644
a
|
b
|
try_complete_commands_prepare (try_complete_automation_state_t * state, char *te |
843 | 843 | ti = text; |
844 | 844 | else |
845 | 845 | { |
846 | | ti = str_get_prev_char (&text[*lc_start]); |
| 846 | ti = str_get_prev_char (&text[*lc_start], text); |
847 | 847 | while (ti > text && whitespace (ti[0])) |
848 | | str_prev_char (&ti); |
| 848 | str_prev_char (&ti, text); |
849 | 849 | } |
850 | 850 | |
851 | | if (ti == text) |
852 | | state->in_command_position++; |
853 | | else if (strchr (command_separator_chars, ti[0]) != NULL) |
| 851 | if (!ti) |
854 | 852 | { |
855 | 853 | state->in_command_position++; |
856 | | if (ti != text) |
857 | | { |
858 | | int this_char, prev_char; |
| 854 | ti = text; |
| 855 | } |
859 | 856 | |
860 | | /* Handle the two character tokens '>&', '<&', and '>|'. |
861 | | We are not in a command position after one of these. */ |
862 | | this_char = ti[0]; |
863 | | prev_char = str_get_prev_char (ti)[0]; |
| 857 | /* Is there any more preceding text, and there's a command separator? */ |
| 858 | if (ti != text && strchr (command_separator_chars, ti[0]) != NULL) |
| 859 | { |
| 860 | int this_char, prev_char = '\0'; |
| 861 | char *prev_char_p; |
864 | 862 | |
865 | | /* Quoted */ |
866 | | if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) |
867 | | || (this_char == '|' && prev_char == '>') || (ti != text |
868 | | && str_get_prev_char (ti)[0] == '\\')) |
869 | | state->in_command_position = 0; |
870 | | } |
| 863 | /* Initial assumption that we're at command. */ |
| 864 | state->in_command_position++; |
| 865 | |
| 866 | /* Handle the two character tokens '>&', '<&', and '>|'. |
| 867 | We are not in a command position after one of these. */ |
| 868 | this_char = ti[0]; |
| 869 | prev_char_p = str_get_prev_char (ti, text); |
| 870 | if (prev_char_p) |
| 871 | prev_char = prev_char_p[0]; |
| 872 | |
| 873 | if ((this_char == '&' && (strchr ("<>", prev_char))) |
| 874 | || (this_char == '|' && prev_char == '>') || prev_char == '\\') |
| 875 | state->in_command_position = 0; |
871 | 876 | } |
872 | 877 | } |
873 | 878 | |
… |
… |
complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void |
1043 | 1048 | /* Refill the list box and start again */ |
1044 | 1049 | else if (end == min_end) |
1045 | 1050 | { |
1046 | | end = str_get_prev_char (&input->buffer[end]) - input->buffer; |
| 1051 | end = str_get_prev_char (&input->buffer[end], input->buffer) - input->buffer; |
| 1052 | if (end < 0) |
| 1053 | end = 0; |
1047 | 1054 | input_handle_char (input, parm); |
1048 | 1055 | h->ret_value = B_USER; |
1049 | 1056 | dlg_stop (h); |
… |
… |
complete_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void |
1054 | 1061 | int i; |
1055 | 1062 | GList *e; |
1056 | 1063 | |
1057 | | new_end = str_get_prev_char (&input->buffer[end]) - input->buffer; |
| 1064 | new_end = str_get_prev_char (&input->buffer[end], input->buffer) - input->buffer; |
| 1065 | /* The buffer is empty (no previous char available)? */ |
| 1066 | if (new_end < 0) |
| 1067 | new_end = 0; |
1058 | 1068 | |
1059 | 1069 | for (i = 0, e = listbox_get_first_link (LISTBOX (g->current->data)); |
1060 | 1070 | e != NULL; i++, e = g_list_next (e)) |
… |
… |
complete_engine_fill_completions (WInput * in) |
1401 | 1411 | { |
1402 | 1412 | char *s; |
1403 | 1413 | const char *word_separators; |
| 1414 | gboolean separator_found = FALSE; |
1404 | 1415 | |
1405 | 1416 | word_separators = (in->completion_flags & INPUT_COMPLETE_SHELL_ESC) ? " \t;|<>" : "\t;|<>"; |
1406 | 1417 | |
… |
… |
complete_engine_fill_completions (WInput * in) |
1416 | 1427 | str_next_char (&s); |
1417 | 1428 | } |
1418 | 1429 | |
1419 | | for (; s >= in->buffer; str_prev_char (&s)) |
| 1430 | for (; s; str_prev_char (&s, in->buffer)) |
1420 | 1431 | { |
1421 | 1432 | start = s - in->buffer; |
1422 | 1433 | if (strchr (word_separators, *s) != NULL && !strutils_is_char_escaped (in->buffer, s)) |
| 1434 | { |
| 1435 | separator_found = TRUE; |
1423 | 1436 | break; |
| 1437 | } |
1424 | 1438 | } |
1425 | 1439 | |
| 1440 | /* Note: str_prev_char() returns NULL if no preceding character fitting within string found. */ |
| 1441 | if (s < in->buffer) |
| 1442 | s = in->buffer; |
| 1443 | |
1426 | 1444 | if (start < end) |
1427 | 1445 | { |
1428 | | str_next_char (&s); |
| 1446 | if (separator_found) |
| 1447 | str_next_char (&s); |
| 1448 | if (s > in->buffer + end) |
| 1449 | s = in->buffer + end; |
1429 | 1450 | start = s - in->buffer; |
1430 | 1451 | } |
1431 | 1452 | |
diff --git a/src/help.c b/src/help.c
index f5922f086..2c437ea57 100644
a
|
b
|
move_backward2 (const char *c, int lines) |
229 | 229 | int line; |
230 | 230 | |
231 | 231 | currentpoint = c; |
232 | | for (line = 0, p = currentpoint; (*p != '\0') && ((int) (p - fdata) >= 0); str_cprev_char (&p)) |
| 232 | for (line = 0, p = currentpoint; p && (*p != '\0') && ((int) (p - fdata) >= 0); |
| 233 | str_cprev_char (&p, fdata)) |
233 | 234 | { |
234 | 235 | if (*p == CHAR_NODE_END) |
235 | 236 | { |
diff --git a/src/usermenu.c b/src/usermenu.c
index 698244220..695a56814 100644
a
|
b
|
check_patterns (char *p) |
133 | 133 | point after argument. */ |
134 | 134 | |
135 | 135 | static char * |
136 | | extract_arg (char *p, char *arg, int size) |
| 136 | extract_arg (char *p, char *arg, const char *begin, int size) |
137 | 137 | { |
138 | 138 | while (*p != '\0' && whiteness (*p)) |
139 | 139 | p++; |
… |
… |
extract_arg (char *p, char *arg, int size) |
152 | 152 | p = np; |
153 | 153 | } |
154 | 154 | *arg = '\0'; |
155 | | if (*p == '\0' || *p == '\n') |
156 | | str_prev_char (&p); |
| 155 | if (p && (*p == '\0' || *p == '\n')) |
| 156 | str_prev_char (&p, begin); |
| 157 | if (!p) |
| 158 | p = (char *) begin; |
157 | 159 | return p; |
158 | 160 | } |
159 | 161 | |
… |
… |
test_type (WPanel * panel, char *arg) |
215 | 217 | p. Returns the point after condition. */ |
216 | 218 | |
217 | 219 | static char * |
218 | | test_condition (const WEdit * edit_widget, char *p, gboolean * condition) |
| 220 | test_condition (const WEdit * edit_widget, char *p, const char *begin, gboolean * condition) |
219 | 221 | { |
220 | 222 | char arg[256]; |
221 | 223 | const mc_search_type_t search_type = easy_patterns ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX; |
222 | 224 | |
223 | 225 | /* Handle one condition */ |
224 | | for (; *p != '\n' && *p != '&' && *p != '|'; p++) |
| 226 | for (; p && *p != '\n' && *p != '&' && *p != '|'; p++) |
225 | 227 | { |
226 | 228 | WPanel *panel = NULL; |
227 | 229 | |
… |
… |
test_condition (const WEdit * edit_widget, char *p, gboolean * condition) |
238 | 240 | switch (*p++) |
239 | 241 | { |
240 | 242 | case '!': |
241 | | p = test_condition (edit_widget, p, condition); |
| 243 | p = test_condition (edit_widget, p, begin, condition); |
242 | 244 | *condition = !*condition; |
243 | | str_prev_char (&p); |
| 245 | str_prev_char (&p, begin); |
244 | 246 | break; |
245 | 247 | case 'f': /* file name pattern */ |
246 | | p = extract_arg (p, arg, sizeof (arg)); |
| 248 | p = extract_arg (p, arg, begin, sizeof (arg)); |
247 | 249 | #ifdef USE_INTERNAL_EDIT |
248 | 250 | if (edit_widget != NULL) |
249 | 251 | { |
… |
… |
test_condition (const WEdit * edit_widget, char *p, gboolean * condition) |
267 | 269 | syntax_type = edit_get_syntax_type (edit_widget); |
268 | 270 | if (syntax_type != NULL) |
269 | 271 | { |
270 | | p = extract_arg (p, arg, sizeof (arg)); |
| 272 | p = extract_arg (p, arg, begin, sizeof (arg)); |
271 | 273 | *condition = mc_search (arg, DEFAULT_CHARSET, syntax_type, MC_SEARCH_T_NORMAL); |
272 | 274 | } |
273 | 275 | } |
274 | 276 | #endif |
275 | 277 | break; |
276 | 278 | case 'd': |
277 | | p = extract_arg (p, arg, sizeof (arg)); |
| 279 | p = extract_arg (p, arg, begin, sizeof (arg)); |
278 | 280 | *condition = panel != NULL |
279 | 281 | && mc_search (arg, DEFAULT_CHARSET, vfs_path_as_str (panel->cwd_vpath), |
280 | 282 | search_type); |
281 | 283 | break; |
282 | 284 | case 't': |
283 | | p = extract_arg (p, arg, sizeof (arg)); |
| 285 | p = extract_arg (p, arg, begin, sizeof (arg)); |
284 | 286 | *condition = panel != NULL && test_type (panel, arg); |
285 | 287 | break; |
286 | 288 | case 'x': /* executable */ |
287 | 289 | { |
288 | 290 | struct stat status; |
289 | 291 | |
290 | | p = extract_arg (p, arg, sizeof (arg)); |
| 292 | p = extract_arg (p, arg, begin, sizeof (arg)); |
291 | 293 | *condition = stat (arg, &status) == 0 && is_exe (status.st_mode); |
292 | 294 | break; |
293 | 295 | } |
… |
… |
debug_out (char *start, char *end, gboolean condition) |
356 | 358 | the point just before the end of line. */ |
357 | 359 | |
358 | 360 | static char * |
359 | | test_line (const WEdit * edit_widget, char *p, gboolean * result) |
| 361 | test_line (const WEdit * edit_widget, char *p, const char *begin, gboolean * result) |
360 | 362 | { |
361 | 363 | char operator; |
362 | 364 | |
363 | 365 | /* Repeat till end of line */ |
364 | | while (*p != '\0' && *p != '\n') |
| 366 | while (p && *p != '\0' && *p != '\n') |
365 | 367 | { |
366 | 368 | char *debug_start, *debug_end; |
367 | 369 | gboolean condition = TRUE; |
… |
… |
test_line (const WEdit * edit_widget, char *p, gboolean * result) |
384 | 386 | break; |
385 | 387 | |
386 | 388 | debug_start = p; |
387 | | p = test_condition (edit_widget, p, &condition); |
| 389 | p = test_condition (edit_widget, p, begin, &condition); |
388 | 390 | debug_end = p; |
389 | 391 | /* Add one debug statement */ |
390 | 392 | debug_out (debug_start, debug_end, condition); |
… |
… |
test_line (const WEdit * edit_widget, char *p, gboolean * result) |
413 | 415 | /* Report debug message */ |
414 | 416 | debug_out (NULL, NULL, TRUE); |
415 | 417 | |
416 | | if (*p == '\0' || *p == '\n') |
417 | | str_prev_char (&p); |
| 418 | if (p && (*p == '\0' || *p == '\n')) |
| 419 | str_prev_char (&p, begin); |
| 420 | if (!p) |
| 421 | p = (char *) begin; |
418 | 422 | return p; |
419 | 423 | } |
420 | 424 | |
… |
… |
user_menu_cmd (const WEdit * edit_widget, const char *menu_file, int selected_en |
1037 | 1041 | if (*(p + 1) == '=') |
1038 | 1042 | { |
1039 | 1043 | /* Combined adding and default */ |
1040 | | p = test_line (edit_widget, p + 1, &accept_entry); |
| 1044 | p = test_line (edit_widget, p + 1, data, &accept_entry); |
1041 | 1045 | if (selected == 0 && accept_entry) |
1042 | 1046 | selected = menu_lines; |
1043 | 1047 | } |
1044 | 1048 | else |
1045 | 1049 | { |
1046 | 1050 | /* A condition for adding the entry */ |
1047 | | p = test_line (edit_widget, p, &accept_entry); |
| 1051 | p = test_line (edit_widget, p, data, &accept_entry); |
1048 | 1052 | } |
1049 | 1053 | break; |
1050 | 1054 | |
… |
… |
user_menu_cmd (const WEdit * edit_widget, const char *menu_file, int selected_en |
1052 | 1056 | if (*(p + 1) == '+') |
1053 | 1057 | { |
1054 | 1058 | /* Combined adding and default */ |
1055 | | p = test_line (edit_widget, p + 1, &accept_entry); |
| 1059 | p = test_line (edit_widget, p + 1, data, &accept_entry); |
1056 | 1060 | if (selected == 0 && accept_entry) |
1057 | 1061 | selected = menu_lines; |
1058 | 1062 | } |
… |
… |
user_menu_cmd (const WEdit * edit_widget, const char *menu_file, int selected_en |
1060 | 1064 | { |
1061 | 1065 | /* A condition for making the entry default */ |
1062 | 1066 | i = 1; |
1063 | | p = test_line (edit_widget, p, &i); |
| 1067 | p = test_line (edit_widget, p, data, &i); |
1064 | 1068 | if (selected == 0 && i != 0) |
1065 | 1069 | selected = menu_lines; |
1066 | 1070 | } |