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 main.c
40  * \author Andrés Martinelli <andmarti@gmail.com>
41  * \date 2017-07-18
42  * \brief The main file of sc-im
43  *
44  * \details This is the main file for sc-im.
45  *
46  * \see Homepage: https://github.com/andmarti1424/sc-im
47  *
48  * \bug It has been detected that libxls can produce memory leaks. One example
49  * is when you try to read a non xls file (e.g. xlsx file).
50  *
51  * \bug Extended ascii characters are not showing correctly. Compile sc-im
52  * against -lncursesw and not -lncurses.
53  */
54 
55 #include <signal.h>
56 #include <unistd.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <time.h>
60 #include <fcntl.h>   // for F_GETFL O_NONBLOCK F_SETFL
61 #include <locale.h>
62 #include <wchar.h>
63 #include <sys/ioctl.h> // for ioctl
64 
65 #ifndef NO_WORDEXP
66 #include <wordexp.h>
67 #endif
68 
69 #include "main.h"
70 #include "shift.h"
71 #include "macros.h"
72 #include "tui.h"
73 #include "input.h"
74 #include "marks.h"
75 #include "maps.h"
76 #include "yank.h"
77 #include "file.h"
78 #include "utils/dictionary.h"
79 #include "utils/string.h"
80 #include "history.h"
81 #include "conf.h"
82 #include "buffer.h"
83 #include "cmds.h"
84 #include "vmtbl.h"   // for growtbl
85 #include "filter.h"
86 #include "dep_graph.h"
87 
88 #ifdef UNDO
89 #include "undo.h"
90 #endif
91 
92 #ifdef XLUA
93 #include "lua.h"
94 #endif
95 
96 int currow = 0; /**< Current row of the selected cell. */
97 int curcol = 0; /**< Current column of the selected cell. */
98 int lastrow = 0;
99 int lastcol = 0;
100 int maxrows;
101 int maxcols;
102 unsigned char * col_hidden;
103 unsigned char * col_frozen;
104 int * fwidth;
105 int * precision;
106 int * realfmt;
107 unsigned char * row_hidden;
108 unsigned char * row_frozen;
109 unsigned char * row_format;
110 char line[FBUFLEN];
111 int modflg; /**< Indicates a change was made since last save */
112 struct ent *** tbl;
113 int shall_quit = 0;
114 unsigned int curmode;
115 unsigned int lastmode;
116 int maxrow, maxcol;
117 char curfile[PATHLEN];
118 char loadingfile[PATHLEN] = { '\0' };
119 char * exepath;
120 
121 int changed;
122 int cellassign;
123 int arg = 1;
124 int brokenpipe = FALSE; /**< Set to true if SIGPIPE is received */
125 char * ascext;
126 char * tbl0ext;
127 char * tblext;
128 char * latexext;
129 char * slatexext;
130 char * texext;
131 char dpoint = '.'; /**< Default decimal point character */
132 char thsep = ','; /**< Default thousands separator character */
133 int linelim = -1;
134 int calc_order = BYROWS;
135 int optimize  = 0; /**< Causes numeric expressions to be optimizedv */
136 int tbl_style = 0; /**< Headers for T command output */
137 int rndtoeven = 0;
138 int rowsinrange = 1;
139 int colsinrange = DEFWIDTH;
140 double eval_result;
141 char * seval_result;
142 FILE * fdoutput;  /**< Output file descriptor (stdout or file) */
143 int rescol = RESCOL; /**< Columns reserved for row numbers */
144 
145 struct block * buffer;
146 struct block * lastcmd_buffer;
147 struct dictionary * user_conf_d; /**< User's configuration dictionary */
148 struct history * commandline_history;
149 struct history * insert_history;
150 char stderr_buffer[1024] = "";
151 struct timeval startup_tv, current_tv; /**< Runtime timer */
152 
153 #ifdef AUTOBACKUP
154 struct timeval lastbackup_tv; /**< Last backup timer */
155 #ifdef HAVE_PTHREAD
156 #include <pthread.h>
157 int pthread_exists = 0; /**< Return status of pthread_create */
158 pthread_t fthread;
159 #endif
160 #endif
161 
162 void read_stdin();
163 extern char * rev;
164 
165 /**
166  * \brief The main() function
167  *
168  * \details The main() function of sc-im. It is the first function called when
169  * the applicaiton is executed.
170  *
171  * \param[in] argc (argument count) is the number of strings pointed to by argv. This
172  * is passed to main() by the system.
173  *
174  * \param[in] argv (argument vector) is a is a one-dimensional array of strings.
175  * Each string is one of the arguments that was passed to the program. The
176  * first string is the executable's name. This is passed to main() by
177  * the system.
178  *
179  * \return 0 on success; 1 on some errors; -1 on error
180  */
181 
182 // TODO Document the possible errors. Why are some things -1 while others
183 // are 1? Look for instances of exit_app(<number>).
184 
main(int argc,char ** argv)185 int main (int argc, char ** argv) {
186     // Define how the file stream should be buffered. Error if unsuccessful.
187     if (setvbuf(stderr, stderr_buffer, _IOFBF, STDERRBUF) != 0) {
188         fprintf(stderr, "Error setting stderr buffer\n");
189         return -1;
190     }
191 
192     // set up signals so we can catch them
193     signals();
194 
195 #ifdef USELOCALE
196     // Set location dependent information. This is used by some libraries.
197     //setlocale(LC_ALL, "");
198     setlocale(LC_CTYPE, "");
199 #endif
200 
201     // start configuration dictionaries
202     user_conf_d = create_dictionary();
203     store_default_config_values(); // Stores default values in user_conf_d
204 
205     // Read the main() parameters and replace values in user_conf_d as necessary
206     read_argv(argc, argv);
207 
208     // check if help is in argv. if so, show usage and quit
209     if (get_conf_int("help"))
210         show_usage_and_quit();
211 
212     // check if version is in argv. if so, show version and quit
213     if (get_conf_int("version"))
214         show_version_and_quit();
215 
216     // create command line history structure
217     if (! get_conf_int("nocurses")) {
218 #ifdef HISTORY_FILE
219         commandline_history = (struct history *) create_history(':');
220         load_history(commandline_history, ':'); // load the command history file
221 #endif
222 #ifdef INS_HISTORY_FILE
223         insert_history = (struct history *) create_history('=');
224         load_history(insert_history, '='); // load the insert history file
225 #endif
226     }
227 
228     // create basic structures that will depend on the loaded file
229     create_structures();
230 
231     // setup the spreadsheet arrays (tbl)
232     if (! growtbl(GROWNEW, 0, 0)) return exit_app(1);
233 
234     // initiate NCURSES if that is what is wanted
235     if (! get_conf_int("nocurses")) {
236         ui_start_screen();
237 
238 #ifdef USECOLORS
239         if (get_d_colors_param() == NULL) {
240             start_default_ucolors();
241         /*
242          * in case we decide to change colors
243          * this creates a dictionary and stores in it
244          * the relationship between macros and the keys values
245          * that are defined in .sc files
246          */
247             set_colors_param_dict();
248         }
249 #endif
250     }
251 
252     /*
253      * If the 'output' parameter is defined, SC-IM saves its output to that file.
254      * To achieve that, we open the output file and keep it open until exit.
255      * otherwise, SC-IM will output to stdout.
256      */
257     if (get_conf_value("output") != NULL) {
258         fdoutput = fopen(get_conf_value("output"), "w+");
259         if (fdoutput == NULL) {
260             sc_error("Cannot open file: %s.", get_conf_value("output"));
261             return exit_app(-1);
262         }
263 
264         if (! get_conf_int("nocurses")) { // WE MUST STOP SCREEN!
265             ui_stop_screen();
266 
267             // if output is set, nocurses should always be 1 !
268             put(user_conf_d, "nocurses", "1");
269         }
270     }
271 
272 #ifdef XLUA
273     doLuainit();
274 #endif
275 
276     wchar_t stdin_buffer[BUFFERSIZE] = { L'\0' };
277 
278     // if there was no file passed to scim executable
279     // 1. erase db !
280     if (! loadingfile[0]) erasedb();
281 
282     // 2. loadrc
283     loadrc();
284 
285     // 3. read sc file passed as argv
286     load_sc();
287 
288     // 4. check input from stdin (pipeline)
289     // and send it to interp
290     read_stdin();
291 
292 
293     // change curmode to NORMAL_MODE
294     chg_mode('.');
295 
296     // initiate ui
297     FILE * f;
298     if ( ! get_conf_int("nocurses")) {
299         // we show welcome screen if no spreadsheet was passed to SC-IM
300         // and no input was sent throw pipeline
301         if ( ! curfile[0] && ! wcslen(stdin_buffer)) {
302             ui_do_welcome();
303             // show mode and cell's details in status bar
304             ui_print_mode();
305             ui_show_celldetails();
306         } else {
307             ui_show_header();
308             ui_update(TRUE);
309         }
310     } else {
311         f = fopen("/dev/tty", "rw");
312         if (f == NULL) sc_error("fatal error loading stdin");
313     }
314 
315     // handle input from keyboard
316     if (! get_conf_int("nocurses"))
317         buffer = (struct block *) create_buf(); // this should only take place if curses ui
318 
319     wchar_t nocurses_buffer[BUFFERSIZE];
320 
321     // runtime timer
322     gettimeofday(&startup_tv, NULL);
323 
324     #ifdef AUTOBACKUP
325     //gettimeofday(&lastbackup_tv, NULL);
326     lastbackup_tv = (struct timeval) {0};
327     #endif
328 
329     if (get_conf_value("export_csv")) {
330         export_delim(NULL, ',', 0, 0, maxrow, maxcol, 0);
331     }
332 
333     if (get_conf_value("export_tab")) {
334         export_delim(NULL, '\t', 0, 0, maxrow, maxcol, 0);
335     }
336 
337     if (get_conf_value("export_mkd")) {
338         export_markdown(NULL, 0, 0, maxrow, maxcol);
339     }
340 
341     if (get_conf_value("export") || get_conf_value("export_txt")) {
342         export_plain(NULL, 0, 0, maxrow, maxcol);
343     }
344 
345 
346     while ( ! shall_quit && ! get_conf_int("quit_afterload")) {
347         // save current time for runtime timer
348         gettimeofday(&current_tv, NULL);
349 
350         // autobackup if it is time to do so
351         handle_backup();
352 
353         // if we are in ncurses
354         if (! get_conf_int("nocurses")) {
355             handle_input(buffer);
356 
357         // if we are not in ncurses
358         } else if (fgetws(nocurses_buffer, BUFFERSIZE, f) != NULL) {
359             sc_debug("Interp will receive: %ls", nocurses_buffer);
360             send_to_interp(nocurses_buffer);
361         }
362 
363         /* shall_quit=1 means :q
364            shall_quit=2 means :q! */
365         if (shall_quit == 1 && modcheck()) shall_quit = 0;
366     }
367     if (get_conf_int("nocurses") && f != NULL) fclose(f);
368 
369     return shall_quit == -1 ? exit_app(-1) : exit_app(0);
370 }
371 
372 extern graphADT graph;
373 
374 /**
375  * \brief Creates the structures used by the program.
376  *
377  * \return none
378  */
379 
create_structures()380 void create_structures() {
381     // initiate mark array
382     create_mark_array();
383 
384     // create last command buffer
385     lastcmd_buffer = (struct block *) create_buf();
386 
387     // create yank list structure
388     init_yanklist();
389 
390     /* Assign NULL to colformats
391     int c;
392     for (c = 0; c < COLFORMATS; c++)
393         colformat[c] = NULL;
394     */
395 
396     // init calc chain graph
397     graph = GraphCreate();
398 }
399 
400 /**
401  * \brief TODO Document read_stdin()
402  *
403  * \return none
404  */
405 
read_stdin()406 void read_stdin() {
407     //sc_debug("reading stdin from pipeline");
408     fd_set readfds;
409     FD_ZERO(&readfds);
410     FD_SET(STDIN_FILENO, &readfds);
411     fd_set savefds = readfds;
412     struct timeval timeout;
413     timeout.tv_sec = 0;
414     timeout.tv_usec = 0;
415     FILE * f = stdin;
416     //FILE * f = fopen("/dev/tty", "rw");
417     wchar_t stdin_buffer[BUFFERSIZE] = { L'\0' };
418 
419     if (select(1, &readfds, NULL, NULL, &timeout)) {
420         //sc_debug("there is data");
421         while (f != NULL && fgetws(stdin_buffer, BUFFERSIZE, f) != NULL) {
422             sc_debug("Interp will receive: %ls", stdin_buffer);
423             send_to_interp(stdin_buffer);
424         }
425         fflush(f);
426     } else {
427         //sc_debug("there is NO data");
428     }
429     readfds = savefds;
430     if (f != NULL) fclose(f);
431 
432     if ( ! freopen("/dev/tty", "rw", stdin)) {
433         perror(NULL);
434         exit(-1);
435     }
436     //sc_debug("finish reading");
437 }
438 
439 /**
440  * \brief Delete basic structures that depend on the loaded files.
441  *
442  * \return none
443  */
delete_structures()444 void delete_structures() {
445 
446     // Free marks array
447     free_marks_array();
448 
449     // Free yanklist
450     free_yanklist();
451 
452     // Erase last_command buffer
453     erase_buf(lastcmd_buffer);
454 
455     // Free ranges
456     free_ranges();
457 
458     // Free filters
459     free_filters();
460 
461     // Free undo list - from start of list
462 #ifdef UNDO
463     clear_undo_list();
464 #endif
465 
466     // Free lua stuff
467 #ifdef XLUA
468     doLuaclose();
469 #endif
470 
471     // free deleted ents
472     flush_saved();
473 
474     // free calc chain graph
475     destroy_graph(graph);
476 
477     // Free ents of tbl
478     erasedb();
479 
480     // free custom_colors
481     free_custom_colors();
482 }
483 
484 /**
485  * \brief Cleans things up just before exiting the program.
486  *
487  * \param[in] status
488  * \param[out] status
489  *
490  * \return status is returned unchanged
491  */
492 
exit_app(int status)493 int exit_app(int status) {
494 
495     // free history
496     if (! get_conf_int("nocurses")) {
497 
498 #ifdef HISTORY_FILE
499         if (! save_history(commandline_history, "w")) sc_error("Could not save commandline history");
500         if (commandline_history != NULL) destroy_history(commandline_history);
501 #endif
502 
503 #ifdef INS_HISTORY_FILE
504         if (! save_history(insert_history, "a")) sc_error("Could not save input mode history");
505         if (insert_history != NULL) destroy_history(insert_history);
506 #endif
507     }
508 
509     // wait for autobackup thread to finish, just in case
510     #if defined(AUTOBACKUP) && defined(HAVE_PTHREAD)
511     if (pthread_exists) pthread_join (fthread, NULL);
512     #endif
513 
514     // remove backup file
515 #ifdef AUTOBACKUP
516     if (strlen(curfile) && backup_exists(curfile)) remove_backup(curfile);
517 #endif
518 
519     // erase structures
520     delete_structures();
521 
522     // Free mappings
523     del_maps();
524 
525     // Erase stdin
526     erase_buf(buffer);
527 
528     // stop CURSES screen
529     if (! get_conf_int("nocurses"))
530         ui_stop_screen();
531 
532     // close fdoutput
533     if (get_conf_value("output") != NULL && get_conf_value("output")[0] != '\0' && fdoutput != NULL) {
534         fclose(fdoutput);
535     }
536 
537     // delete user config dictionaries
538     destroy_dictionary(user_conf_d);
539 
540     return status;
541 }
542 
543 /**
544  * \brief Read command line parameters and store them in a dictionary
545  *
546  * \details Read parameters passed to SC-IM executable and
547  * store them in user_conf dictionary.
548  *
549  * \param[in] argc (argument count) is the number of strings pointed to by
550  * argv.
551  * \param[in] argv (argument vector) is a one-dimensional array of strings.
552  * Each string is one of the arguments that was passed to the program. The
553  * first string is the executable's name.
554  *
555  * \return none
556  */
557 
read_argv(int argc,char ** argv)558 void read_argv(int argc, char ** argv) {
559     int i;
560     for (i = 1; i < argc; i++) {
561         if ( ! strncmp(argv[i], "--", 2) ) {       // it was passed a parameter
562             parse_str(user_conf_d, argv[i] + 2, 0);
563         } else {                                   // it was passed a file
564             strncpy(loadingfile, argv[i], PATHLEN-1);
565         }
566     }
567     exepath = argv[0];
568     return;
569 }
570 
571 /**
572  * \brief Attempt to load a file
573  *
574  * \return none
575  */
576 
load_sc()577 void load_sc() {
578     char name[PATHLEN];
579     strcpy(name, ""); //force name to be empty
580     #ifdef NO_WORDEXP
581     size_t len;
582     #else
583     int c;
584     wordexp_t p;
585     #endif
586 
587     #ifdef NO_WORDEXP
588     if ((len = strlen(loadingfile)) >= sizeof(name)) {
589         sc_info("File path too long: '%s'", loadingfile);
590         return;
591     }
592     memcpy(name, loadingfile, len+1);
593     #else
594     wordexp(loadingfile, &p, 0);
595     for (c=0; c < p.we_wordc; c++) {
596         if (c) sprintf(name + strlen(name), " ");
597         sprintf(name + strlen(name), "%s", p.we_wordv[c]);
598     }
599     wordfree(&p);
600     #endif
601 
602     if (strlen(name) != 0) {
603         sc_readfile_result result = readfile(name, 0);
604         if (!get_conf_int("nocurses")) {
605             if (result == SC_READFILE_DOESNTEXIST) {
606                 // It's a new record!
607                 sc_info("New file: \"%s\"", name);
608             } else if (result == SC_READFILE_ERROR) {
609                 sc_info("\"%s\" is not a SC-IM compatible file", name);
610             }
611         }
612     }
613 }
614 
615 /**
616  * \brief Set the calculation order
617  *
618  * \return none
619  */
620 
setorder(int i)621 void setorder(int i) {
622     if ((i == BYROWS) || (i == BYCOLS)) calc_order = i;
623     return;
624 }
625 
626 /**
627  * \brief Set signals catched by sc-im
628  *
629  * \return none
630  */
631 
signals()632 void signals() {
633     void sig_int();
634     void sig_abrt();
635     void sig_term();
636     void nopipe();
637     void sig_winchg();
638     void sig_tstp();
639     void sig_cont();
640 
641     signal(SIGINT, sig_int);
642     signal(SIGABRT, sig_abrt);
643     signal(SIGTERM, sig_term); // kill
644     signal(SIGPIPE, nopipe);
645     //(void) signal(SIGALRM, time_out);
646     signal(SIGWINCH, sig_winchg);
647     //(void) signal(SIGBUS, doquit);
648     //(void) signal(SIGFPE, doquit);
649     signal(SIGTSTP, sig_tstp);
650     signal(SIGCONT, sig_cont);
651     return;
652 }
653 
654 /**
655  * \brief Handles the SIGPIPE signal
656  *
657  * \return none
658  */
659 
660 // TODO Possibly rename this function to sig_nopipe() for consistency
661 // with the other signal functions.
662 
nopipe()663 void nopipe() {
664     sc_error("brokenpipe!");
665     brokenpipe = TRUE;
666     return;
667 }
668 
669 /**
670  * \brief Handles the SIGTSTP signal
671  *
672  * \return none
673  */
674 
sig_tstp()675 void sig_tstp() {
676     //sc_info("Got SIGTSTP.");
677     def_prog_mode();
678     endwin();
679     signal(SIGTSTP, SIG_DFL);  /* set handler to default */
680     kill(getpid(), SIGTSTP);   /* call the default handler */
681 }
682 
683 
684 /**
685  * \brief Handles the SIGCONT signal
686  *
687  * \return none
688  */
689 
sig_cont()690 void sig_cont() {
691     signal(SIGTSTP, sig_tstp); /* set handler back to this */
692     sig_winchg();
693     reset_prog_mode();
694     refresh();
695     ui_update(TRUE);
696     //sc_info("Got SIGCONT.");
697 }
698 
699 /**
700  * \brief Handles the SIGINT signal
701  *
702  * \return none
703  */
704 
sig_int()705 void sig_int() {
706     if ( ! get_conf_int("debug"))
707         sc_error("Got SIGINT. Press «:q<Enter>» to quit SC-IM");
708     else
709         shall_quit = 2;
710     return;
711 }
712 
713 /**
714  * \brief Handles the SIGABRT signal
715  *
716  * \return none
717  */
718 
sig_abrt()719 void sig_abrt() {
720     sc_error("Error !!! Quitting SC-IM.");
721     shall_quit = -1; // error !
722     return;
723 }
724 
725 /**
726  * \brief Handles the SIGABRT signal
727  *
728  * \return none
729  */
730 
sig_term()731 void sig_term() {
732     sc_error("Got SIGTERM signal. Quitting SC-IM.");
733     shall_quit = 2;
734     return;
735 }
736 
737 /**
738  * \brief Send the version number to standard output and quit.
739  *
740  * \return none
741  */
742 
743 // TODO Split this into two commands. One prints the version number
744 // the other prints the version number along with the other information.
745 
show_version_and_quit()746 void show_version_and_quit() {
747     put(user_conf_d, "nocurses", "1");
748     sc_info("SC-IM - %s", rev);
749 #ifdef NCURSES
750     sc_info("-DNCURSES");
751 #endif
752 #ifdef MAXROWS
753     sc_info("-DMAXROWS %d", MAXROWS);
754 #endif
755 #ifdef UNDO
756     sc_info("-DUNDO");
757 #endif
758 #ifdef XLS
759     sc_info("-DXLS");
760 #endif
761 #ifdef XLSX
762     sc_info("-DXLSX");
763 #endif
764 #ifdef XLSX_EXPORT
765     sc_info("-DXLSX_EXPORT");
766 #endif
767 #ifdef XLUA
768     sc_info("-DXLUA");
769 #endif
770 #ifdef DEFAULT_COPY_TO_CLIPBOARD_CMD
771     sc_info("-DDEFAULT_COPY_TO_CLIPBOARD_CMD=\"%s\"", DEFAULT_COPY_TO_CLIPBOARD_CMD);
772 #endif
773 #ifdef DEFAULT_PASTE_FROM_CLIPBOARD_CMD
774     sc_info("-DDEFAULT_PASTE_FROM_CLIPBOARD_CMD=\"%s\"", DEFAULT_PASTE_FROM_CLIPBOARD_CMD);
775 #endif
776 #ifdef DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD
777     sc_info("-DDEFAULT_OPEN_FILE_UNDER_CURSOR_CMD=\"%s\"", DEFAULT_OPEN_FILE_UNDER_CURSOR_CMD);
778 #endif
779 #ifdef USELOCALE
780     sc_info("-DUSELOCALE");
781 #endif
782 #ifdef MOUSE
783     sc_info("-DMOUSE");
784 #endif
785 #ifdef USECOLORS
786     sc_info("-DUSECOLORS");
787 #endif
788 #ifdef _XOPEN_SOURCE_EXTENDED
789     sc_info("-D_XOPEN_SOURCE_EXTENDED");
790 #endif
791 #ifdef _GNU_SOURCE
792     sc_info("-D_GNU_SOURCE");
793 #endif
794 #ifdef SNAME
795     sc_info("-DSNAME=\"%s\"", SNAME);
796 #endif
797 #ifdef HELP_PATH
798     sc_info("-DHELP_PATH=\"%s\"", HELP_PATH);
799 #endif
800 #ifdef LIBDIR
801     sc_info("-DLIBDIR=\"%s\"", LIBDIR);
802 #endif
803 #ifdef DFLT_PAGER
804     sc_info("-DDFLT_PAGER=\"%s\"", DFLT_PAGER);
805 #endif
806 #ifdef DFLT_EDITOR
807     sc_info("-DDFLT_EDITOR=\"%s\"", DFLT_EDITOR);
808 #endif
809 #ifdef CONFIG_DIR
810     sc_info("-DCONFIG_DIR=\"%s\"", CONFIG_DIR);
811 #endif
812 #ifdef CONFIG_FILE
813     sc_info("-DCONFIG_FILE=\"%s\"", CONFIG_FILE);
814 #endif
815 #ifdef HISTORY_DIR
816     sc_info("-DHISTORY_DIR=\"%s\"", HISTORY_DIR);
817 #endif
818 #ifdef HISTORY_FILE
819     sc_info("-DHISTORY_FILE=\"%s\"", HISTORY_FILE);
820 #endif
821 #ifdef INS_HISTORY_FILE
822     sc_info("-DINS_HISTORY_FILE=\"%s\"", INS_HISTORY_FILE);
823 #endif
824 #ifdef HAVE_PTHREAD
825     sc_info("-DHAVE_PTHREAD");
826 #endif
827 #ifdef AUTOBACKUP
828     sc_info("-DAUTOBACKUP");
829 #endif
830     put(user_conf_d, "quit_afterload", "1");
831 }
832 
833 /**
834  * \brief Print usage message to stdout text and quit
835  *
836  * \return none
837  */
838 
839 // NOTE this is a quick and dirty command to search for arguments used in the sources (macOS 10.14)
840 // grep "get_conf_value(\"" -r ./src/*.c | grep get_conf_value |sed 's/"//g' |sed 's/.*get_conf_value(//g'|cut -d ')' -f1 |sort|uniq|sed 's/^/--/g'
show_usage_and_quit()841 void show_usage_and_quit(){
842   put(user_conf_d, "nocurses", "1");
843   printf("\
844 \nSC-IM - SC Improved\
845 \n\
846 \nUsage: sc-im [arguments] [file]          specified file\
847 \n   or: sc-im [arguments] -               read text from stdin\
848 \n\
849 \nArguments:\
850 \n\
851 \n  --autocalc                  Set variable 'autocalc'.\
852 \n  --copy_to_clipboard_delimited_tab  Set variable 'copy_to_clipboard_delimited_tab'\
853 \n  --debug                     Set variable 'debug'\
854 \n  --default_copy_to_clipboard_cmd=COMMAND  set variable 'default_copy_from_clipboard_cmd'\
855 \n  --default_paste_from_clipboard_cmd=COMMAND  set variable 'default_paste_from_clipboard_cmd'\
856 \n  --default_open_file_under_cursor_cmd=COMMAND  set variable 'default_open_file_under_cursor_cmd'\
857 \n  --export_csv                Export to csv without interaction\
858 \n  --export_tab                Export to tab without interaction\
859 \n  --export_txt                Export to txt without interaction\
860 \n  --export_mkd                Export to markdown without interaction\
861 \n  --external_functions        Set variable 'external_functions'\
862 \n  --half_page_scroll          Set variable 'half_page_scroll'\
863 \n  --ignorecase                Set variable 'ignorecase'\
864 \n  --import_delimited_as_text Import text as\
865 \n  --newline_action={j or l}   Set variable 'newline_action'\
866 \n  --nocurses                  Run interactive but without ncurses interface.\
867 \n  --numeric                   Set variable 'numeric'\
868 \n  --numeric_decimal           Set variable 'numeric_decimal'\
869 \n  --output=FILE               Save the results in FILE\
870 \n  --overlap                   Set variable 'overlap variable'\
871 \n  --quit_afterload            Quit after loading all the files\
872 \n  --show_cursor               Make the screen cursor follow the active cell\
873 \n  --tm_gmtoff={seconds}       set gmt offset used for converting datetimes to localtime.\
874 \n  --txtdelim={\",\" or \";\" or \"\\t\" or \"|\"}  Sets delimiter when opening a .tab of .csv file");
875 #ifdef XLSX
876   printf("\n\
877 \n  --sheet=SHEET               Open SHEET when loading xlsx file. Default is 1.\
878 \n  --xlsx_readformulas         Set variable 'xlsx_readformulas'");
879 #endif
880   printf("\n\
881 \n  --version                   Print version information and exit\
882 \n  --help                      Print Help (this message) and exit\n");
883     put(user_conf_d, "quit_afterload", "1");
884 }
885