"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/cli/main.c" between
wcalc-2.4.1.tar.gz and wcalc-2.5.tar.gz

About: Wcalc is a natural-expression command-line calculator.

main.c  (wcalc-2.4.1):main.c  (wcalc-2.5)
skipping to change at line 19 skipping to change at line 19
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <strings.h> /* for strncasecmp(), per POSIX 2001 */ #include <strings.h> /* for strncasecmp(), per POSIX 2001 */
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> /* for stat() */ #include <sys/stat.h> /* for stat() */
#include <ctype.h> /* for isdigit and isalpha */ #include <ctype.h> /* for isdigit and isalpha */
#include <errno.h> #include <errno.h>
#include <fcntl.h> /* for open() */ #include <fcntl.h> /* for open() */
#include <limits.h> /* for stroul() */ #include <limits.h> /* for stroul() */
#include <sys/mman.h> /* for mmap() */
#include <assert.h> /* for assert() */
#include <stdarg.h> /* for va_start() */
#include "number.h" #include "number.h"
#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
# if defined(HAVE_READLINE_READLINE_H) # if defined(HAVE_READLINE_READLINE_H)
# include <readline/readline.h> # include <readline/readline.h>
# elif defined(HAVE_READLINE_H) # elif defined(HAVE_READLINE_H)
# include <readline.h> # include <readline.h>
# else /* !defined(HAVE_READLINE_H) */ # else /* !defined(HAVE_READLINE_H) */
extern char *readline(); extern char *readline();
# endif /* !defined(HAVE_READLINE_H) */ # endif /* !defined(HAVE_READLINE_H) */
skipping to change at line 58 skipping to change at line 61
#endif /* HAVE_READLINE_HISTORY */ #endif /* HAVE_READLINE_HISTORY */
#include "calculator.h" #include "calculator.h"
#include "conversion.h" #include "conversion.h"
#ifdef HAVE_CONFIG_H /* auto-tool build */ #ifdef HAVE_CONFIG_H /* auto-tool build */
# include "parser.h" # include "parser.h"
#else #else
# include "y.tab.h" # include "y.tab.h"
#endif #endif
#include "variables.h" #include "variables.h"
#include "help.h"
#include "files.h" #include "files.h"
#include "historyManager.h" #include "historyManager.h"
#include "list.h" #include "list.h"
#include "iscmd.h"
#include "isconst.h" #include "isconst.h"
#include "isfunc.h"
#include "output.h"
#include "evalvar.h"
#define TRUEFALSE (!strcmp(value, "yes") || !strcmp(value, "true") || !strcmp(v alue, "1")) #define TRUEFALSE (!strcmp(value, "yes") || !strcmp(value, "true") || !strcmp(v alue, "1"))
#define BIG_STRING 4096 #define BIG_STRING 4096
#define VERSION PACKAGE_VERSION #define VERSION PACKAGE_VERSION
#define EXIT_EARLY(code) do { \
clearHistory(); \
cleanupvar(); \
num_free(last_answer); \
lists_cleanup(); \
fflush(NULL); \
exit(code); \
} while (0)
static int read_prefs(void); static int read_prefs(void);
static int read_preload(void); static int read_preload(void);
static void display_and_clear_errstring(void);
/* /*
* These are declared here because they're not in any header files. * These are declared here because they're not in any header files.
* yyparse() is declared with an empty argument list so that it is * yyparse() is declared with an empty argument list so that it is
* compatible with the generated C code from yacc/bison. * compatible with the generated C code from yacc/bison.
* This part is taken from http://www.bgw.org/tutorials/programming/c/lex_yacc/m ain.c * This part is taken from http://www.bgw.org/tutorials/programming/c/lex_yacc/m ain.c
*/ */
extern int yyparse(void); extern int yyparse(void);
extern int yy_scan_string(const char *); extern int yy_scan_string(const char *);
static int exit_on_err = 0;
#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
/*@null@*/ /*@null@*/
static List tc_options = NULL; static List tc_options = NULL;
/*@null@*/ /*@null@*/
static char *tc_generator(const char *text, static char *
int state) tc_generator(const char *text,
int state)
{ /*{{{ */ { /*{{{ */
char *ret = getHeadOfList(tc_options); char *ret = getHeadOfList(tc_options);
if (ret) { if (ret) {
return ret; return ret;
} else { } else {
return NULL; return NULL;
} }
} /*}}} */ } /*}}} */
/*@null@*/ /*@null@*/
static char *tc_rounding(const char *text, static char *
int state) tc_rounding(const char *text,
int state)
{ /*{{{ */ { /*{{{ */
static unsigned int i = 0; static unsigned int i = 0;
char *rounding[] = { "none", "simple", "sig_fig", 0 }; char *rounding[] = { "none", "simple", "sig_fig", 0 };
if (state == 0) { if (state == 0) {
i = 0; i = 0;
} }
while (rounding[i] != NULL) { while (rounding[i] != NULL) {
if (strncmp(text, rounding[i], strlen(text)) == 0) { if (strncmp(text, rounding[i], strlen(text)) == 0) {
return strdup(rounding[i++]); return strdup(rounding[i++]);
} }
i++; i++;
} }
return NULL; return NULL;
} /*}}} */ } /*}}} */
/*@null@*/ /*@null@*/
static char *tc_engineering(const char *text, static char *
int state) tc_engineering(const char *text,
int state)
{ /*{{{ */ { /*{{{ */
static unsigned int i = 0; static unsigned int i = 0;
char *engineering[] = { "always", "never", "auto", "automatic" , 0 }; char *engineering[] = { "always", "never", "auto", "automatic" , 0 };
if (state == 0) { if (state == 0) {
i = 0; i = 0;
} }
while (engineering[i] != NULL) { while (engineering[i] != NULL) {
if (strncmp(text, engineering[i], strlen(text)) == 0) { if (strncmp(text, engineering[i], strlen(text)) == 0) {
return strdup(engineering[i++]); return strdup(engineering[i++]);
} }
i++; i++;
} }
return NULL; return NULL;
} /*}}} */ } /*}}} */
char **qcommands = NULL;
# define COMPLETE(strs) do { \ # define COMPLETE(strs) do { \
int compareword = 0; \ int compareword = 0; \
int comparechar = 0; \ int comparechar = 0; \
int textcurs = 0; \ int textcurs = 0; \
while (strs[compareword] != NULL) { \ while (strs[compareword] != NULL) { \
if (text[textcurs] == 0) { /* add to the list of possibilities */ \ if (text[textcurs] == 0) { /* add to the list of possibilities */ \
addToList( &tc_options, strdup(strs[compareword])); \ addToList(&tc_options, strdup(strs[compareword])); \
textcurs = 0; \ textcurs = 0; \
comparechar = 0; \ comparechar = 0; \
compareword ++; \ compareword++; \
} else if (text[textcurs] == strs[compareword][comparechar]) { \ } else if (text[textcurs] == strs[compareword][comparechar]) { \
textcurs ++; \ textcurs++; \
comparechar ++; \ comparechar++; \
} else { /* not a possibility: next! */ \ } else { /* not a possibility: next! */ \
textcurs = 0; \ textcurs = 0; \
compareword ++; \ compareword++; \
comparechar = 0; \ comparechar = 0; \
} \ } \
} \ } \
} while (0) } while (0)
# define COMPLETE2(strs) do { # define COMPLETE2(strs) do { \
\ const unsigned textlen = strlen(text); \
int compareword = 0; for (unsigned _c_i = 0; strs[_c_i].explanation; _c_i++) { \
\ const char *const *const _c_names = strs[_c_i].names; \
int comparechar = 0; for (unsigned _c_j = 0; _c_names[_c_j]; _c_j++) { \
\ if (!strncmp(text, _c_names[_c_j], textlen)) { \
int textcurs = 0; /* add to the list of possibilities */ \
\ addToList(&tc_options, strdup(_c_names[_c_j])); \
while (strs[compareword].label != NULL) { } \
\ } \
if (text[textcurs] == 0) { /* add to the list of possibilities */ } \
\
addToList( &tc_options, strdup(strs[compareword].label));
\
textcurs = 0;
\
comparechar = 0;
\
compareword ++;
\
} else if (text[textcurs] == strs[compareword].label[comparechar]) {
\
textcurs ++;
\
comparechar ++;
\
} else { /* not a possibility: next! */
\
textcurs = 0;
\
compareword ++;
\
comparechar = 0;
\
}
\
}
\
} while (0) } while (0)
static char **wcalc_completion(const char *text, static void
int start, build_qcommands(void)
int end) {
unsigned c_count = 0;
for (unsigned c = 0; commands[c].explanation; c++) {
for (unsigned n = 0; commands[c].names[n]; n++) {
c_count++;
}
}
c_count++;
qcommands = malloc(sizeof(char *) * c_count);
c_count = 0;
for (unsigned c = 0; commands[c].explanation; c++) {
for (unsigned n = 0; commands[c].names[n]; n++) {
qcommands[c_count] = malloc(strlen(commands[c].names[n]) + 2);
sprintf(qcommands[c_count], "\\%s", commands[c].names[n]);
c_count++;
}
}
qcommands[c_count] = NULL;
}
static char **
wcalc_completion(const char *text,
int start,
int end)
{ /*{{{ */ { /*{{{ */
/*extern const char *commands[];*/ /*extern const char *commands[];*/
extern const char *qcommands[]; char **variables;
extern const char *funcs[]; char **retvals = NULL;
char **variables;
char **retvals = NULL;
// printf("\ncompleting: %s\n", text); // printf("\ncompleting: %s\n", text);
if ('\\' == rl_line_buffer[0]) { if ('\\' == rl_line_buffer[0]) {
if ((NULL == strchr(rl_line_buffer, ' ')) && if ((NULL == strchr(rl_line_buffer, ' ')) &&
(NULL == strchr(rl_line_buffer, '\t'))) { (NULL == strchr(rl_line_buffer, '\t'))) {
COMPLETE(qcommands); COMPLETE(qcommands);
} else if (strncmp("\\explain", rl_line_buffer, 8) == 0) { } else if (strncmp("\\explain", rl_line_buffer, 8) == 0) {
int i = 8; int i = 8;
while (isspace(rl_line_buffer[i])) ++i; while (isspace(rl_line_buffer[i])) ++i;
if (i == start) { if (i == start) {
COMPLETE(qcommands); COMPLETE(qcommands);
COMPLETE2(consts); COMPLETE2(consts);
COMPLETE(funcs); COMPLETE2(funcs);
variables = listvarnames(); variables = listvarnames();
COMPLETE(variables); COMPLETE(variables);
free(variables); free(variables);
} }
} else if ((strncmp("\\open", rl_line_buffer, 5) == 0) || } else if ((strncmp("\\open", rl_line_buffer, 5) == 0) ||
(strncmp("\\save", rl_line_buffer, 5) == 0)) { (strncmp("\\save", rl_line_buffer, 5) == 0)) {
int i = 5; int i = 5;
while (isspace(rl_line_buffer[i])) ++i; while (isspace(rl_line_buffer[i])) ++i;
if (i == start) { if (i == start) {
skipping to change at line 306 skipping to change at line 342
COMPLETE(conversions[unit_cat][unit].aka); COMPLETE(conversions[unit_cat][unit].aka);
} }
} }
} }
} }
} }
} }
} else { } else {
COMPLETE(qcommands); COMPLETE(qcommands);
COMPLETE2(consts); COMPLETE2(consts);
COMPLETE(funcs); COMPLETE2(funcs);
variables = listvarnames(); variables = listvarnames();
COMPLETE(variables); COMPLETE(variables);
free(variables); free(variables);
} }
rl_attempted_completion_over = 1; // do not use standard file completion rl_attempted_completion_over = 1; // do not use standard file completion
rl_completion_entry_function = tc_generator; rl_completion_entry_function = tc_generator;
retvals = rl_completion_matches(text, tc_generator); retvals = rl_completion_matches(text, tc_generator);
return retvals; return retvals;
} /*}}} */ } /*}}} */
#endif /* ifdef HAVE_LIBREADLINE */ #endif /* ifdef HAVE_LIBREADLINE */
static void PrintConversionUnitCategory(int nCategory) enum ui_colors {
NONE,
RESET,
BLACK,
RED,
GREEN,
YELLOW,
BLUE,
MAGENTA,
CYAN,
WHITE,
BOLDBLACK,
BOLDRED,
BOLDGREEN,
BOLDYELLOW,
BOLDBLUE,
BOLDMAGENTA,
BOLDCYAN,
BOLDWHITE,
};
const char *const colors[] = {
"", // NONE
"\033[0m", // RESET
"\033[30m",
"\033[31m",
"\033[32m",
"\033[33m",
"\033[34m",
"\033[35m",
"\033[36m",
"\033[37m",
"\033[1m\033[30m",
"\033[1m\033[31m",
"\033[1m\033[32m",
"\033[1m\033[33m",
"\033[1m\033[34m",
"\033[1m\033[35m",
"\033[1m\033[36m",
"\033[1m\033[37m",
};
enum ui_pieces {
PROMPT,
CONV_CAT,
CONV_UNIT,
APPROX_ANSWER,
EXACT_ANSWER,
ERR_LOCATION,
ERR_TEXT,
PREF_NAME,
PREF_VAL,
PREF_CMD,
STATUS,
VAR_NAME,
VAR_DESC,
SUBVAR_NAME,
EXPLANATION,
UNCOLOR,
};
int black_and_white_ui[] = {
NONE, // PROMPT
NONE, // CONV_CAT
NONE, // CONV_UNIT
NONE, // APPROX_ANSWER
NONE, // EXACT_ANSWER
NONE, // ERR_LOCATION
NONE, // ERR_TEXT
NONE, // PREF_NAME
NONE, // PREF_VAL
NONE, // PREF_CMD
NONE, // STATUS
NONE, // VAR_NAME
NONE, // VAR_DESC
NONE, // SUBVAR_NAME
NONE, // EXPLANATION
NONE, // UNCOLOR
};
int color_ui[] = {
BLUE, // PROMPT
BOLDYELLOW, // CONV_CAT
CYAN, // CONV_UNIT
YELLOW, // APPROX_ANSWER
GREEN, // EXACT_ANSWER
BOLDMAGENTA, // ERR_LOCATION
BOLDRED, // ERR_TEXT
YELLOW, // PREF_NAME
CYAN, // PREF_VAL
BLUE, // PREF_CMD
BOLDGREEN, // STATUS
BOLDCYAN, // VAR_NAME
CYAN, // VAR_DESC
CYAN, // SUBVAR_NAME
NONE, // EXPLANATION
RESET, // UNCOLOR
};
int *uiselect = black_and_white_ui;
static void
PrintConversionUnitCategory(int nCategory)
{ {
printf("\n%s\n", conversion_names[nCategory]); printf("\n%s%s%s\n", colors[uiselect[CONV_CAT]], conversion_names[nCategory] , colors[uiselect[UNCOLOR]]);
size_t unit, nAka; size_t unit, nAka;
for (unit = 0; conversions[nCategory][unit].name; ++unit) { for (unit = 0; conversions[nCategory][unit].name; ++unit) {
printf("\n%s: ", conversions[nCategory][unit].name); printf("\n%s%s%s: ", colors[uiselect[CONV_UNIT]], conversions[nCategory] [unit].name, colors[uiselect[UNCOLOR]]);
for (nAka = 0; nAka < 9; ++nAka) { for (nAka = 0; nAka < 9; ++nAka) {
if (conversions[nCategory][unit].aka[nAka] != NULL) { if (conversions[nCategory][unit].aka[nAka] != NULL) {
if (nAka > 0) { printf(", "); } if (nAka > 0) { printf(", "); }
printf("%s", conversions[nCategory][unit].aka[nAka]); printf("%s", conversions[nCategory][unit].aka[nAka]);
} }
} }
} }
printf("\n\n"); printf("\n\n");
} }
int main(int argc, void
char *argv[]) show_answer(char *err,
int uncertain,
char *answer)
{ /*{{{*/
if (err && strlen(err)) {
display_and_clear_errstring();
}
if (uncertain) {
printf("%s%s %s%s\n", colors[uiselect[APPROX_ANSWER]], conf.print_equal
? "~=" : " ", colors[uiselect[UNCOLOR]], answer);
} else {
printf("%s%s %s%s\n", colors[uiselect[EXACT_ANSWER]], conf.print_equal ?
" =" : " ", colors[uiselect[UNCOLOR]], answer);
}
} /*}}}*/
static void
display_and_clear_errstring(void)
{ /*{{{ */
extern int scanerror;
extern char *errstring;
extern int errloc;
if (errstring && errstring[0]) {
if (errloc != -1) {
int i;
extern int show_line_numbers;
extern char *last_input;
if (show_line_numbers && last_input) {
fprintf(stderr, "-> %s\n", last_input);
}
fprintf(stderr, " ");
for (i = 0; i < errloc; i++) {
fprintf(stderr, " ");
}
fprintf(stderr, "%s^%s\n", colors[uiselect[ERR_LOCATION]], colors[ui
select[UNCOLOR]]);
errloc = -1;
}
fprintf(stderr, "%s%s%s", colors[uiselect[ERR_TEXT]], errstring, colors[
uiselect[UNCOLOR]]);
if (errstring[strlen(errstring) - 1] != '\n') {
fprintf(stderr, "\n");
}
free(errstring);
errstring = NULL;
scanerror = 0;
if (exit_on_err) {
EXIT_EARLY(EXIT_FAILURE);
}
}
} /*}}} */
int
main(int argc,
char *argv[])
{ /*{{{ */ { /*{{{ */
extern int yydebug; extern int yydebug;
extern int lines; extern int lines;
#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
char *readme = NULL; char *readme = NULL;
#else #else
char readme[BIG_STRING]; char readme[BIG_STRING];
#endif #endif
#ifdef HAVE_READLINE_HISTORY #ifdef HAVE_READLINE_HISTORY
char *historyfile = "/.wcalc_history"; char *historyfile = "/.wcalc_history";
#endif #endif
int tty, i; int tty, i;
short cmdline_input = 0; short cmdline_input = 0;
yydebug = 1; /* turn on ugly YACC debugging */ // yydebug = 1; /* turn on ugly YACC debugging */
yydebug = 0; /* turn off ugly YACC debugging */ yydebug = 0; /* turn off ugly YACC debugging */
initvar(); initvar();
lists_init(); lists_init();
/* initialize the preferences */ /* initialize the preferences */
conf.precision = -1; conf.precision = -1;
conf.engineering = automatic; conf.engineering = automatic;
standard_output = 1; standard_output = 1;
conf.picky_variables = 1; conf.picky_variables = 1;
skipping to change at line 423 skipping to change at line 608
} }
argnum = strtol(valstr, &endptr, 0); argnum = strtol(valstr, &endptr, 0);
if ((*endptr != '\0') || (endptr == valstr)) { if ((*endptr != '\0') || (endptr == valstr)) {
if (strlen(valstr)) { if (strlen(valstr)) {
fprintf(stderr, fprintf(stderr,
"-P option requires a valid integer (found '%s' inst ead).\n", valstr); "-P option requires a valid integer (found '%s' inst ead).\n", valstr);
} else { } else {
fprintf(stderr, fprintf(stderr,
"-P option requires a valid integer.\n"); "-P option requires a valid integer.\n");
} }
fflush(stderr); EXIT_EARLY(EXIT_FAILURE);
num_free(last_answer);
exit(EXIT_FAILURE);
} else { } else {
conf.precision = (int)argnum; conf.precision = (int)argnum;
} }
} else if (!strcmp(argv[i], "-E") || } else if (!strcmp(argv[i], "-E") ||
!strcmp(argv[i], "--engineering")) { !strcmp(argv[i], "--engineering")) {
conf.engineering = always; conf.engineering = always;
} else if (!strcmp(argv[i], "-EE")) { } else if (!strcmp(argv[i], "-EE")) {
conf.engineering = never; conf.engineering = never;
} else if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "--help")) { } else if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "--help")) {
print_command_help(); display_command_help();
num_free(last_answer); EXIT_EARLY(EXIT_SUCCESS);
exit(EXIT_SUCCESS);
} else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
printf("wcalc "VERSION "\n"); printf("wcalc "VERSION "\n");
num_free(last_answer); EXIT_EARLY(EXIT_SUCCESS);
exit(EXIT_SUCCESS);
} else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--units")) { } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--units")) {
if ((i + 1 >= argc) || !strcasecmp(argv[i + 1], "all")) { if ((i + 1 >= argc) || !strcasecmp(argv[i + 1], "all")) {
int nCategory; int nCategory;
for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) { for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) {
PrintConversionUnitCategory(nCategory); PrintConversionUnitCategory(nCategory);
} }
} else if (strlen(argv[i + 1]) == 1) { } else if (strlen(argv[i + 1]) == 1) {
fprintf(stderr, "The %s option's (optional) argument must be two or more letters of one\nof the following (case insensitive):\n", argv[i]); fprintf(stderr, "The %s option's (optional) argument must be two or more letters of one\nof the following (case insensitive):\n", argv[i]);
int nCategory; int nCategory;
for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) { for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) {
printf("\t%s\n", conversion_names[nCategory]); printf("\t%s\n", conversion_names[nCategory]);
} }
num_free(last_answer); EXIT_EARLY(EXIT_FAILURE);
exit(EXIT_FAILURE);
} else { } else {
const size_t len = strlen(argv[i + 1]); const size_t len = strlen(argv[i + 1]);
int printed = 0; int printed = 0;
int nCategory; int nCategory;
for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) { for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) {
if (!strncasecmp(argv[i + 1], conversion_names[nCategory], l en)) { if (!strncasecmp(argv[i + 1], conversion_names[nCategory], l en)) {
printed = 1; printed = 1;
PrintConversionUnitCategory(nCategory); PrintConversionUnitCategory(nCategory);
break; break;
} }
} }
if (printed == 0) { if (printed == 0) {
fprintf(stderr, "The %s option's (optional) argument must be two or more letters of one\nof the following (case insensitive):\n", argv[i]); fprintf(stderr, "The %s option's (optional) argument must be two or more letters of one\nof the following (case insensitive):\n", argv[i]);
int nCategory;
for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) { for (nCategory = 0; nCategory <= MAX_TYPE; ++nCategory) {
printf("\t%s\n", conversion_names[nCategory]); printf("\t%s\n", conversion_names[nCategory]);
} }
num_free(last_answer); EXIT_EARLY(EXIT_FAILURE);
exit(EXIT_FAILURE);
} }
} }
num_free(last_answer); EXIT_EARLY(EXIT_SUCCESS);
exit(EXIT_SUCCESS);
} else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--decimal") || } else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--decimal") ||
!strcmp(argv[i], "-dec") || !strcmp(argv[i], "--dec")) { !strcmp(argv[i], "-dec") || !strcmp(argv[i], "--dec")) {
conf.output_format = DECIMAL_FORMAT; conf.output_format = DECIMAL_FORMAT;
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--hexadecimal") | | } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--hexadecimal") | |
!strcmp(argv[i], "-hex") || !strcmp(argv[i], "--hex")) { !strcmp(argv[i], "-hex") || !strcmp(argv[i], "--hex")) {
conf.output_format = HEXADECIMAL_FORMAT; conf.output_format = HEXADECIMAL_FORMAT;
} else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--octal") || } else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--octal") ||
!strcmp(argv[i], "-oct") || !strcmp(argv[i], "--oct")) { !strcmp(argv[i], "-oct") || !strcmp(argv[i], "--oct")) {
conf.output_format = OCTAL_FORMAT; conf.output_format = OCTAL_FORMAT;
} else if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--binary") || } else if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--binary") ||
skipping to change at line 516 skipping to change at line 693
!strcmp(&(argv[i][8]), "none")) { !strcmp(&(argv[i][8]), "none")) {
conf.rounding_indication = NO_ROUNDING_INDICATION; conf.rounding_indication = NO_ROUNDING_INDICATION;
} else if (!strcmp(&(argv[i][8]), "simple")) { } else if (!strcmp(&(argv[i][8]), "simple")) {
conf.rounding_indication = SIMPLE_ROUNDING_INDICATION; conf.rounding_indication = SIMPLE_ROUNDING_INDICATION;
} else if (!strcmp(&(argv[i][8]), "sig_fig")) { } else if (!strcmp(&(argv[i][8]), "sig_fig")) {
conf.rounding_indication = SIG_FIG_ROUNDING_INDICATION; conf.rounding_indication = SIG_FIG_ROUNDING_INDICATION;
} }
} else if (!strcmp(argv[i], "--round")) { } else if (!strcmp(argv[i], "--round")) {
fprintf(stderr, fprintf(stderr,
"--round requires an argument (none|simple|sig_fig)\n"); "--round requires an argument (none|simple|sig_fig)\n");
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} else if (!strncmp(argv[i], "--idsep=", 7)) { } else if (!strncmp(argv[i], "--idsep=", 7)) {
if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) { if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) {
fprintf(stderr, "--idsep= must have an argument\n"); fprintf(stderr, "--idsep= must have an argument\n");
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
if ((conf.in_thou_delimiter != argv[i][7]) && ((conf.in_thou_delimit er != 0) || (conf.thou_delimiter != argv[i][7]))) { if ((conf.in_thou_delimiter != argv[i][7]) && ((conf.in_thou_delimit er != 0) || (conf.thou_delimiter != argv[i][7]))) {
conf.in_dec_delimiter = argv[i][7]; conf.in_dec_delimiter = argv[i][7];
} else { } else {
fprintf(stderr, fprintf(stderr,
"%c cannot be the decimal separator. It is the thousands separator.\n", "%c cannot be the decimal separator. It is the thousands separator.\n",
argv[i][7]); argv[i][7]);
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
} else if (!strncmp(argv[i], "--dsep=", 7)) { } else if (!strncmp(argv[i], "--dsep=", 7)) {
if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) { if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) {
fprintf(stderr, "--dsep= must have an argument\n"); fprintf(stderr, "--dsep= must have an argument\n");
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
if (conf.thou_delimiter != argv[i][7]) { if (conf.thou_delimiter != argv[i][7]) {
conf.dec_delimiter = argv[i][7]; conf.dec_delimiter = argv[i][7];
} else { } else {
fprintf(stderr, fprintf(stderr,
"%c cannot be the decimal separator. It is the thousands separator.\n", "%c cannot be the decimal separator. It is the thousands separator.\n",
argv[i][7]); argv[i][7]);
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
} else if (!strncmp(argv[i], "--itsep=", 7)) { } else if (!strncmp(argv[i], "--itsep=", 7)) {
if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) { if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) {
fprintf(stderr, "--itsep= must have an argument\n"); fprintf(stderr, "--itsep= must have an argument\n");
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
if ((conf.in_dec_delimiter != argv[i][7]) && ((conf.in_dec_delimiter != 0) || (conf.dec_delimiter != argv[i][7]))) { if ((conf.in_dec_delimiter != argv[i][7]) && ((conf.in_dec_delimiter != 0) || (conf.dec_delimiter != argv[i][7]))) {
conf.in_thou_delimiter = argv[i][7]; conf.in_thou_delimiter = argv[i][7];
} else { } else {
fprintf(stderr, fprintf(stderr,
"%c cannot be the thousands separator. It is the decimal separator.\n", "%c cannot be the thousands separator. It is the decimal separator.\n",
argv[i][7]); argv[i][7]);
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
} else if (!strncmp(argv[i], "--tsep=", 7)) { } else if (!strncmp(argv[i], "--tsep=", 7)) {
if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) { if ((strlen(argv[i]) > 8) || (strlen(argv[i]) == 7)) {
fprintf(stderr, "--tsep= must have an argument\n"); fprintf(stderr, "--tsep= must have an argument\n");
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
if (conf.dec_delimiter != argv[i][7]) { if (conf.dec_delimiter != argv[i][7]) {
conf.thou_delimiter = argv[i][7]; conf.thou_delimiter = argv[i][7];
} else { } else {
fprintf(stderr, fprintf(stderr,
"%c cannot be the thousands separator. It is the decimal separator.\n", "%c cannot be the thousands separator. It is the decimal separator.\n",
argv[i][7]); argv[i][7]);
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
} else if (!strncmp(argv[i], "--bits", 6)) { } else if (!strncmp(argv[i], "--bits", 6)) {
unsigned long int argnum; unsigned long int argnum;
char *endptr; char *endptr;
argnum = strtoul(&(argv[i][6]), &endptr, 0); argnum = strtoul(&(argv[i][6]), &endptr, 0);
if ((endptr != NULL) && (strlen(endptr) > 0)) { if ((endptr != NULL) && (strlen(endptr) > 0)) {
fprintf(stderr, fprintf(stderr,
"--bits option requires a valid integer without spaces.\ n"); "--bits option requires a valid integer without spaces.\ n");
num_free(last_answer); EXIT_EARLY(EXIT_FAILURE);
exit(EXIT_FAILURE);
} else { } else {
if (argnum < NUM_PREC_MIN) { if (argnum < NUM_PREC_MIN) {
fprintf(stderr, "Minimum precision is %lu.\n", (unsigned lon g)NUM_PREC_MIN); fprintf(stderr, "Minimum precision is %lu.\n", (unsigned lon g)NUM_PREC_MIN);
} else if (argnum > NUM_PREC_MAX) { } else if (argnum > NUM_PREC_MAX) {
fprintf(stderr, "Maximum precision is %lu.\n", (unsigned lon g)NUM_PREC_MAX); fprintf(stderr, "Maximum precision is %lu.\n", (unsigned lon g)NUM_PREC_MAX);
} else { } else {
num_set_default_prec(argnum); num_set_default_prec(argnum);
} }
} }
} else if (!strcmp(argv[i], "--ints")) { } else if (!strcmp(argv[i], "--ints")) {
conf.print_ints = !conf.print_ints; conf.print_ints = !conf.print_ints;
} else if (!strcmp(argv[i], "--delim")) { } else if (!strcmp(argv[i], "--delim")) {
conf.print_commas = !conf.print_commas; conf.print_commas = !conf.print_commas;
} else if (!strcmp(argv[i], "--verbose")) { } else if (!strcmp(argv[i], "--verbose")) {
conf.verbose = !conf.verbose; conf.verbose = !conf.verbose;
} else if (!strcmp(argv[i], "--yydebug")) { } else if (!strcmp(argv[i], "--yydebug")) {
yydebug = 1; yydebug = 1;
} else if (!strcmp(argv[i], "-n")) { } else if (!strcmp(argv[i], "-n")) {
conf.print_equal = 0; conf.print_equal = 0;
} else if (!strcmp(argv[i], "-C") || !strcmp(argv[i], "--color")) {
conf.color_ui = !conf.color_ui;
if (conf.color_ui) {
uiselect = color_ui;
} else {
uiselect = black_and_white_ui;
}
} else if (!strcmp(argv[i], "--defaults")) { } else if (!strcmp(argv[i], "--defaults")) {
/* ignore this argument */ /* ignore this argument */
} else { } else {
extern char *errstring; extern char *errstring;
if (isatty(1) == 0) { /* Find out where stdout is going */
uiselect = black_and_white_ui;
}
if (!cmdline_input) { if (!cmdline_input) {
#ifdef HAVE_READLINE_HISTORY #ifdef HAVE_READLINE_HISTORY
char *filename; char *filename;
const char *const home = getenv("HOME"); const char *const home = getenv("HOME");
using_history(); using_history();
filename = malloc(strlen(home) + strlen(historyfile) + 2); filename = malloc(strlen(home) + strlen(historyfile) + 2);
snprintf(filename, snprintf(filename,
strlen(home) + strlen(historyfile) + 1, strlen(home) + strlen(historyfile) + 1,
"%s%s", "%s%s",
skipping to change at line 655 skipping to change at line 842
if (!cmdline_input) { if (!cmdline_input) {
extern char *errstring; extern char *errstring;
char *envinput = getenv("wcalc_input"); char *envinput = getenv("wcalc_input");
if (envinput) { if (envinput) {
#ifdef HAVE_READLINE_HISTORY #ifdef HAVE_READLINE_HISTORY
char *filename; char *filename;
const char *const home = getenv("HOME"); const char *const home = getenv("HOME");
using_history(); using_history();
filename = malloc(strlen(home) + strlen(historyfile) + 2); filename = malloc(strlen(home) + strlen(historyfile) + 2);
snprintf(filename, strcpy(filename, home);
strlen(home) + strlen(historyfile) + 1, strcat(filename, historyfile);
"%s%s",
home, historyfile);
if (read_history(filename)) { if (read_history(filename)) {
if (errno != ENOENT) { if (errno != ENOENT) {
perror("Reading History"); perror("Reading History");
} }
} }
free(filename); free(filename);
#endif /* ifdef HAVE_READLINE_HISTORY */ #endif /* ifdef HAVE_READLINE_HISTORY */
cmdline_input = 1; cmdline_input = 1;
if (conf.verbose) { if (conf.verbose) {
printf("-> %s\n", envinput); printf("-> %s\n", envinput);
skipping to change at line 709 skipping to change at line 894
if (write_history(filename)) { if (write_history(filename)) {
perror("Saving History 1"); perror("Saving History 1");
} }
if (conf.history_limit) { if (conf.history_limit) {
if (history_truncate_file(filename, conf.history_limit_len)) { if (history_truncate_file(filename, conf.history_limit_len)) {
perror("Truncating History"); perror("Truncating History");
} }
} }
free(filename); free(filename);
#endif /* ifdef HAVE_READLINE_HISTORY */ #endif /* ifdef HAVE_READLINE_HISTORY */
clearHistory(); EXIT_EARLY(EXIT_SUCCESS);
cleanupvar();
num_free(last_answer);
lists_cleanup();
exit(EXIT_SUCCESS);
} }
tty = isatty(0); /* Find out where stdin is coming from... */ tty = isatty(0); /* Find out where stdin is coming from... */
if (tty > 0) { if (tty > 0) {
/* if stdin is a keyboard or terminal, then use readline and prompts */ /* if stdin is a keyboard or terminal, then use readline and prompts */
#ifdef HAVE_READLINE_HISTORY #ifdef HAVE_READLINE_HISTORY
const char *const home = getenv("HOME"); const char *const home = getenv("HOME");
char *filename; char *filename;
using_history(); using_history();
skipping to change at line 736 skipping to change at line 917
strlen(home) + strlen(historyfile) + 1, strlen(home) + strlen(historyfile) + 1,
"%s%s", "%s%s",
home, historyfile); home, historyfile);
if (read_history(filename)) { if (read_history(filename)) {
if (errno != ENOENT) { if (errno != ENOENT) {
perror("Reading History"); perror("Reading History");
} }
} }
#endif /* ifdef HAVE_READLINE_HISTORY */ #endif /* ifdef HAVE_READLINE_HISTORY */
#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
build_qcommands();
rl_attempted_completion_function = wcalc_completion; rl_attempted_completion_function = wcalc_completion;
rl_basic_word_break_characters = " \t\n\"\'+-*/[{()}]=<>!|~&^%"; rl_basic_word_break_characters = " \t\n\"\'+-*/[{()}]=<>!|~&^%";
#endif #endif
printf exit_on_err = 0;
("Enter an expression to evaluate, q to quit, or ? for help:\n"); printf("Enter an expression to evaluate, q to quit, or ? for help:\n");
while (1) { while (1) {
lines = 1; lines = 1;
fflush(NULL); fflush(NULL);
#ifdef HAVE_LIBREADLINE #ifdef HAVE_LIBREADLINE
readme = readline("-> "); {
#else char prompt[30] = "";
snprintf(prompt, 30, "\1%s\2->\1%s\2 ", colors[uiselect[PROMPT]]
, colors[uiselect[UNCOLOR]]);
readme = readline(prompt);
}
if (!readme) {
/* from the readline manpage:
* readline returns the text of the line read. A blank
* line returns the empty string. If EOF is encountered
* while reading a line, and the line is empty, NULL is
* returned. If an eof is read with a non-empty line, it
* is treated as a newline.
* This means: readme == NULL is a perfectly reasonable
* response from readline(), AND it means something
* significant. DO NOT DO errno PARSING HERE!!!!
*/
printf("\n");
break;
}
#else /* ifdef HAVE_LIBREADLINE */
{ {
char c; char c;
unsigned int i = 0; unsigned int i = 0;
memset(readme, 0, BIG_STRING); memset(readme, 0, BIG_STRING);
printf("-> "); printf("%s->%s ", colors[uiselect[PROMPT]], colors[uiselect[UNCO LOR]]);
fflush(stdout); fflush(stdout);
c = fgetc(stdin); c = fgetc(stdin);
while (c != '\n' && i < BIG_STRING && !feof(stdin) && while (c != '\n' && i < BIG_STRING && !feof(stdin) &&
!ferror(stdin)) { !ferror(stdin)) {
readme[i] = c; readme[i] = c;
c = fgetc(stdin); c = fgetc(stdin);
++i; ++i;
} }
if (feof(stdin) || ferror(stdin)) { if (feof(stdin) || ferror(stdin)) {
printf("\n");
break; break;
} }
} }
#endif /* ifdef HAVE_LIBREADLINE */ #endif /* ifdef HAVE_LIBREADLINE */
if (!readme) {
/* from the readline manpage:
* readline returns the text of the line read. A blank
* line returns the empty string. If EOF is encountered
* while reading a line, and the line is empty, NULL is
* returned. If an eof is read with a non-empty line, it
* is treated as a newline.
* This means: readme == NULL is a perfectly reasonable
* response from readline(), AND it means something
* significant. DO NOT DO errno PARSING HERE!!!!
*/
printf("\n");
break;
}
/* if there is a line */ /* if there is a line */
if (strlen(readme)) { if (strlen(readme)) {
if (!strcmp(readme, "q") || !strcmp(readme, "quit") || if (!strcmp(readme, "q") || !strcmp(readme, "quit") ||
!strcmp(readme, "\\q")) { !strcmp(readme, "\\q")) {
break; break;
} else if (!strncmp(readme, "\\yydebug", 8)) { } else if (!strncmp(readme, "\\yydebug", 8)) {
// addToHistory(readme, 0); // addToHistory(readme, 0);
yydebug = !yydebug; yydebug = !yydebug;
printf("Debug Mode %s\n", yydebug ? "On" : "Off"); printf("Debug Mode %s\n", yydebug ? "On" : "Off");
} else if (!strncmp(readme, "\\color", 6)) {
conf.color_ui = !conf.color_ui;
if (conf.color_ui) {
uiselect = color_ui;
} else {
uiselect = black_and_white_ui;
}
} else { } else {
if (conf.verbose) { if (conf.verbose) {
printf("-> %s\n", readme); printf("-> %s\n", readme);
} }
parseme(readme); parseme(readme);
{ {
extern char *errstring; extern char *errstring;
if (!errstring || (errstring && !strlen(errstring)) || if (!errstring || (errstring && !strlen(errstring)) ||
conf.remember_errors) { conf.remember_errors) {
skipping to change at line 836 skipping to change at line 1030
if (history_truncate_file(filename, conf.history_limit_len)) { if (history_truncate_file(filename, conf.history_limit_len)) {
perror("Truncating History"); perror("Truncating History");
} }
} }
free(filename); free(filename);
#endif /* ifdef HAVE_READLINE_HISTORY */ #endif /* ifdef HAVE_READLINE_HISTORY */
} else if (tty < 0) { } else if (tty < 0) {
fprintf(stderr, "Could not determine terminal type.\n"); fprintf(stderr, "Could not determine terminal type.\n");
} else { } else {
/* if stdin is ANYTHING ELSE (a pipe, a file, etc), don't prompt */ /* if stdin is ANYTHING ELSE (a pipe, a file, etc), don't prompt */
char *line, gotten;
unsigned int linelen = 0, maxlinelen = BIG_STRING; unsigned int linelen = 0, maxlinelen = BIG_STRING;
extern int show_line_numbers; extern int show_line_numbers;
exit_on_err = 1;
show_line_numbers = 1; show_line_numbers = 1;
while (1) { while (1) {
line = calloc(maxlinelen, sizeof(char)); char *line = calloc(maxlinelen, sizeof(char));
gotten = fgetc(stdin); char gotten = fgetc(stdin);
while (gotten != '\n' && !feof(stdin) && !ferror(stdin)) { while (gotten != '\n' && !feof(stdin) && !ferror(stdin)) {
line[linelen] = gotten; line[linelen] = gotten;
gotten = fgetc(stdin); gotten = fgetc(stdin);
linelen++; linelen++;
if (linelen > maxlinelen) { if (linelen > maxlinelen) {
char *temp; char *temp;
temp = realloc(line, (maxlinelen + BIG_STRING) * sizeof(char )); temp = realloc(line, (maxlinelen + BIG_STRING) * sizeof(char ));
if (!temp) { if (!temp) {
free(line); free(line);
fprintf(stderr, fprintf(stderr,
"Ran out of memory. Line too long.\n"); "Ran out of memory. Line too long.\n");
exit(EXIT_FAILURE); EXIT_EARLY(EXIT_FAILURE);
} }
memset(temp + maxlinelen, 0, BIG_STRING); memset(temp + maxlinelen, 0, BIG_STRING);
maxlinelen += BIG_STRING; maxlinelen += BIG_STRING;
line = temp; line = temp;
} }
} }
if (ferror(stdin) || (feof(stdin) && (linelen == 0))) { if (ferror(stdin) || (feof(stdin) && (linelen == 0))) {
free(line); free(line);
break; break;
} }
skipping to change at line 877 skipping to change at line 1071
printf("-> %s\n", line); printf("-> %s\n", line);
} }
parseme(line); parseme(line);
if (putval("a", last_answer, "previous answer") != 0) { if (putval("a", last_answer, "previous answer") != 0) {
fprintf(stderr, "error storing last answer\n"); fprintf(stderr, "error storing last answer\n");
} }
{ {
extern int errloc; extern int errloc;
if (errloc != -1) { if (errloc != -1) {
errloc = -1;
display_and_clear_errstring(); display_and_clear_errstring();
/*fprintf(stderr, "%s", errstring); /*fprintf(stderr, "%s", errstring);
* if (errstring[strlen(errstring) - 1] != '\n') * if (errstring[strlen(errstring) - 1] != '\n')
* fprintf(stderr, "\n"); * fprintf(stderr, "\n");
* free(errstring); * free(errstring);
* errstring = NULL;*/ * errstring = NULL;*/
} }
} }
free(line); free(line);
linelen = 0; linelen = 0;
} }
} }
clearHistory();
cleanupvar();
if (pretty_answer) { if (pretty_answer) {
extern char *pa; extern char *pa;
free(pretty_answer); free(pretty_answer);
if (pa) { if (pa) {
free(pa); free(pa);
} }
} }
num_free(last_answer); EXIT_EARLY(EXIT_SUCCESS);
lists_cleanup();
exit(EXIT_SUCCESS);
} /*}}} */ } /*}}} */
static int read_preload(void) static int
read_preload(void)
{ /*{{{ */ { /*{{{ */
int fd = openDotFile("wcalc_preload", O_RDONLY); int fd = openDotFile("wcalc_preload", O_RDONLY);
switch (fd) { switch (fd) {
case -1: case -1:
fprintf(stderr, "HOME environment variable unset. Cannot read preloa d file.\n"); fprintf(stderr, "HOME environment variable unset. Cannot read preloa d file.\n");
return 0; return 0;
case -2: case -2:
fprintf(stderr, "HOME environment variable is too long. Cannot read preload file.\n"); fprintf(stderr, "HOME environment variable is too long. Cannot read preload file.\n");
skipping to change at line 936 skipping to change at line 1126
} }
if (loadStateFD(fd, 0) < 0) { if (loadStateFD(fd, 0) < 0) {
perror("Error reading preload file (~/.wcalc_preload)"); perror("Error reading preload file (~/.wcalc_preload)");
} }
if (close(fd) < 0) { if (close(fd) < 0) {
perror("Could not close preload file."); perror("Could not close preload file.");
} }
return 1; return 1;
} /*}}} */ } /*}}} */
static int read_prefs(void) #define CHECK_COLOR(x) else if (!strcasecmp(str, # x)) { return x; }
static enum ui_colors
str2color(const char *str)
{
if (!strcasecmp(str, "NONE")) {
return NONE;
}
CHECK_COLOR(BLACK)
CHECK_COLOR(RED)
CHECK_COLOR(GREEN)
CHECK_COLOR(YELLOW)
CHECK_COLOR(BLUE)
CHECK_COLOR(MAGENTA)
CHECK_COLOR(CYAN)
CHECK_COLOR(WHITE)
CHECK_COLOR(BOLDBLACK)
CHECK_COLOR(BOLDRED)
CHECK_COLOR(BOLDGREEN)
CHECK_COLOR(BOLDYELLOW)
CHECK_COLOR(BOLDBLUE)
CHECK_COLOR(BOLDMAGENTA)
CHECK_COLOR(BOLDCYAN)
CHECK_COLOR(BOLDWHITE)
else {
fprintf(stderr, "Unrecognized color: '%s'\n", str);
return RESET;
}
}
#define HANDLECOLOR(x) else if (!strcasecmp(key, # x "]")) { uiselect[x] = str2c
olor(value); }
static int
assign_color_prefs(const char *key,
const char *value)
{
assert(key);
assert(value);
if (uiselect != color_ui) {
fprintf(stderr, "Colors not enabled!\n");
return 0;
}
if (!strcasecmp(key, "conversion_category]")) {
uiselect[CONV_CAT] = str2color(value);
} else if (!strcasecmp(key, "conversion_unit]")) {
uiselect[CONV_UNIT] = str2color(value);
}
HANDLECOLOR(PROMPT)
HANDLECOLOR(APPROX_ANSWER)
HANDLECOLOR(EXACT_ANSWER)
HANDLECOLOR(ERR_LOCATION)
HANDLECOLOR(ERR_TEXT)
HANDLECOLOR(PREF_NAME)
HANDLECOLOR(PREF_VAL)
HANDLECOLOR(PREF_CMD)
HANDLECOLOR(STATUS)
HANDLECOLOR(VAR_NAME)
HANDLECOLOR(VAR_DESC)
HANDLECOLOR(SUBVAR_NAME)
HANDLECOLOR(EXPLANATION)
else {
char *res = strdup(key);
*strchr(res, ']') = 0;
fprintf(stderr, "Unrecognized colorable resource: '%s'\n", res);
free(res);
return 0;
}
return 1;
}
static int
set_pref(const char *key,
const char *value)
{
if (!strcmp(key, "precision")) {
conf.precision = atoi(value);
} else if (!strcmp(key, "show_equals")) {
conf.print_equal = TRUEFALSE;
} else if (!strcmp(key, "flag_undeclared")) {
conf.picky_variables = TRUEFALSE;
} else if (!strcmp(key, "use_radians")) {
conf.use_radians = TRUEFALSE;
} else if (!strcmp(key, "print_prefixes")) {
conf.print_prefixes = TRUEFALSE;
} else if (!strcmp(key, "save_errors")) {
conf.remember_errors = TRUEFALSE;
} else if (!strcmp(key, "remember_errors")) {
conf.remember_errors = TRUEFALSE;
} else if (!strcmp(key, "precision_guard")) {
conf.precision_guard = TRUEFALSE;
} else if (!strcmp(key, "print_integers")) {
conf.print_ints = TRUEFALSE;
} else if (!strcmp(key, "print_delimiters")) {
conf.print_commas = TRUEFALSE;
} else if (!strcmp(key, "input_thousands_delimiter")) {
conf.in_thou_delimiter = value[0];
} else if (!strcmp(key, "input_decimal_delimiter")) {
conf.in_dec_delimiter = value[0];
} else if (!strcmp(key, "thousands_delimiter")) {
conf.thou_delimiter = value[0];
} else if (!strcmp(key, "decimal_delimiter")) {
conf.dec_delimiter = value[0];
} else if (!strcmp(key, "history_limit")) {
if (!strcmp(value, "no")) {
conf.history_limit = conf.history_limit_len = 0;
} else {
conf.history_limit = 1;
conf.history_limit_len = strtoul(value, NULL, 0);
}
} else if (!strcmp(key, "output_format")) {
if (!strcmp(value, "decimal")) {
conf.output_format = DECIMAL_FORMAT;
} else if (!strcmp(value, "octal")) {
conf.output_format = OCTAL_FORMAT;
} else if (!strcmp(value, "binary")) {
conf.output_format = BINARY_FORMAT;
} else if (!strcmp(value, "hex") || !strcmp(value, "hexadecimal")) {
conf.output_format = HEXADECIMAL_FORMAT;
} else {
fprintf(stderr, "Unrecognized output_format in wcalcrc.\n\tSupported
formats are decimal, octal, binary, hex.\n");
return 0;
}
} else if (!strcmp(key, "rounding_indication")) {
if (!strcmp(value, "no") || !strcmp(value, "none")) {
conf.rounding_indication = NO_ROUNDING_INDICATION;
} else if (!strcmp(value, "simple")) {
conf.rounding_indication = SIMPLE_ROUNDING_INDICATION;
} else if (!strcmp(value, "sig_fig")) {
conf.rounding_indication = SIG_FIG_ROUNDING_INDICATION;
} else {
fprintf(stderr, "Unrecognized rounding_indication in wcalcrc.\n\tSup
ported indication types are none, simple, sig_fig.\n");
return 0;
}
} else if (!strcmp(key, "engineering")) {
if (!strcmp(value, "auto") || !strcmp(value, "automatic") || !strcmp(val
ue, "yes") || !strcmp(value, "true") || !strcmp(value, "1")) {
conf.engineering = automatic;
} else if (!strcmp(value, "always")) {
conf.engineering = always;
} else {
conf.engineering = never;
}
} else if (!strcmp(key, "c_style_mod")) {
conf.c_style_mod = TRUEFALSE;
} else if (!strcmp(key, "color_ui") || !strcmp(key, "color")) {
conf.color_ui = TRUEFALSE;
if (conf.color_ui) {
uiselect = color_ui;
} else {
uiselect = black_and_white_ui;
}
} else if (!strncmp(key, "colors[", 7)) {
return assign_color_prefs(key + 7, value);
} else {
fprintf(stderr, "Unrecognized key in wcalcrc: %s\n", key);
return 0;
}
return 1;
}
static void
config_error(const char *format,
...)
{ /*{{{*/
va_list args;
fprintf(stderr, "Wcalc: Config: ");
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
} /*}}}*/
static size_t
copy_string(char *d,
const char *s,
size_t dmax,
size_t smax)
{ /*{{{*/
size_t dcurs = 0, scurs = 0;
const char quoted = (s[0] == '\'');
if (quoted) {
scurs = 1;
while (dcurs < dmax && scurs < smax && s[scurs] != '\'') {
d[dcurs++] = s[scurs++];
}
scurs++; // skip the terminating quote
} else {
do {
d[dcurs++] = s[scurs++];
} while (dcurs < dmax && scurs < smax &&
(isalnum(s[scurs]) || s[scurs] == '[' || s[scurs] == ']' || s[s
curs] == '.' || s[scurs] == '_' || s[scurs] == ' '));
}
if (scurs > smax) { return 0; }
if (dcurs > dmax) { return 0; }
d[dcurs] = 0;
while (dcurs > 0 && isspace(d[dcurs - 1])) {
dcurs--;
d[dcurs] = 0;
}
return scurs;
} /*}}}*/
static int
read_prefs(void)
{ /*{{{ */ { /*{{{ */
int fd = openDotFile("wcalcrc", O_RDONLY); int fd = openDotFile("wcalcrc", O_RDONLY);
char key[BIG_STRING], value[BIG_STRING]; char key[BIG_STRING], value[BIG_STRING];
size_t curs = 0; size_t curs = 0;
int retval = 1; size_t curs_max;
char *f_mutable;
const char *f;
switch (fd) { switch (fd) {
case -1: case -1:
fprintf(stderr, "HOME environment variable unset. Cannot read prefer ences.\n"); fprintf(stderr, "HOME environment variable unset. Cannot read prefer ences.\n");
return 0; return 0;
case -2: case -2:
fprintf(stderr, "HOME environment variable is too long. Cannot read preferences.\n"); fprintf(stderr, "HOME environment variable is too long. Cannot read preferences.\n");
return 0; return 0;
} }
if (fd < 0) { if (fd < 0) {
if (errno == ENOENT) { if (errno == ENOENT) {
/* The prefs file does not exist. This is okay, just means we can't read it. */ /* The prefs file does not exist. This is okay, just means we can't read it. */
return 1; return 1;
} }
perror("Could not open preferences file (~/.wcalcrc)"); perror("Could not open preferences file (~/.wcalcrc)");
return 0; return 0;
} }
while (retval == 1) { {
char quoted = 0; struct stat info;
char junk; if (fstat(fd, &info)) {
perror("Could not determine the size of the preference file");
close(fd);
return 0;
}
curs_max = info.st_size - 1;
f_mutable = mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (f_mutable == MAP_FAILED) {
perror("Could not read the preference file");
close(fd);
return 0;
}
f = f_mutable;
}
assert(curs_max > curs);
do {
memset(value, 0, BIG_STRING); memset(value, 0, BIG_STRING);
memset(key, 0, BIG_STRING); memset(key, 0, BIG_STRING);
curs = 0;
// read until we find a non-comment // read until we find a non-comment
while (1 == (retval = read(fd, &(key[curs]), 1))) { while (curs < curs_max && (isspace(f[curs]) || f[curs] == '#')) {
// if we find a comment if (f[curs] == '#') { // skip to the next line
if (key[curs] == '#') { do {
// read until the end of line curs++;
junk = 0; } while (curs < curs_max && f[curs] != '\n');
while (read(fd, &junk, 1) == 1 && junk != '\n') ;
} else if (isalpha((int)(key[curs]))) {
break;
} }
}
if (retval != 1) {
break;
}
// read in the key
quoted = 1;
if (key[curs] != '\'') {
curs++; curs++;
quoted = 0;
} }
while (retval == 1 && curs < BIG_STRING) { if (curs >= curs_max) { break; } // not an error!
retval = read(fd, &(key[curs]), 1); // read in the key
if ((!quoted && isspace((int)(key[curs]))) || {
(!quoted && (key[curs] == '=')) || size_t skip = copy_string(key, f + curs, BIG_STRING, curs_max - curs
(quoted && (key[curs] != '\''))) { );
break; if (!skip) {
config_error("Incomplete key (%s)! (probably an unterminated quo
te)\n", key);
goto err_exit;
} }
++curs; curs += skip;
} }
if (retval != 1) {
break;
}
junk = key[curs];
key[curs] = 0;
// eat the equals sign (and any surrounding space) // eat the equals sign (and any surrounding space)
while (retval == 1 && (isspace((int)junk) || junk == '=')) { while (curs < curs_max && isspace(f[curs])) curs++;
retval = read(fd, &junk, 1); if ((curs == curs_max) || (f[curs] != '=')) {
config_error("Expected equals (=) after key (%s)!\n", key);
goto err_exit;
} }
if (retval != 1) { do {
break; curs++;
} while (curs < curs_max && isspace(f[curs]));
if (curs == curs_max) {
config_error("Key (%s) has no value!\n", key);
goto err_exit;
} }
value[0] = junk; // junk now contains the next non-junk character
curs = 0;
// read in the value // read in the value
quoted = 1; {
if (value[0] != '\'') { size_t skip = copy_string(value, f + curs, BIG_STRING, curs_max - cu
++curs; rs);
quoted = 0; if (!skip) {
} config_error("Incomplete value (%s) for key (%s)! (probably an u
while (retval == 1 && value[curs - 1] && curs < BIG_STRING) { nterminated quote)\n", value, key);
retval = read(fd, &(value[curs]), 1); goto err_exit;
if ((!quoted && isspace((int)(value[curs]))) || }
(quoted && (value[curs] != '\''))) { curs += skip;
break; }
if (!set_pref(key, value)) { goto err_exit; }
// eat the rest of the line
while (curs < curs_max && f[curs] != '\n') curs++;
if (curs < curs_max) { curs++; }
} while (curs < curs_max);
if (munmap(f_mutable, curs_max + 1)) {
perror("Unmapping the config file");
}
if (close(fd)) {
perror("Closing the config file");
}
return 1;
err_exit:
config_error("Corrupt config file. Cannot continue.\n");
exit(EXIT_FAILURE);
} /*}}} */
static void
prefline(const char *name,
const char *val,
const char *cmd)
{
if (name && val && cmd) {
printf("%s%27s:%s %s%-24s%s -> ",
colors[uiselect[PREF_NAME]], name, colors[uiselect[UNCOLOR]],
colors[uiselect[PREF_VAL]], val, colors[uiselect[UNCOLOR]]);
if (strchr(cmd, ',')) {
unsigned offset = 0;
while (strchr(cmd + offset, ',')) {
unsigned cmdlen = strchr(cmd + offset, ',') - (cmd + offset);
printf("%s%.*s%s, ",
colors[uiselect[PREF_CMD]], cmdlen, cmd + offset, colors[
uiselect[UNCOLOR]]);
offset += cmdlen + 1;
} }
curs++; printf("%s%s%s\n",
colors[uiselect[PREF_CMD]], cmd + offset, colors[uiselect[UNC
OLOR]]);
} else {
printf("%s%s%s\n",
colors[uiselect[PREF_CMD]], cmd, colors[uiselect[UNCOLOR]]);
} }
value[curs] = 0; } else if (name && val) {
printf("%s%27s:%s %s%-24s%s\n",
colors[uiselect[PREF_NAME]], name, colors[uiselect[UNCOLOR]],
colors[uiselect[PREF_VAL]], val, colors[uiselect[UNCOLOR]]);
}
}
if (!strcmp(key, "precision")) { #define DP_YESNO(x) ((x) ? "yes" : "no")
conf.precision = atoi(value); void
} else if (!strcmp(key, "show_equals")) { display_prefs(void)
conf.print_equal = TRUEFALSE; {
} else if (!strcmp(key, "flag_undeclared")) { if (standard_output) {
conf.picky_variables = TRUEFALSE; char tmp[50];
} else if (!strcmp(key, "use_radians")) { sprintf(tmp, "%-3i %s", conf.precision, ((conf.precision == -1) ? "(auto
conf.use_radians = TRUEFALSE; )" : " "));
} else if (!strcmp(key, "print_prefixes")) { prefline("Display Precision", tmp, "\\p");
conf.print_prefixes = TRUEFALSE; sprintf(tmp, "%-24lu", (unsigned long)num_get_default_prec());
} else if (!strcmp(key, "save_errors")) { prefline("Internal Precision", tmp, "\\bits");
conf.remember_errors = TRUEFALSE; prefline("Engineering Output",
} else if (!strcmp(key, "remember_errors")) { (conf.engineering == always) ? "always" : (conf.engineering ==
conf.remember_errors = TRUEFALSE; never) ? "never " : "auto ",
} else if (!strcmp(key, "precision_guard")) { "\\e");
conf.precision_guard = TRUEFALSE; prefline("Output Format", output_string(conf.output_format), "\\b,\\d,\\
} else if (!strcmp(key, "print_integers")) { h,\\o");
conf.print_ints = TRUEFALSE; prefline("Use Radians", DP_YESNO(conf.use_radians), "\\r");
} else if (!strcmp(key, "print_delimiters")) { prefline("Print Prefixes", DP_YESNO(conf.print_prefixes), "\\pre,\\prefi
conf.print_commas = TRUEFALSE; xes");
} else if (!strcmp(key, "input_thousands_delimiter")) { prefline("Avoid Abbreviating Integers", DP_YESNO(conf.print_ints), "\\in
conf.in_thou_delimiter = value[0]; ts");
} else if (!strcmp(key, "input_decimal_delimiter")) { prefline("Rounding Indication",
conf.in_dec_delimiter = value[0]; conf.rounding_indication == SIMPLE_ROUNDING_INDICATION ? "yes (
} else if (!strcmp(key, "thousands_delimiter")) { simple) " : (conf.rounding_indication == SIG_FIG_ROUNDING_INDICATION ? "yes (sig
conf.thou_delimiter = value[0]; _fig)" : "no "),
} else if (!strcmp(key, "decimal_delimiter")) { "\\round");
conf.dec_delimiter = value[0]; prefline("Save Errors in History", DP_YESNO(conf.remember_errors), "\\re
} else if (!strcmp(key, "history_limit")) { ");
if (!strcmp(value, "no")) { sprintf(tmp, "'%c'", conf.thou_delimiter);
conf.history_limit = conf.history_limit_len = 0; prefline("Thousands Delimiter", tmp, "\\tsep");
} else { sprintf(tmp, "'%c'", conf.dec_delimiter);
conf.history_limit = 1; prefline("Decimal Delimiter", tmp, "\\dsep");
conf.history_limit_len = strtoul(value, NULL, 0); prefline("Precision Guard", DP_YESNO(conf.precision_guard), "\\cons");
prefline("History Limit", DP_YESNO(conf.history_limit), "\\hlimit");
if (conf.history_limit) {
sprintf(tmp, "%lu", conf.history_limit_len);
prefline("History Limited To", tmp, NULL);
}
prefline("Verbose", DP_YESNO(conf.verbose), "\\verbose");
prefline("Display Delimiters", DP_YESNO(conf.print_commas), "\\delim");
prefline("Modulo Operator", (conf.c_style_mod ? "C-style " : "not C-s
tyle"), "\\cmod");
}
}
void
display_status(const char *format,
...)
{
if (standard_output) {
va_list args;
printf("%s", colors[uiselect[STATUS]]);
va_start(args, format);
vprintf(format, args);
va_end(args);
printf("%s\n", colors[uiselect[UNCOLOR]]);
}
}
void
display_output_format(int format)
{
if (standard_output) {
switch (format) {
case HEXADECIMAL_FORMAT:
display_status("Hexadecimal Formatted Output");
break;
case OCTAL_FORMAT:
display_status("Octal Formatted Output");
break;
case DECIMAL_FORMAT:
display_status("Decimal Formatted Output");
break;
case BINARY_FORMAT:
display_status("Binary Formatted Output");
break;
}
}
}
void
display_val(const char *name)
{
if (standard_output) {
answer_t val;
char approx = 0;
char *err;
printf("display_val\n");
display_and_clear_errstring();
printf("%s%s%s", colors[uiselect[VAR_NAME]], name, colors[uiselect[UNCOL
OR]]);
val = getvar_full(name);
if (val.exp) {
printf(" %s=%s %s\n", colors[uiselect[EXACT_ANSWER]], colors[uiselec
t[UNCOLOR]], val.exp);
} else {
char *p = print_this_result(val.val, 0, &approx, &err);
printf("display_val\n");
show_answer(err, approx, p);
}
if (val.desc) {
printf(":: %s%s%s\n", colors[uiselect[VAR_DESC]], val.desc, colors[u
iselect[UNCOLOR]]);
}
}
}
void
display_var(variable_t *v,
unsigned count,
unsigned digits)
{
printf("%*u. %s%s%s", digits, count,
colors[uiselect[VAR_NAME]], v->key, colors[uiselect[UNCOLOR]]);
if (v->exp) {
printf(" %s=%s %s\n",
colors[uiselect[EXACT_ANSWER]], colors[uiselect[UNCOLOR]],
v->expression);
} else {
char approx = 0;
char *err;
char *p = print_this_result(v->value, 0, &approx, &err);
printf("display_var\n");
show_answer(err, approx, p);
}
if (v->description) {
printf("%*s %s%s%s\n", digits + 4, "::",
colors[uiselect[VAR_DESC]], v->description, colors[uiselect[UNCOL
OR]]);
}
}
void
display_expvar_explanation(const char *str,
const char *exp,
List subvars,
const char *desc)
{
printf("%s%s%s is the expression: '%s'\n", colors[uiselect[VAR_NAME]], str,
colors[uiselect[UNCOLOR]], exp);
if (desc) {
printf("Description: %s%s%s\n", colors[uiselect[VAR_DESC]], desc, colors
[uiselect[UNCOLOR]]);
}
if (listLen(subvars) > 0) {
unsigned maxnamelen = 0;
{
/* First, find the longest variable name... */
ListIterator si = getListIterator(subvars);
char *cursor = (char *)nextListElement(si);
if (cursor != NULL) {
maxnamelen = strlen(cursor);
while ((cursor = (char *)nextListElement(si)) != NULL) {
unsigned len = strlen(cursor);
if (maxnamelen < len) { maxnamelen = len; }
}
} }
} else if (!strcmp(key, "output_format")) { freeListIterator(si);
if (!strcmp(value, "decimal")) { }
conf.output_format = DECIMAL_FORMAT; printf("%s%s%s uses the following variables:\n",
} else if (!strcmp(value, "octal")) { colors[uiselect[VAR_NAME]], str, colors[uiselect[UNCOLOR]]);
conf.output_format = OCTAL_FORMAT; while (listLen(subvars) > 0) {
} else if (!strcmp(value, "binary")) { char *curstr = (char *)getHeadOfList(subvars);
conf.output_format = BINARY_FORMAT; char *value = evalvar_noparse(curstr);
} else if (!strcmp(value, "hex") || !strcmp(value, "hexadecimal")) {
conf.output_format = HEXADECIMAL_FORMAT; printf("\t%s%*s%s\t(currently: %s)\n", colors[uiselect[SUBVAR_NAME]]
} else { , -maxnamelen, curstr, colors[uiselect[UNCOLOR]],
fprintf(stderr, "Unrecognized output_format in wcalcrc.\n\tSuppo value ? value : "undefined");
rted formats are decimal, octal, binary, hex.\n"); if (curstr) {
free(curstr);
} }
} else if (!strcmp(key, "rounding_indication")) { if (value) {
if (!strcmp(value, "no") || !strcmp(value, "none")) { free(value);
conf.rounding_indication = NO_ROUNDING_INDICATION;
} else if (!strcmp(value, "simple")) {
conf.rounding_indication = SIMPLE_ROUNDING_INDICATION;
} else if (!strcmp(value, "sig_fig")) {
conf.rounding_indication = SIG_FIG_ROUNDING_INDICATION;
} else {
fprintf(stderr, "Unrecognized rounding_indication in wcalcrc.\n\
tSupported indication types are none, simple, sig_fig.\n");
} }
} else if (!strcmp(key, "engineering")) { }
if (!strcmp(value, "auto") || !strcmp(value, "automatic") || !strcmp }
(value, "yes") || !strcmp(value, "true") || !strcmp(value, "1")) { }
conf.engineering = automatic;
} else if (!strcmp(value, "always")) { void
conf.engineering = always; display_valvar_explanation(const char *str,
Number *val,
const char *desc)
{
printf("%s%s%s is a variable with the value: %s\n",
colors[uiselect[VAR_NAME]], str, colors[uiselect[UNCOLOR]],
print_this_result(*val, 0, NULL, NULL));
if (desc) {
printf("Description: %s%s%s\n", colors[uiselect[VAR_DESC]], desc, colors
[uiselect[UNCOLOR]]);
}
}
void
display_explanation(const char *exp,
...)
{
if (standard_output) {
va_list args;
printf("%s", colors[uiselect[EXPLANATION]]);
va_start(args, exp);
vprintf(exp, args);
va_end(args);
printf("%s\n", colors[uiselect[UNCOLOR]]);
}
}
void
display_stateline(const char *buf)
{
printf("-> %s\n", buf);
}
void
display_consts(void)
{
size_t linelen = 0;
for (size_t i = 0; consts[i].explanation; i++) {
const char *const *const names = consts[i].names;
for (size_t j = 0; names[j]; j++) {
if (linelen + strlen(names[j]) + 2 > 70) {
printf(",\n");
linelen = 0;
}
if (linelen == 0) {
printf("%s", names[j]);
linelen = strlen(names[j]);
} else { } else {
conf.engineering = never; printf(", %s", names[j]);
linelen += strlen(names[j]) + 2;
} }
} else if (!strcmp(key, "c_style_mod")) {
conf.c_style_mod = TRUEFALSE;
} else {
fprintf(stderr, "Unrecognized key in wcalcrc: %s\n", key);
} }
memset(key, 0, sizeof(key));
memset(value, 0, sizeof(value));
} }
return 1; printf("\n");
} /*}}} */ }
/* vim:set expandtab: */ /* vim:set expandtab: */
 End of changes. 86 change blocks. 
261 lines changed or deleted 856 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS