1 /*******************************************************************************
2 * Copyright (c) 2013-2021, Andrés Martinelli <andmarti@gmail.com> *
3 * All rights reserved. *
4 * *
5 * This file is a part of SC-IM *
6 * *
7 * SC-IM is a spreadsheet program that is based on SC. The original authors *
8 * of SC are James Gosling and Mark Weiser, and mods were later added by *
9 * Chuck Martin. *
10 * *
11 * Redistribution and use in source and binary forms, with or without *
12 * modification, are permitted provided that the following conditions are met: *
13 * 1. Redistributions of source code must retain the above copyright *
14 * notice, this list of conditions and the following disclaimer. *
15 * 2. Redistributions in binary form must reproduce the above copyright *
16 * notice, this list of conditions and the following disclaimer in the *
17 * documentation and/or other materials provided with the distribution. *
18 * 3. All advertising materials mentioning features or use of this software *
19 * must display the following acknowledgement: *
20 * This product includes software developed by Andrés Martinelli *
21 * <andmarti@gmail.com>. *
22 * 4. Neither the name of the Andrés Martinelli nor the *
23 * names of other contributors may be used to endorse or promote products *
24 * derived from this software without specific prior written permission. *
25 * *
26 * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY *
27 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
29 * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY *
30 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;*
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
36 *******************************************************************************/
37
38 /**
39 * \file cmds_command.c
40 * \author Andrés Martinelli <andmarti@gmail.com>
41 * \date 2017-07-18
42 * \brief TODO Write a tbrief file description.
43 */
44
45 #include <string.h>
46 #include <wchar.h>
47 #include <stdlib.h>
48 #include <ctype.h> // for isprint()
49
50 #ifndef NO_WORDEXP
51 #include <wordexp.h>
52 #endif
53
54 #include "sc.h" // for rescol
55 #include "conf.h"
56 #include "cmds_command.h"
57 #include "cmds_edit.h"
58 #include "cmds.h"
59 #include "utils/string.h"
60 #include "utils/dictionary.h"
61 #include "tui.h"
62 #include "file.h"
63 #include "main.h"
64 #include "interp.h"
65 #include "hide_show.h"
66 #include "exec.h"
67 #include "help.h"
68 #include "marks.h"
69 #include "filter.h"
70 #include "maps.h"
71 #include "xls.h"
72 #include "xlsx.h"
73 #include "cmds_visual.h"
74 #include "plot.h"
75
76 #ifdef UNDO
77 #include "undo.h"
78 #endif
79
80 extern char * rev;
81 extern struct dictionary * user_conf_d;
82
83 wchar_t inputline[BUFFERSIZE];
84 extern wchar_t interp_line[BUFFERSIZE];
85 int inputline_pos; /**< Position in window. Some chars has 2 chars width */
86 // see https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms
87 int real_inputline_pos; /**< Real position in inputline */
88
89 static wchar_t * valid_commands[] = {
90 L"!",
91 L"addfilter",
92 L"autojus",
93 L"ccopy",
94 L"cellcolor",
95 L"cmap",
96 L"cnoremap",
97 L"color",
98 L"cpaste",
99 L"cunmap",
100 L"datefmt",
101 L"define_color",
102 L"delfilter",
103 L"delfilters",
104 L"e csv",
105 L"e! csv",
106 L"e mkd",
107 L"e! mkd",
108 L"e tab",
109 L"e! tab",
110 L"e tex",
111 L"e! tex",
112 L"e txt",
113 L"e! txt",
114 L"e xlsx",
115 L"e! xlsx",
116 L"fcopy",
117 L"file",
118 L"fill",
119 L"filteroff",
120 L"filteron",
121 L"format",
122 L"formatcol",
123 L"formatrow",
124 L"freezecol",
125 L"freezerow",
126 L"fsum",
127 L"h",
128 L"help",
129 L"hiddencols",
130 L"hiddenrows",
131 L"hidecol",
132 L"hiderow",
133 L"imap",
134 L"inoremap",
135 L"int",
136 L"iunmap",
137 L"load!",
138 L"load",
139 L"lock",
140 L"nmap",
141 L"nnoremap",
142 L"nunmap",
143 L"pad",
144 L"plot",
145 L"plotedit",
146 L"q!",
147 L"q",
148 L"quit!",
149 L"quit",
150 L"redefine_color",
151 L"refresh",
152 L"set",
153 L"showcol",
154 L"showcols",
155 L"showfilters",
156 L"showmaps",
157 L"showrow",
158 L"showrows",
159 L"sort",
160 L"strtonum",
161 L"subtotal",
162 L"trigger",
163 L"unformat",
164 L"unfreezecol",
165 L"unfreezerow",
166 L"unlock",
167 L"untrigger",
168 L"valueize",
169 L"version",
170 L"vmap",
171 L"vnoremap",
172 L"vunmap",
173 L"w",
174 L"wq",
175 L"x",
176 (wchar_t *) 0
177 };
178
179 /**
180 * \brief TODO Document do_commandmode()
181 *
182 * \param[in] sb
183 *
184 * \return none
185 */
186
do_commandmode(struct block * sb)187 void do_commandmode(struct block * sb) {
188
189 // If a visual selected range exists
190 int p = is_range_selected();
191 struct srange * sr = NULL;
192 if (p != -1) sr = get_range_by_pos(p);
193
194
195 /*
196 * Normal KEY handlers for this MODE
197 */
198 if (sb->value == OKEY_BS || sb->value == OKEY_BS2) { // BS
199 if ( ! wcslen(inputline) || ! real_inputline_pos ) return;
200 int l = wcwidth(inputline[real_inputline_pos - 1]);
201 real_inputline_pos--;
202 del_wchar(inputline, real_inputline_pos);
203 inputline_pos -= l;
204 ui_show_header();
205
206 #ifdef HISTORY_FILE
207 if (commandline_history->pos == 0)
208 del_wchar(get_line_from_history(commandline_history, commandline_history->pos), real_inputline_pos); // Clean history
209 #endif
210 ui_show_header();
211 return;
212
213 } else if (sb->value == OKEY_LEFT) { // LEFT
214 if (inputline_pos) {
215 real_inputline_pos--;
216 int l = wcwidth(inputline[real_inputline_pos]);
217 inputline_pos -= l;
218 }
219 ui_show_header();
220 return;
221
222 } else if (sb->value == OKEY_RIGHT) { // RIGHT
223 int max = wcswidth(inputline, wcslen(inputline));
224 if (inputline_pos < max) {
225 int l = wcwidth(inputline[real_inputline_pos++]);
226 inputline_pos += l;
227 }
228 ui_show_header();
229 return;
230
231 } else if (sb->value == OKEY_DEL) { // DEL
232 if (inputline_pos > wcswidth(inputline, wcslen(inputline))) return;
233 del_wchar(inputline, real_inputline_pos);
234
235 #ifdef HISTORY_FILE
236 if (commandline_history->pos == 0)
237 del_wchar(get_line_from_history(commandline_history, commandline_history->pos), real_inputline_pos); // Clean history
238 #endif
239 ui_show_header();
240 return;
241
242 #ifdef HISTORY_FILE
243 } else if (sb->value == OKEY_UP || sb->value == ctl('p') || // UP
244 sb->value == OKEY_DOWN || sb->value == ctl('n')) { // DOWN
245
246 int delta = 0, k = 0, i, cmp;
247 if (sb->value == OKEY_UP || sb->value == ctl('p')) { // up
248 for (i=commandline_history->pos; -i+1 < commandline_history->len; i--, k--)
249 if (wcslen(get_line_from_history(commandline_history, 0))) {
250 if (! (cmp = wcsncmp(inputline, get_line_from_history(commandline_history, i-1), wcslen(get_line_from_history(commandline_history, 0))))) {
251 k--;
252 break;
253 } else if (commandline_history->len == 2-i && cmp) {
254 k=0;
255 break;
256 }
257 } else if (!wcslen(get_line_from_history(commandline_history, 0))) {
258 k--;
259 break;
260 }
261 } else if (sb->value == OKEY_DOWN || sb->value == ctl('n')) { // down
262 for (i=commandline_history->pos; i != 0; i++, k++)
263 if (wcslen(get_line_from_history(commandline_history, 0))) {
264 if (! (cmp = wcsncmp(inputline, get_line_from_history(commandline_history, i+1), wcslen(get_line_from_history(commandline_history, 0))))) {
265 k++;
266 break;
267 } else if (commandline_history->pos == 0 && cmp) {
268 k=0;
269 break;
270 }
271 } else if (!wcslen(get_line_from_history(commandline_history, 0))) {
272 k++;
273 break;
274 }
275 }
276 delta += k;
277 commandline_history->pos += delta;
278 wcscpy(inputline, get_line_from_history(commandline_history, commandline_history->pos));
279 inputline_pos = wcswidth(inputline, real_inputline_pos);
280 ui_show_header();
281 return;
282 #endif
283
284 } else if (sb->value == ctl('v') ) { // VISUAL SUBMODE
285 visual_submode = ':';
286 chg_mode('v');
287 start_visualmode(currow, curcol, currow, curcol);
288 return;
289
290 } else if (sb->value == ctl('r') && get_bufsize(sb) == 2 && // C-r // FIXME ???
291 (sb->pnext->value - (L'a' - 1) < 1 || sb->pnext->value > 26)) {
292 wchar_t cline [BUFFERSIZE];
293 int i, r = get_mark(sb->pnext->value)->row;
294 if (r != -1) {
295 swprintf(cline, BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->col), r);
296 } else {
297 swprintf(cline, BUFFERSIZE, L"%s%d:", coltoa(get_mark(sb->pnext->value)->rng->tlcol), get_mark(sb->pnext->value)->rng->tlrow);
298 swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s%d", coltoa(get_mark(sb->pnext->value)->rng->brcol), get_mark(sb->pnext->value)->rng->brrow);
299 }
300 for(i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]);
301
302 #ifdef HISTORY_FILE
303 if (commandline_history->pos == 0) { // Only if editing the new command
304 wchar_t * sl = get_line_from_history(commandline_history, 0);
305 wcscat(sl, cline); // Insert into history
306 }
307 #endif
308 ui_show_header();
309 return;
310
311 } else if (sb->value == ctl('f')) { // C-f
312 wchar_t cline [BUFFERSIZE];
313 int i;
314 struct ent * p1 = *ATBL(tbl, currow, curcol);
315 if (! p1 || ! p1->format) {
316 sc_error("cell has no format");
317 return;
318 }
319 swprintf(cline, BUFFERSIZE, L"%s", p1->format);
320 for (i = 0; i < wcslen(cline); i++) ins_in_line(cline[i]);
321
322 #ifdef HISTORY_FILE
323 if (commandline_history->pos == 0) { // Only if editing the new command
324 wchar_t * sl = get_line_from_history(commandline_history, 0);
325 wcscat(sl, cline); // Insert into history
326 }
327 #endif
328 ui_show_header();
329 return;
330
331 } else if ( sb->value == ctl('w') || sb->value == ctl('b') ||
332 sb->value == OKEY_HOME || sb->value == OKEY_END) {
333 switch (sb->value) {
334 case ctl('w'):
335 real_inputline_pos = for_word(1, 0, 1) + 1; // E
336 break;
337 case ctl('b'):
338 real_inputline_pos = back_word(1); // B
339 break;
340 case OKEY_HOME:
341 real_inputline_pos = 0; // 0
342 break;
343 case OKEY_END:
344 real_inputline_pos = wcslen(inputline); // $
345 break;
346 }
347 inputline_pos = wcswidth(inputline, real_inputline_pos);
348 ui_show_header();
349 return;
350
351 } else if (sb->value == '\t') { // TAB completion
352 int i, clen = (sizeof(valid_commands) / sizeof(char *)) - 1;
353
354 if (! get_comp()) copy_to_curcmd(inputline); // keep original cmd
355
356 for (i = 0; i < clen; i++) {
357 if ( ! wcscmp(inputline, valid_commands[i]) ) {
358 wcscpy(inputline, get_curcmd());
359 continue;
360 }
361 if ( ! wcsncmp(inputline, valid_commands[i], wcslen(inputline))
362 ) {
363 wcscpy(inputline, valid_commands[i]);
364 real_inputline_pos = wcslen(inputline);
365 inputline_pos = wcswidth(inputline, real_inputline_pos);
366 set_comp(1);
367 break;
368 }
369 }
370
371 // Restore inputline content
372 if (i == clen) {
373 wcscpy(inputline, get_curcmd());
374 real_inputline_pos = wcslen(inputline);
375 inputline_pos = wcswidth(inputline, real_inputline_pos);
376 set_comp(0);
377 }
378
379 ui_show_header();
380 return;
381
382 } else if (sc_isprint(sb->value)) { // Write new char
383 ins_in_line(sb->value);
384 ui_show_header();
385
386 #ifdef HISTORY_FILE
387 if (commandline_history->pos == 0) { // Only if editing the new command
388 wchar_t * sl = get_line_from_history(commandline_history, 0);
389 add_wchar(sl, sb->value, real_inputline_pos-1); // Insert into history
390 }
391 #endif
392 return;
393
394
395 /*
396 * CONFIRM A COMMAND PRESSING ENTER
397 */
398 } else if (find_val(sb, OKEY_ENTER)) {
399
400 if ( ! wcscmp(inputline, L"refresh")) {
401 sig_winchg();
402
403 } else if ( ! wcscmp(inputline, L"help") || ! wcscmp(inputline, L"h") ) {
404 help();
405
406 } else if ( ! wcscmp(inputline, L"q!") || ! wcscmp(inputline, L"quit!") ) {
407 shall_quit = 2;
408
409 } else if ( ! wcscmp(inputline, L"q") || ! wcscmp(inputline, L"quit") ) {
410 shall_quit = 1;
411
412 } else if ( ! wcsncmp(inputline, L"autojus", 7) ) {
413 wchar_t cline [BUFFERSIZE];
414 wcscpy(cline, inputline);
415 int c = curcol, cf = curcol;
416 if (p != -1) {
417 c = sr->tlcol;
418 cf = sr->brcol;
419 }
420 if ( p != -1 || ! wcscmp(inputline, L"autojus")) {
421 swprintf(cline, BUFFERSIZE, L"autojus %s:", coltoa(c));
422 swprintf(cline + wcslen(cline), BUFFERSIZE, L"%s", coltoa(cf));
423 }
424 send_to_interp(cline);
425
426 } else if ( ! wcsncmp(inputline, L"define_color", 12) ) {
427 send_to_interp(inputline);
428
429 } else if ( ! wcsncmp(inputline, L"redefine_color", 14) ) {
430 send_to_interp(inputline);
431
432 } else if ( ! wcsncmp(inputline, L"load", 4) ) {
433 char name [BUFFERSIZE];
434 int name_ok = 0;
435 int force_rewrite = 0;
436 #ifndef NO_WORDEXP
437 size_t len;
438 wordexp_t p;
439 #endif
440
441 wcstombs(name, inputline, BUFFERSIZE);
442 if ( ! wcsncmp(inputline, L"load! ", 6) ) {
443 force_rewrite = 1;
444 del_range_chars(name, 4, 4);
445 }
446
447 del_range_chars(name, 0, 4);
448 if ( ! strlen(name) ) {
449 sc_error("Path to file to load is missing !");
450 } else if ( modflg && ! force_rewrite ) {
451 sc_error("Changes were made since last save. Use '!' to force the load");
452 } else {
453 #ifdef NO_WORDEXP
454 name_ok = 1;
455 #else
456 wordexp(name, &p, 0);
457 if ( p.we_wordc < 1 ) {
458 sc_error("Failed expanding filepath");
459
460 } else if ( (len = strlen(p.we_wordv[0])) >= sizeof(name) ) {
461 sc_error("File path too long");
462 wordfree(&p);
463 } else {
464 memcpy(name, p.we_wordv[0], len+1);
465 name_ok = 1;
466 wordfree(&p);
467 }
468 #endif
469 }
470
471 if ( name_ok ) {
472 if ( ! file_exists(name)) {
473 sc_error("File %s does not exists!", name);
474 } else {
475 delete_structures();
476 create_structures();
477 readfile(name, 0);
478
479 if (! get_conf_int("nocurses")) {
480 ui_show_header();
481 }
482 }
483 }
484 } else if ( ! wcsncmp(inputline, L"hiderow ", 8) ||
485 ! wcsncmp(inputline, L"showrow ", 8) ||
486 ! wcsncmp(inputline, L"showcol ", 8) ||
487 ! wcsncmp(inputline, L"hidecol ", 8)
488 ) {
489 send_to_interp(inputline);
490
491 } else if ( ! wcsncmp(inputline, L"showrows", 8) ) {
492 if (p != -1) { // only continue if there is a selected range
493 int r, arg;
494 sr = get_range_by_pos(p);
495 r = sr->tlrow;
496 arg = sr->brrow - sr->tlrow + 1;
497 show_row(r, arg);
498 }
499
500 } else if ( ! wcsncmp(inputline, L"showcols", 8) ) {
501 if (p != -1) { // only continue if there is a selected range
502 int r, arg;
503 sr = get_range_by_pos(p);
504 r = sr->tlcol;
505 arg = sr->brcol - sr->tlcol + 1;
506 show_col(r, arg);
507 }
508
509 // range lock / unlock
510 } else if ( ! wcsncmp(inputline, L"lock", 4) || ! wcsncmp(inputline, L"unlock", 6) ||
511 ! wcsncmp(inputline, L"valueize", 8) ) {
512 int r = currow, c = curcol, rf = currow, cf = curcol;
513 if (p != -1) {
514 c = sr->tlcol;
515 r = sr->tlrow;
516 rf = sr->brrow;
517 cf = sr->brcol;
518 }
519 if ( ! wcsncmp(inputline, L"lock", 4) ) lock_cells(lookat(r, c), lookat(rf, cf));
520 else if ( ! wcsncmp(inputline, L"unlock", 6) ) unlock_cells(lookat(r, c), lookat(rf, cf));
521 else if ( ! wcsncmp(inputline, L"valueize", 8) ) valueize_area(r, c, rf, cf);
522
523 } else if ( ! wcsncmp(inputline, L"datefmt", 7)) {
524 wcscpy(interp_line, inputline);
525
526 int r = currow, c = curcol, rf = currow, cf = curcol;
527 if (p != -1) { // in case there is a range selected
528 c = sr->tlcol;
529 r = sr->tlrow;
530 rf = sr->brrow;
531 cf = sr->brcol;
532 }
533 wchar_t cline [BUFFERSIZE];
534 wcscpy(cline, interp_line);
535 int found = wstr_in_wstr(interp_line, L"\"");
536 if (found != -1) {
537 del_range_wchars(cline, 0, found-1);
538 swprintf(interp_line, BUFFERSIZE, L"datefmt %s%d:", coltoa(c), r);
539 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d %ls", coltoa(cf), rf, cline);
540 send_to_interp(interp_line);
541 }
542
543 } else if ( ! wcsncmp(inputline, L"sort ", 5) ) {
544 wcscpy(interp_line, inputline);
545 if (p != -1) { // in case there is a range selected
546 wchar_t cline [BUFFERSIZE];
547 wcscpy(cline, interp_line);
548 int found = wstr_in_wstr(interp_line, L"\"");
549 if (found != -1) {
550 del_range_wchars(cline, 0, found-1);
551 swprintf(interp_line, BUFFERSIZE, L"sort %s%d:", coltoa(sr->tlcol), sr->tlrow);
552 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d %ls", coltoa(sr->brcol), sr->brrow, cline);
553 }
554 }
555 sc_info("Sorting..");
556 send_to_interp(interp_line);
557 sc_info("Done.");
558
559 } else if ( ! wcsncmp(inputline, L"subtotal ", 9) ) {
560 int r = currow, c = curcol, rf = currow, cf = curcol, pos, cancel = 0;
561 if (p != -1) {
562 c = sr->tlcol;
563 r = sr->tlrow;
564 rf = sr->brrow;
565 cf = sr->brcol;
566 }
567 if (any_locked_cells(r, c, rf, cf)) {
568 sc_error("Locked cells encountered. Nothing changed");
569 } else {
570 wchar_t line [BUFFERSIZE];
571 wcscpy(line, inputline);
572 del_range_wchars(line, 0, 8);
573 if (
574 (pos = wstr_in_wstr(line, L"@sum")) != -1 ||
575 (pos = wstr_in_wstr(line, L"@avg")) != -1 ||
576 (pos = wstr_in_wstr(line, L"@max")) != -1 ||
577 (pos = wstr_in_wstr(line, L"@min")) != -1 ) {
578 add_wchar(line, L'\"', pos);
579 add_wchar(line, L'\"', pos+5);
580 } else if (
581 (pos = wstr_in_wstr(line, L"@prod")) != -1) {
582 add_wchar(line, L'\"', pos);
583 add_wchar(line, L'\"', pos+6);
584 } else if (
585 (pos = wstr_in_wstr(line, L"@count")) != -1) {
586 add_wchar(line, L'\"', pos);
587 add_wchar(line, L'\"', pos+7);
588 } else if (
589 (pos = wstr_in_wstr(line, L"@stddev")) != -1) {
590 add_wchar(line, L'\"', pos);
591 add_wchar(line, L'\"', pos+8);
592 } else {
593 sc_error("Please specify a function to apply the subtotals");
594 cancel = 1;
595 }
596 if (!cancel) {
597 swprintf(interp_line, BUFFERSIZE, L"subtotal %s%d:", coltoa(c), r);
598 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(cf), rf);
599 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line);
600 send_to_interp(interp_line);
601 unselect_ranges();
602 }
603 }
604
605 } else if ( ! wcsncmp(inputline, L"freezecol", 9) ) {
606 if (p != -1) {
607 swprintf(interp_line, BUFFERSIZE, L"freeze %s:", coltoa(sr->tlcol));
608 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(sr->brcol));
609 } else if (! wcscmp(inputline, L"freezecol")) {
610 swprintf(interp_line, BUFFERSIZE, L"freeze %s", coltoa(curcol));
611 } else
612 swprintf(interp_line, BUFFERSIZE, L"freeze %ls", &inputline[9]);
613 send_to_interp(interp_line);
614
615 } else if ( ! wcsncmp(inputline, L"freezerow", 9) ) {
616 if (p != -1) {
617 swprintf(interp_line, BUFFERSIZE, L"freeze %d:%d", sr->tlrow, sr->brrow);
618 } else if (! wcscmp(inputline, L"freezerow")) {
619 swprintf(interp_line, BUFFERSIZE, L"freeze %d", currow);
620 } else
621 swprintf(interp_line, BUFFERSIZE, L"freeze %ls", &inputline[9]);
622 send_to_interp(interp_line);
623
624 } else if ( ! wcsncmp(inputline, L"unfreezecol", 11) ) {
625 if (p != -1) {
626 swprintf(interp_line, BUFFERSIZE, L"unfreeze %s:", coltoa(sr->tlcol));
627 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(sr->brcol));
628 } else if (! wcscmp(inputline, L"unfreezecol")) {
629 swprintf(interp_line, BUFFERSIZE, L"unfreeze %s", coltoa(curcol));
630 } else
631 swprintf(interp_line, BUFFERSIZE, L"unfreeze %ls", &inputline[11]);
632 send_to_interp(interp_line);
633
634 } else if ( ! wcsncmp(inputline, L"unfreezerow", 11) ) {
635 if (p != -1) {
636 swprintf(interp_line, BUFFERSIZE, L"unfreeze %d:%d", sr->tlrow, sr->brrow);
637 } else if (! wcscmp(inputline, L"unfreezerow")) {
638 swprintf(interp_line, BUFFERSIZE, L"unfreeze %d", currow);
639 } else
640 swprintf(interp_line, BUFFERSIZE, L"unfreeze %ls", &inputline[11]);
641 send_to_interp(interp_line);
642
643 } else if ( ! wcsncmp(inputline, L"addfilter", 9) ) {
644 wchar_t cline [BUFFERSIZE];
645 char line [BUFFERSIZE];
646 wcscpy(cline, inputline);
647 int found;
648 if ((found = wstr_in_wstr(cline, L"\"")) != -1) {
649 del_range_wchars(cline, wcslen(cline), wcslen(cline));
650 del_range_wchars(cline, 0, found);
651 wcstombs(line, cline, BUFFERSIZE);
652 add_filter(line);
653 line[strlen(line)-1]='\0'; // remove last "
654 sc_info("Added filter: %s", line);
655 }
656
657 } else if ( ! wcsncmp(inputline, L"delfilter ", 10) ) {
658 wchar_t cline [BUFFERSIZE];
659 char line [BUFFERSIZE];
660 wcscpy(cline, inputline);
661 del_range_wchars(cline, 0, 9);
662 wcstombs(line, cline, BUFFERSIZE);
663 int id = atoi(line);
664 if (del_filter(id) == 0) sc_info("Removed filter: %d", id);
665
666 } else if ( ! wcsncmp(inputline, L"delfilters", 10) ) {
667 if (free_filters() == 0) sc_info("Removed filters");
668
669 } else if ( ! wcsncmp(inputline, L"filteron", 8) ) {
670 wcscpy(interp_line, inputline);
671 if ( ! wcscmp(inputline, L"filteron") && p == -1) { // If there is no selected range and no range in inputline passed
672 sc_error("Please specify a range or select one");
673 } else if (p != -1) {
674 wchar_t cline [BUFFERSIZE];
675 wcscpy(cline, interp_line);
676 swprintf(interp_line, BUFFERSIZE, L"filteron %s%d:", coltoa(sr->tlcol), sr->tlrow);
677 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(sr->brcol), sr->brrow);
678 send_to_interp(interp_line);
679 } else { // no range selected. range passed in inputline
680 send_to_interp(interp_line);
681 }
682
683 } else if ( ! wcsncmp(inputline, L"filteroff", 9) ) {
684 disable_filters();
685
686 } else if ( ! wcsncmp(inputline, L"hiddenrows", 10)) {
687 show_hiddenrows();
688
689 } else if ( ! wcsncmp(inputline, L"hiddencols", 10)) {
690 show_hiddencols();
691
692 } else if ( ! wcsncmp(inputline, L"showfilters", 11)) {
693 show_filters();
694
695 } else if ( ! wcsncmp(inputline, L"int ", 4) ) { // send cmd to interpreter
696 wcscpy(interp_line, inputline);
697 del_range_wchars(interp_line, 0, 3);
698 send_to_interp(interp_line);
699
700 } else if ( ! wcsncmp(inputline, L"fill ", 5) ) {
701 interp_line[0]=L'\0';
702 int r = currow, c = curcol, rf = currow, cf = curcol;
703 if (p != -1) {
704 c = sr->tlcol;
705 r = sr->tlrow;
706 rf = sr->brrow;
707 cf = sr->brcol;
708 swprintf(interp_line, BUFFERSIZE, L"fill %s%d:", coltoa(c), r);
709 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(cf), rf);
710 }
711
712 if (any_locked_cells(r, c, rf, cf)) {
713 swprintf(interp_line, BUFFERSIZE, L"");
714 sc_error("Locked cells encountered. Nothing changed");
715 } else {
716 if (p != -1)
717 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", &inputline[5]);
718 else
719 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", inputline);
720 send_to_interp(interp_line);
721 }
722
723 } else if ( ! wcsncmp(inputline, L"formatrow ", 10) ) {
724 int r = currow, rf = currow, i;
725 if (p != -1) {
726 r = sr->tlrow;
727 rf = sr->brrow;
728 }
729 #ifdef UNDO
730 int changed = 0, fmt_ori;
731 create_undo_action();
732 #endif
733 for (i=r; i<=rf;i++) {
734 #ifdef UNDO
735 fmt_ori = row_format[i];
736 add_undo_row_format(i, 'R', row_format[i]);
737 #endif
738 swprintf(interp_line, BUFFERSIZE, L"format %d %ls", i, &inputline[10]);
739 send_to_interp(interp_line);
740 #ifdef UNDO
741 if (fmt_ori != row_format[i]) changed = 1;
742 add_undo_row_format(i, 'A', row_format[i]);
743 #endif
744 }
745 #ifdef UNDO
746 if (! changed) dismiss_undo_item(NULL);
747 else end_undo_action();
748 #endif
749
750 } else if ( ! wcsncmp(inputline, L"formatcol ", 10) ) {
751 int c = curcol, cf = curcol, i;
752 if (p != -1) {
753 c = sr->tlcol;
754 cf = sr->brcol;
755 }
756 #ifdef UNDO
757 int changed = 0;
758 int fwidth_ori;
759 int precision_ori;
760 int realfmt_ori;
761 create_undo_action();
762 #endif
763 for (i=c; i<=cf;i++) {
764 #ifdef UNDO
765 fwidth_ori = fwidth[i];
766 precision_ori = precision[i];
767 realfmt_ori = realfmt[i];
768 add_undo_col_format(i, 'R', fwidth[i], precision[i], realfmt[i]);
769 #endif
770 swprintf(interp_line, BUFFERSIZE, L"format %s", coltoa(i));
771 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %ls", &inputline[10]);
772 send_to_interp(interp_line);
773 #ifdef UNDO
774 if (fwidth[i] != fwidth_ori || precision[i] != precision_ori || realfmt[i] != realfmt_ori) changed = 1;
775 add_undo_col_format(i, 'A', fwidth[i], precision[i], realfmt[i]);
776 #endif
777 }
778 #ifdef UNDO
779 if (! changed) dismiss_undo_item(NULL);
780 else end_undo_action();
781 #endif
782
783 } else if ( ! wcsncmp(inputline, L"format ", 7) ) {
784 int r = currow, c = curcol, rf = currow, cf = curcol;
785 if (p != -1) {
786 c = sr->tlcol;
787 r = sr->tlrow;
788 rf = sr->brrow;
789 cf = sr->brcol;
790 swprintf(interp_line, BUFFERSIZE, L"fmt %s%d:", coltoa(c), r);
791 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf);
792 } else
793 swprintf(interp_line, BUFFERSIZE, L"fmt %s%d", coltoa(c), r);
794
795 if (any_locked_cells(r, c, rf, cf)) {
796 sc_error("Locked cells encountered. Nothing changed");
797 } else {
798 int l = wcslen(interp_line);
799 swprintf(interp_line + l, BUFFERSIZE, L"%ls", inputline);
800 del_range_wchars(interp_line, l, l + 5);
801 #ifdef UNDO
802 create_undo_action();
803 copy_to_undostruct(r, c, rf, cf, UNDO_DEL, IGNORE_DEPS, NULL);
804 #endif
805 send_to_interp(interp_line);
806 #ifdef UNDO
807 copy_to_undostruct(r, c, rf, cf, UNDO_ADD, IGNORE_DEPS, NULL);
808 end_undo_action();
809 #endif
810 }
811
812 } else if ( ! wcsncmp(inputline, L"ccopy", 5) ) {
813 int r = currow, c = curcol, rf = currow, cf = curcol;
814 if (p != -1) {
815 c = sr->tlcol;
816 r = sr->tlrow;
817 rf = sr->brrow;
818 cf = sr->brcol;
819 }
820 swprintf(interp_line, BUFFERSIZE, L"ccopy %s%d:", coltoa(c), r);
821 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf);
822 send_to_interp(interp_line);
823
824 } else if ( ! wcsncmp(inputline, L"strtonum", 8) ) {
825 int r = currow, c = curcol, rf = currow, cf = curcol;
826 if (p != -1) {
827 c = sr->tlcol;
828 r = sr->tlrow;
829 rf = sr->brrow;
830 cf = sr->brcol;
831 }
832 swprintf(interp_line, BUFFERSIZE, L"strtonum %s%d:", coltoa(c), r);
833 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf);
834 send_to_interp(interp_line);
835
836 } else if ( ! wcsncmp(inputline, L"cpaste", 6) ) {
837 swprintf(interp_line, BUFFERSIZE, L"cpaste");
838 send_to_interp(interp_line);
839
840 } else if ( ! wcsncmp(inputline, L"cellcolor ", 10) ) {
841 #ifdef USECOLORS
842 interp_line[0]=L'\0';
843 wchar_t line [BUFFERSIZE];
844 wcscpy(line, inputline);
845 del_range_wchars(line, 0, 9);
846 swprintf(interp_line, BUFFERSIZE, L"cellcolor ");
847 if (p != -1) {
848 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow);
849 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow);
850 }
851 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line);
852 send_to_interp(interp_line);
853 #else
854 sc_error("Color support not compiled in");
855 chg_mode('.');
856 inputline[0] = L'\0';
857 #endif
858
859 } else if ( ! wcsncmp(inputline, L"unformat", 8) ) {
860 #ifdef USECOLORS
861 interp_line[0]=L'\0';
862 wchar_t line [BUFFERSIZE];
863 wcscpy(line, inputline);
864 del_range_wchars(line, 0, 7);
865 swprintf(interp_line, BUFFERSIZE, L"unformat");
866 if (p != -1) {
867 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow);
868 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow);
869 }
870 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line);
871 send_to_interp(interp_line);
872 #else
873 sc_error("Color support not compiled in");
874 chg_mode('.');
875 inputline[0] = L'\0';
876 #endif
877
878 } else if ( ! wcsncmp(inputline, L"color ", 6) ) {
879 #ifdef USECOLORS
880 char line [BUFFERSIZE];
881 wcstombs(line, inputline, BUFFERSIZE);
882 del_range_chars(line, 0, 5);
883 chg_color(line);
884 #else
885 sc_error("Color support not compiled in");
886 chg_mode('.');
887 inputline[0] = '\0';
888 #endif
889
890 } else if ( ! wcsncmp(inputline, L"trigger ", 8) ) {
891 interp_line[0]=L'\0';
892 wchar_t line [BUFFERSIZE];
893 wcscpy(line, inputline);
894 del_range_wchars(line, 0, 7);
895 swprintf(interp_line, BUFFERSIZE, L"trigger ");
896 if (p != -1) {
897 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s%d:", coltoa(sr->tlcol), sr->tlrow);
898 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d ", coltoa(sr->brcol), sr->brrow);
899 }
900 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%ls", line);
901 send_to_interp(interp_line);
902
903 } else if ( ! wcsncmp(inputline, L"untrigger ", 10) ) {
904 wcscpy(interp_line, inputline);
905 send_to_interp(interp_line);
906
907 } else if ( ! wcsncmp(inputline, L"set ", 4) ) {
908 wchar_t line [BUFFERSIZE];
909 wcscpy(line, inputline);
910 del_range_wchars(line, 0, 3);
911
912 wchar_t * l;
913 char oper[BUFFERSIZE];
914 if ((l = wcschr(line, L' ')) != NULL) l[0] = L'\0';
915 if ((l = wcschr(line, L'=')) != NULL) l[0] = L'\0';
916
917 wcscpy(interp_line, inputline);
918 send_to_interp(interp_line);
919
920 wcstombs(oper, line, BUFFERSIZE);
921 if (get_conf_value(oper)) {
922 sc_info("Config value changed: %s", oper);
923 } else if (strlen(oper) > 2 && ! wcsncmp(inputline, L"set no", 6)) {
924 sc_info("Config value changed: %s", &oper[2]);
925 }
926
927 } else if ( ! wcsncmp(inputline, L"pad ", 4) ) {
928 int c = curcol, cf = curcol;
929 if (p != -1) { // in case there is a range selected
930 c = sr->tlcol;
931 cf = sr->brcol;
932 }
933 wcscpy(interp_line, inputline); // pad 5
934 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L" %s:", coltoa(c)); // pad 5 A:
935 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s", coltoa(cf)); // B
936 send_to_interp(interp_line);
937
938 } else if ( ! wcsncmp(inputline, L"plot ", 5) ) {
939 int r = currow, c = curcol, rf = currow, cf = curcol;
940 if (p != -1) {
941 c = sr->tlcol;
942 r = sr->tlrow;
943 rf = sr->brrow;
944 cf = sr->brcol;
945 }
946 wchar_t aux[wcslen(inputline)+1];
947 wcscpy(aux, inputline);
948 del_range_wchars(aux, 0, 4);
949 swprintf(interp_line, BUFFERSIZE, L"plot \"%ls\" %s%d:", aux, coltoa(c), r);
950 swprintf(interp_line + wcslen(interp_line), BUFFERSIZE, L"%s%d", coltoa(cf), rf);
951 send_to_interp(interp_line);
952
953 } else if ( ! wcsncmp(inputline, L"plotedit ", 9) ) {
954 wchar_t aux[wcslen(inputline)+1];
955 wcscpy(aux, inputline);
956 del_range_wchars(aux, 0, 8);
957 plotedit(aux);
958
959 } else if ( ! wcscmp(inputline, L"set") ) {
960 char valores[get_dict_buffer_size(user_conf_d) + 1];
961 get_conf_values(valores);
962 ui_show_text(valores);
963
964 } else if ( ! wcscmp(inputline, L"version") ) {
965 ui_show_text(rev);
966
967 } else if ( ! wcscmp(inputline, L"showmaps") ) {
968 extern int len_maps;
969 char valores[MAXMAPITEM * len_maps];
970 get_mappings(valores);
971 ui_show_text(valores);
972
973 } else if ( ! wcsncmp(inputline, L"nmap", 4) ||
974 ! wcsncmp(inputline, L"imap", 4) ||
975 ! wcsncmp(inputline, L"vmap", 4) ||
976 ! wcsncmp(inputline, L"cmap", 4) ||
977 ! wcsncmp(inputline, L"inoremap", 8) ||
978 ! wcsncmp(inputline, L"nnoremap", 8) ||
979 ! wcsncmp(inputline, L"vnoremap", 8) ||
980 ! wcsncmp(inputline, L"cnoremap", 8) ||
981 ! wcsncmp(inputline, L"iunmap", 6) ||
982 ! wcsncmp(inputline, L"vunmap", 6) ||
983 ! wcsncmp(inputline, L"cunmap", 6) ||
984 ! wcsncmp(inputline, L"nunmap", 6) ) {
985 send_to_interp(inputline);
986
987 } else if ( ! wcsncmp(inputline, L"!", 1) ) {
988 char line [BUFFERSIZE];
989 wcstombs(line, inputline, BUFFERSIZE);
990 int found = str_in_str(line, " ");
991 if (found == -1) found++;
992 del_range_chars(line, 0, found);
993 exec_cmd(line);
994
995 } else if ( ! wcscmp(inputline, L"wq") ) {
996 wcscpy(inputline, L"x");
997 if (savefile() == 0) shall_quit = 1;
998
999 } else if ( inputline[0] == L'w' ) {
1000 savefile();
1001
1002 } else if ( ! wcsncmp(inputline, L"file ", 5) ) {
1003
1004 char name [BUFFERSIZE];
1005 int name_ok = 0;
1006 #ifndef NO_WORDEXP
1007 size_t len;
1008 wordexp_t p;
1009 #endif
1010
1011 wcstombs(name, inputline, BUFFERSIZE);
1012 del_range_chars(name, 0, 4);
1013
1014 #ifdef NO_WORDEXP
1015 name_ok = 1;
1016 #else
1017 wordexp(name, &p, 0);
1018 if ( p.we_wordc < 1 ) {
1019 sc_error("Failed to expand filename");
1020 } else if ( (len = strlen(p.we_wordv[0])) >= sizeof(name) ) {
1021 sc_error("File path too long");
1022 wordfree(&p);
1023 } else {
1024 memcpy(name, p.we_wordv[0], len+1);
1025 name_ok = 1;
1026 wordfree(&p);
1027 }
1028 #endif
1029
1030 if (name_ok) {
1031 #ifdef AUTOBACKUP
1032 // check if backup of curfile exists.
1033 // if it exists, remove it.
1034 if (strlen(curfile) && backup_exists(curfile)) remove_backup(curfile);
1035 #endif
1036 strncpy(curfile, name, PATHLEN - 1);
1037 sc_info("File name set to \"%s\"", curfile);
1038 }
1039
1040 } else if ( ! wcscmp(inputline, L"file") ) {
1041
1042 if( ! *curfile ) {
1043 sc_info("Current file has no name");
1044 } else {
1045 sc_info("Current file: \"%s\"", curfile);
1046 }
1047
1048 } else if ( inputline[0] == L'x' ) {
1049 if (savefile() == 0) shall_quit = 1;
1050
1051 } else if ( ! wcscmp(inputline, L"fcopy") ) {
1052 fcopy("");
1053
1054 } else if ( ! wcsncmp(inputline, L"fcopy ", 6)) {
1055
1056 wchar_t line [BUFFERSIZE];
1057 wcscpy(line, inputline);
1058 del_range_wchars(line, 0, 5);
1059 char action[BUFFERSIZE];
1060 wcstombs(action, line, BUFFERSIZE);
1061 fcopy(action);
1062
1063 } else if ( ! wcscmp(inputline, L"fsum") ) {
1064 fsum();
1065
1066 } else if (
1067 ! wcsncmp(inputline, L"e csv" , 5) ||
1068 ! wcsncmp(inputline, L"e! csv" , 6) ||
1069 ! wcsncmp(inputline, L"e tex" , 5) ||
1070 ! wcsncmp(inputline, L"e! tex" , 6) ||
1071 ! wcsncmp(inputline, L"e tab" , 5) ||
1072 ! wcsncmp(inputline, L"e! tab" , 6) ||
1073 ! wcsncmp(inputline, L"e mkd" , 4) ||
1074 ! wcsncmp(inputline, L"e! mkd" , 5) ||
1075 ! wcsncmp(inputline, L"e txt" , 5) ||
1076 ! wcsncmp(inputline, L"e! txt" , 6) ) {
1077 do_export( p == -1 ? 0 : sr->tlrow, p == -1 ? 0 : sr->tlcol,
1078 p == -1 ? maxrow : sr->brrow, p == -1 ? maxcol : sr->brcol);
1079
1080 } else if (
1081 ! wcsncmp(inputline, L"e xlsx" , 6) ||
1082 ! wcsncmp(inputline, L"e! xlsx" , 7)) {
1083 #ifndef XLSX_EXPORT
1084 sc_error("XLSX export support not compiled in");
1085 #else
1086 char linea[BUFFERSIZE];
1087 char filename[PATHLEN] = "";
1088 int force_rewrite = 0;
1089 if (inputline[1] == L'!') force_rewrite = 1;
1090 wcstombs(linea, inputline, BUFFERSIZE); // Use new variable to keep command history untouched
1091 del_range_chars(linea, 0, 1 + force_rewrite); // Remove 'e' or 'e!' from inputline
1092
1093 // Get path and file name to write.
1094 // Use parameter if any.
1095 if (strlen(linea) > 5) { // ex. 'xlsx '
1096 del_range_chars(linea, 0, 4); // remove 'xlsx'
1097 strcpy(filename, linea);
1098 // Use curfile name and '.xlsx' extension
1099 // Remove current '.sc' extension if necessary
1100 } else if (curfile[0]) {
1101 strcpy(filename, curfile);
1102 char * ext = strrchr(filename, '.');
1103 if (ext != NULL) del_range_chars(filename, strlen(filename) - strlen(ext), strlen(filename)-1);
1104 sprintf(filename + strlen(filename), ".xlsx");
1105 } else {
1106 sc_error("No filename specified !");
1107 }
1108
1109 if (strlen(filename) > 0 && ! force_rewrite && file_exists(filename)) {
1110 sc_error("File %s already exists. Use \"!\" to force rewrite.", filename);
1111
1112 #ifdef AUTOBACKUP
1113 // check if backup of filename exists.
1114 // if it exists and '!' is set, remove it.
1115 // if it exists and curfile = fname, remove it.
1116 // else return.
1117 } else if (strlen(filename) && backup_exists(filename)
1118 && !force_rewrite && !(strlen(curfile) && !strcmp(curfile, filename))) {
1119 sc_error("Backup file of %s exists. Use \"!\" to force the write process.", filename);
1120 #endif
1121 } else if (strlen(filename)) {
1122 #ifdef AUTOBACKUP
1123 if (backup_exists(filename)) remove_backup(filename);
1124 #endif
1125 if (export_xlsx(
1126 filename, p == -1 ? 0 : sr->tlrow, p == -1 ? 0 : sr->tlcol,
1127 p == -1 ? maxrow : sr->brrow, p == -1 ? maxcol : sr->brcol) == 0)
1128 sc_info("File \"%s\" written", filename);
1129 }
1130 #endif
1131
1132 } else {
1133 sc_error("COMMAND NOT FOUND !");
1134 }
1135
1136 #ifdef HISTORY_FILE
1137 /*
1138 * if exists in history an item with same text to the command typed
1139 * (counting from the second position) it is moved to the beginning of list.
1140 * (first element in list means last command executed)
1141 */
1142 del_item_from_history(commandline_history, 0);
1143 int moved = move_item_from_history_by_str(commandline_history, inputline, -1);
1144 if (! moved) add(commandline_history, inputline);
1145 commandline_history->pos = 0;
1146 #endif
1147
1148 chg_mode('.');
1149 inputline[0]=L'\0';
1150 inputline_pos = 0; //ADDED 08/10/2018
1151 set_comp(0); // unmark tab completion
1152 ui_update(TRUE);
1153 }
1154 return;
1155 }
1156
1157 /**
1158 * \brief TODO Document ins_in_line()
1159 *
1160 * \param[in] d
1161 *
1162 * \return none
1163 */
1164
ins_in_line(wint_t d)1165 void ins_in_line(wint_t d) {
1166 add_wchar(inputline, (wchar_t) d, real_inputline_pos++);
1167 inputline_pos += wcwidth((wchar_t) d);
1168 return;
1169 }
1170