diff options
Diffstat (limited to 'editors')
-rw-r--r-- | editors/sed.c | 38 | ||||
-rw-r--r-- | editors/vi.c | 97 |
2 files changed, 82 insertions, 53 deletions
diff --git a/editors/sed.c b/editors/sed.c index c8bb503ea..4e9babb9d 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -282,7 +282,7 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str) | |||
282 | static int parse_regex_delim(const char *cmdstr, char **match, char **replace) | 282 | static int parse_regex_delim(const char *cmdstr, char **match, char **replace) |
283 | { | 283 | { |
284 | const char *cmdstr_ptr = cmdstr; | 284 | const char *cmdstr_ptr = cmdstr; |
285 | char delimiter; | 285 | unsigned char delimiter; |
286 | int idx = 0; | 286 | int idx = 0; |
287 | 287 | ||
288 | /* verify that the 's' or 'y' is followed by something. That something | 288 | /* verify that the 's' or 'y' is followed by something. That something |
@@ -297,7 +297,7 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace) | |||
297 | 297 | ||
298 | /* save the replacement string */ | 298 | /* save the replacement string */ |
299 | cmdstr_ptr += idx + 1; | 299 | cmdstr_ptr += idx + 1; |
300 | idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr); | 300 | idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); |
301 | *replace = copy_parsing_escapes(cmdstr_ptr, idx); | 301 | *replace = copy_parsing_escapes(cmdstr_ptr, idx); |
302 | 302 | ||
303 | return ((cmdstr_ptr - cmdstr) + idx); | 303 | return ((cmdstr_ptr - cmdstr) + idx); |
@@ -322,10 +322,11 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex) | |||
322 | char *temp; | 322 | char *temp; |
323 | 323 | ||
324 | delimiter = '/'; | 324 | delimiter = '/'; |
325 | if (*my_str == '\\') delimiter = *++pos; | 325 | if (*my_str == '\\') |
326 | delimiter = *++pos; | ||
326 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); | 327 | next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); |
327 | temp = copy_parsing_escapes(pos, next); | 328 | temp = copy_parsing_escapes(pos, next); |
328 | *regex = xmalloc(sizeof(regex_t)); | 329 | *regex = xzalloc(sizeof(regex_t)); |
329 | xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); | 330 | xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); |
330 | free(temp); | 331 | free(temp); |
331 | /* Move position to next character after last delimiter */ | 332 | /* Move position to next character after last delimiter */ |
@@ -434,8 +435,10 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) | |||
434 | /* compile the match string into a regex */ | 435 | /* compile the match string into a regex */ |
435 | if (*match != '\0') { | 436 | if (*match != '\0') { |
436 | /* If match is empty, we use last regex used at runtime */ | 437 | /* If match is empty, we use last regex used at runtime */ |
437 | sed_cmd->sub_match = xmalloc(sizeof(regex_t)); | 438 | sed_cmd->sub_match = xzalloc(sizeof(regex_t)); |
439 | dbg("xregcomp('%s',%x)", match, cflags); | ||
438 | xregcomp(sed_cmd->sub_match, match, cflags); | 440 | xregcomp(sed_cmd->sub_match, match, cflags); |
441 | dbg("regcomp ok"); | ||
439 | } | 442 | } |
440 | free(match); | 443 | free(match); |
441 | 444 | ||
@@ -717,8 +720,12 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) | |||
717 | G.previous_regex_ptr = current_regex; | 720 | G.previous_regex_ptr = current_regex; |
718 | 721 | ||
719 | /* Find the first match */ | 722 | /* Find the first match */ |
720 | if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) | 723 | dbg("matching '%s'", line); |
724 | if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) { | ||
725 | dbg("no match"); | ||
721 | return 0; | 726 | return 0; |
727 | } | ||
728 | dbg("match"); | ||
722 | 729 | ||
723 | /* Initialize temporary output buffer. */ | 730 | /* Initialize temporary output buffer. */ |
724 | G.pipeline.buf = xmalloc(PIPE_GROW); | 731 | G.pipeline.buf = xmalloc(PIPE_GROW); |
@@ -730,9 +737,10 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) | |||
730 | int i; | 737 | int i; |
731 | 738 | ||
732 | /* Work around bug in glibc regexec, demonstrated by: | 739 | /* Work around bug in glibc regexec, demonstrated by: |
733 | echo " a.b" | busybox sed 's [^ .]* x g' | 740 | * echo " a.b" | busybox sed 's [^ .]* x g' |
734 | The match_count check is so not to break | 741 | * The match_count check is so not to break |
735 | echo "hi" | busybox sed 's/^/!/g' */ | 742 | * echo "hi" | busybox sed 's/^/!/g' |
743 | */ | ||
736 | if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { | 744 | if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { |
737 | pipe_putc(*line++); | 745 | pipe_putc(*line++); |
738 | continue; | 746 | continue; |
@@ -763,11 +771,14 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) | |||
763 | altered++; | 771 | altered++; |
764 | 772 | ||
765 | /* if we're not doing this globally, get out now */ | 773 | /* if we're not doing this globally, get out now */ |
766 | if (sed_cmd->which_match) | 774 | if (sed_cmd->which_match != 0) |
775 | break; | ||
776 | |||
777 | if (*line == '\0') | ||
767 | break; | 778 | break; |
768 | 779 | ||
769 | //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? | 780 | //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? |
770 | } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); | 781 | } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); |
771 | 782 | ||
772 | /* Copy rest of string into output pipeline */ | 783 | /* Copy rest of string into output pipeline */ |
773 | while (1) { | 784 | while (1) { |
@@ -1067,8 +1078,8 @@ static void process_files(void) | |||
1067 | } | 1078 | } |
1068 | 1079 | ||
1069 | /* actual sedding */ | 1080 | /* actual sedding */ |
1070 | //bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c", | 1081 | dbg("pattern_space:'%s' next_line:'%s' cmd:%c", |
1071 | //pattern_space, next_line, sed_cmd->cmd); | 1082 | pattern_space, next_line, sed_cmd->cmd); |
1072 | switch (sed_cmd->cmd) { | 1083 | switch (sed_cmd->cmd) { |
1073 | 1084 | ||
1074 | /* Print line number */ | 1085 | /* Print line number */ |
@@ -1115,6 +1126,7 @@ static void process_files(void) | |||
1115 | case 's': | 1126 | case 's': |
1116 | if (!do_subst_command(sed_cmd, &pattern_space)) | 1127 | if (!do_subst_command(sed_cmd, &pattern_space)) |
1117 | break; | 1128 | break; |
1129 | dbg("do_subst_command succeeeded:'%s'", pattern_space); | ||
1118 | substituted |= 1; | 1130 | substituted |= 1; |
1119 | 1131 | ||
1120 | /* handle p option */ | 1132 | /* handle p option */ |
diff --git a/editors/vi.c b/editors/vi.c index d6d926e35..6fae221ac 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -278,7 +278,6 @@ struct globals { | |||
278 | smallint cmd_mode; // 0=command 1=insert 2=replace | 278 | smallint cmd_mode; // 0=command 1=insert 2=replace |
279 | int file_modified; // buffer contents changed (counter, not flag!) | 279 | int file_modified; // buffer contents changed (counter, not flag!) |
280 | int last_file_modified; // = -1; | 280 | int last_file_modified; // = -1; |
281 | int fn_start; // index of first cmd line file name | ||
282 | int save_argc; // how many file names on cmd line | 281 | int save_argc; // how many file names on cmd line |
283 | int cmdcnt; // repetition count | 282 | int cmdcnt; // repetition count |
284 | unsigned rows, columns; // the terminal screen is this size | 283 | unsigned rows, columns; // the terminal screen is this size |
@@ -363,7 +362,6 @@ struct globals { | |||
363 | #define cmd_mode (G.cmd_mode ) | 362 | #define cmd_mode (G.cmd_mode ) |
364 | #define file_modified (G.file_modified ) | 363 | #define file_modified (G.file_modified ) |
365 | #define last_file_modified (G.last_file_modified ) | 364 | #define last_file_modified (G.last_file_modified ) |
366 | #define fn_start (G.fn_start ) | ||
367 | #define save_argc (G.save_argc ) | 365 | #define save_argc (G.save_argc ) |
368 | #define cmdcnt (G.cmdcnt ) | 366 | #define cmdcnt (G.cmdcnt ) |
369 | #define rows (G.rows ) | 367 | #define rows (G.rows ) |
@@ -599,9 +597,10 @@ int vi_main(int argc, char **argv) | |||
599 | } | 597 | } |
600 | 598 | ||
601 | // The argv array can be used by the ":next" and ":rewind" commands | 599 | // The argv array can be used by the ":next" and ":rewind" commands |
602 | // save optind. | 600 | argv += optind; |
603 | fn_start = optind; // remember first file name for :next and :rew | 601 | argc -= optind; |
604 | save_argc = argc; | 602 | save_argc = argc; |
603 | optind = 0; | ||
605 | 604 | ||
606 | //----- This is the main file handling loop -------------- | 605 | //----- This is the main file handling loop -------------- |
607 | while (1) { | 606 | while (1) { |
@@ -1021,7 +1020,7 @@ static void colon(char *buf) | |||
1021 | } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file | 1020 | } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file |
1022 | // don't edit, if the current file has been modified | 1021 | // don't edit, if the current file has been modified |
1023 | if (file_modified && !useforce) { | 1022 | if (file_modified && !useforce) { |
1024 | status_line_bold("No write since last change (:edit! overrides)"); | 1023 | status_line_bold("No write since last change (:%s! overrides)", cmd); |
1025 | goto ret; | 1024 | goto ret; |
1026 | } | 1025 | } |
1027 | if (args[0]) { | 1026 | if (args[0]) { |
@@ -1040,13 +1039,13 @@ static void colon(char *buf) | |||
1040 | goto ret; | 1039 | goto ret; |
1041 | 1040 | ||
1042 | #if ENABLE_FEATURE_VI_YANKMARK | 1041 | #if ENABLE_FEATURE_VI_YANKMARK |
1043 | if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { | 1042 | if (Ureg >= 0 && Ureg < 28) { |
1044 | free(reg[Ureg]); // free orig line reg- for 'U' | 1043 | free(reg[Ureg]); // free orig line reg- for 'U' |
1045 | reg[Ureg]= 0; | 1044 | reg[Ureg] = NULL; |
1046 | } | 1045 | } |
1047 | if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { | 1046 | if (YDreg >= 0 && YDreg < 28) { |
1048 | free(reg[YDreg]); // free default yank/delete register | 1047 | free(reg[YDreg]); // free default yank/delete register |
1049 | reg[YDreg]= 0; | 1048 | reg[YDreg] = NULL; |
1050 | } | 1049 | } |
1051 | #endif | 1050 | #endif |
1052 | // how many lines in text[]? | 1051 | // how many lines in text[]? |
@@ -1111,11 +1110,12 @@ static void colon(char *buf) | |||
1111 | Hit_Return(); | 1110 | Hit_Return(); |
1112 | } else if (strncmp(cmd, "quit", i) == 0 // quit | 1111 | } else if (strncmp(cmd, "quit", i) == 0 // quit |
1113 | || strncmp(cmd, "next", i) == 0 // edit next file | 1112 | || strncmp(cmd, "next", i) == 0 // edit next file |
1113 | || strncmp(cmd, "prev", i) == 0 // edit previous file | ||
1114 | ) { | 1114 | ) { |
1115 | int n; | 1115 | int n; |
1116 | if (useforce) { | 1116 | if (useforce) { |
1117 | // force end of argv list | ||
1118 | if (*cmd == 'q') { | 1117 | if (*cmd == 'q') { |
1118 | // force end of argv list | ||
1119 | optind = save_argc; | 1119 | optind = save_argc; |
1120 | } | 1120 | } |
1121 | editing = 0; | 1121 | editing = 0; |
@@ -1123,8 +1123,7 @@ static void colon(char *buf) | |||
1123 | } | 1123 | } |
1124 | // don't exit if the file been modified | 1124 | // don't exit if the file been modified |
1125 | if (file_modified) { | 1125 | if (file_modified) { |
1126 | status_line_bold("No write since last change (:%s! overrides)", | 1126 | status_line_bold("No write since last change (:%s! overrides)", cmd); |
1127 | (*cmd == 'q' ? "quit" : "next")); | ||
1128 | goto ret; | 1127 | goto ret; |
1129 | } | 1128 | } |
1130 | // are there other file to edit | 1129 | // are there other file to edit |
@@ -1137,6 +1136,14 @@ static void colon(char *buf) | |||
1137 | status_line_bold("No more files to edit"); | 1136 | status_line_bold("No more files to edit"); |
1138 | goto ret; | 1137 | goto ret; |
1139 | } | 1138 | } |
1139 | if (*cmd == 'p') { | ||
1140 | // are there previous files to edit | ||
1141 | if (optind < 1) { | ||
1142 | status_line_bold("No previous files to edit"); | ||
1143 | goto ret; | ||
1144 | } | ||
1145 | optind -= 2; | ||
1146 | } | ||
1140 | editing = 0; | 1147 | editing = 0; |
1141 | } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] | 1148 | } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] |
1142 | fn = args; | 1149 | fn = args; |
@@ -1172,10 +1179,10 @@ static void colon(char *buf) | |||
1172 | } | 1179 | } |
1173 | } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args | 1180 | } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args |
1174 | if (file_modified && !useforce) { | 1181 | if (file_modified && !useforce) { |
1175 | status_line_bold("No write since last change (:rewind! overrides)"); | 1182 | status_line_bold("No write since last change (:%s! overrides)", cmd); |
1176 | } else { | 1183 | } else { |
1177 | // reset the filenames to edit | 1184 | // reset the filenames to edit |
1178 | optind = fn_start - 1; | 1185 | optind = -1; /* start from 0th file */ |
1179 | editing = 0; | 1186 | editing = 0; |
1180 | } | 1187 | } |
1181 | #if ENABLE_FEATURE_VI_SET | 1188 | #if ENABLE_FEATURE_VI_SET |
@@ -1225,51 +1232,53 @@ static void colon(char *buf) | |||
1225 | #endif /* FEATURE_VI_SET */ | 1232 | #endif /* FEATURE_VI_SET */ |
1226 | #if ENABLE_FEATURE_VI_SEARCH | 1233 | #if ENABLE_FEATURE_VI_SEARCH |
1227 | } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern | 1234 | } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern |
1228 | char *ls, *F, *R; | 1235 | char *F, *R, *flags; |
1229 | int gflag; | 1236 | size_t len_F, len_R; |
1237 | int gflag; // global replace flag | ||
1230 | 1238 | ||
1231 | // F points to the "find" pattern | 1239 | // F points to the "find" pattern |
1232 | // R points to the "replace" pattern | 1240 | // R points to the "replace" pattern |
1233 | // replace the cmd line delimiters "/" with NULLs | 1241 | // replace the cmd line delimiters "/" with NULs |
1234 | gflag = 0; // global replace flag | ||
1235 | c = orig_buf[1]; // what is the delimiter | 1242 | c = orig_buf[1]; // what is the delimiter |
1236 | F = orig_buf + 2; // start of "find" | 1243 | F = orig_buf + 2; // start of "find" |
1237 | R = strchr(F, c); // middle delimiter | 1244 | R = strchr(F, c); // middle delimiter |
1238 | if (!R) | 1245 | if (!R) |
1239 | goto colon_s_fail; | 1246 | goto colon_s_fail; |
1247 | len_F = R - F; | ||
1240 | *R++ = '\0'; // terminate "find" | 1248 | *R++ = '\0'; // terminate "find" |
1241 | buf1 = strchr(R, c); | 1249 | flags = strchr(R, c); |
1242 | if (!buf1) | 1250 | if (!flags) |
1243 | goto colon_s_fail; | 1251 | goto colon_s_fail; |
1244 | *buf1++ = '\0'; // terminate "replace" | 1252 | len_R = flags - R; |
1245 | if (*buf1 == 'g') { // :s/foo/bar/g | 1253 | *flags++ = '\0'; // terminate "replace" |
1246 | buf1++; | 1254 | gflag = *flags; |
1247 | gflag++; // turn on gflag | 1255 | |
1248 | } | ||
1249 | q = begin_line(q); | 1256 | q = begin_line(q); |
1250 | if (b < 0) { // maybe :s/foo/bar/ | 1257 | if (b < 0) { // maybe :s/foo/bar/ |
1251 | q = begin_line(dot); // start with cur line | 1258 | q = begin_line(dot); // start with cur line |
1252 | b = count_lines(text, q); // cur line number | 1259 | b = count_lines(text, q); // cur line number |
1253 | } | 1260 | } |
1254 | if (e < 0) | 1261 | if (e < 0) |
1255 | e = b; // maybe :.s/foo/bar/ | 1262 | e = b; // maybe :.s/foo/bar/ |
1263 | |||
1256 | for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 | 1264 | for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 |
1257 | ls = q; // orig line start | 1265 | char *ls = q; // orig line start |
1266 | char *found; | ||
1258 | vc4: | 1267 | vc4: |
1259 | buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" | 1268 | found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" |
1260 | if (buf1) { | 1269 | if (found) { |
1261 | uintptr_t bias; | 1270 | uintptr_t bias; |
1262 | // we found the "find" pattern - delete it | 1271 | // we found the "find" pattern - delete it |
1263 | text_hole_delete(buf1, buf1 + strlen(F) - 1); | 1272 | text_hole_delete(found, found + len_F - 1); |
1264 | // inset the "replace" patern | 1273 | // inset the "replace" patern |
1265 | bias = string_insert(buf1, R); // insert the string | 1274 | bias = string_insert(found, R); // insert the string |
1266 | buf1 += bias; | 1275 | found += bias; |
1267 | ls += bias; | 1276 | ls += bias; |
1268 | /*q += bias; - recalculated anyway */ | 1277 | /*q += bias; - recalculated anyway */ |
1269 | // check for "global" :s/foo/bar/g | 1278 | // check for "global" :s/foo/bar/g |
1270 | if (gflag == 1) { | 1279 | if (gflag == 'g') { |
1271 | if ((buf1 + strlen(R)) < end_line(ls)) { | 1280 | if ((found + len_R) < end_line(ls)) { |
1272 | q = buf1 + strlen(R); | 1281 | q = found + len_R; |
1273 | goto vc4; // don't let q move past cur line | 1282 | goto vc4; // don't let q move past cur line |
1274 | } | 1283 | } |
1275 | } | 1284 | } |
@@ -2073,6 +2082,14 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte | |||
2073 | dot += bias; | 2082 | dot += bias; |
2074 | end += bias; | 2083 | end += bias; |
2075 | p += bias; | 2084 | p += bias; |
2085 | #if ENABLE_FEATURE_VI_YANKMARK | ||
2086 | { | ||
2087 | int i; | ||
2088 | for (i = 0; i < ARRAY_SIZE(mark); i++) | ||
2089 | if (mark[i]) | ||
2090 | mark[i] += bias; | ||
2091 | } | ||
2092 | #endif | ||
2076 | text = new_text; | 2093 | text = new_text; |
2077 | } | 2094 | } |
2078 | memmove(p + size, p, end - size - p); | 2095 | memmove(p + size, p, end - size - p); |
@@ -2304,7 +2321,7 @@ static void rawmode(void) | |||
2304 | { | 2321 | { |
2305 | tcgetattr(0, &term_orig); | 2322 | tcgetattr(0, &term_orig); |
2306 | term_vi = term_orig; | 2323 | term_vi = term_orig; |
2307 | term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's | 2324 | term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's |
2308 | term_vi.c_iflag &= (~IXON & ~ICRNL); | 2325 | term_vi.c_iflag &= (~IXON & ~ICRNL); |
2309 | term_vi.c_oflag &= (~ONLCR); | 2326 | term_vi.c_oflag &= (~ONLCR); |
2310 | term_vi.c_cc[VMIN] = 1; | 2327 | term_vi.c_cc[VMIN] = 1; |
@@ -3314,7 +3331,7 @@ static void do_cmd(int c) | |||
3314 | end_cmd_q(); // stop adding to q | 3331 | end_cmd_q(); // stop adding to q |
3315 | break; | 3332 | break; |
3316 | case 'U': // U- Undo; replace current line with original version | 3333 | case 'U': // U- Undo; replace current line with original version |
3317 | if (reg[Ureg] != 0) { | 3334 | if (reg[Ureg] != NULL) { |
3318 | p = begin_line(dot); | 3335 | p = begin_line(dot); |
3319 | q = end_line(dot); | 3336 | q = end_line(dot); |
3320 | p = text_hole_delete(p, q); // delete cur line | 3337 | p = text_hole_delete(p, q); // delete cur line |
@@ -3328,7 +3345,7 @@ static void do_cmd(int c) | |||
3328 | case KEYCODE_END: // Cursor Key End | 3345 | case KEYCODE_END: // Cursor Key End |
3329 | for (;;) { | 3346 | for (;;) { |
3330 | dot = end_line(dot); | 3347 | dot = end_line(dot); |
3331 | if (--cmdcnt > 0) | 3348 | if (--cmdcnt <= 0) |
3332 | break; | 3349 | break; |
3333 | dot_next(); | 3350 | dot_next(); |
3334 | } | 3351 | } |
@@ -3506,7 +3523,7 @@ static void do_cmd(int c) | |||
3506 | || strncmp(p, "q!", cnt) == 0 // delete lines | 3523 | || strncmp(p, "q!", cnt) == 0 // delete lines |
3507 | ) { | 3524 | ) { |
3508 | if (file_modified && p[1] != '!') { | 3525 | if (file_modified && p[1] != '!') { |
3509 | status_line_bold("No write since last change (:quit! overrides)"); | 3526 | status_line_bold("No write since last change (:%s! overrides)", p); |
3510 | } else { | 3527 | } else { |
3511 | editing = 0; | 3528 | editing = 0; |
3512 | } | 3529 | } |