Skip to content
Snippets Groups Projects
Commit 140b1a71 authored by Andre Maroneze's avatar Andre Maroneze Committed by Dario Pinto
Browse files

adding Accel

parent 70246958
No related branches found
No related tags found
1 merge request!6Feature/new cgc
Showing
with 5539 additions and 0 deletions
This diff is collapsed.
[metrics] Eva coverage statistics
=======================
Syntactically reachable functions = 51 (out of 68)
Semantically reached functions = 19
Coverage estimation = 37.3%
Unreached functions (32) =
</home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c>: cgc_eval_function;
cgc_infixtorpn; cgc_is_arg_arithmetic;
</home/andr/git/oscs-pub3/cgc-challenges/Accel/accelfunc.c>:
cgc_handle_op_abs; cgc_handle_op_add; cgc_handle_op_avg;
cgc_handle_op_cos; cgc_handle_op_count; cgc_handle_op_ln;
cgc_handle_op_log10; cgc_handle_op_max; cgc_handle_op_median;
cgc_handle_op_min; cgc_handle_op_power; cgc_handle_op_product;
cgc_handle_op_quotient; cgc_handle_op_sin; cgc_handle_op_sqrt;
cgc_handle_op_stddev; cgc_handle_op_subtract; cgc_handle_op_sum;
</home/andr/git/oscs-pub3/cgc-challenges/Accel/accelio.c>:
cgc_sanitize_formula;
</home/andr/git/oscs-pub3/cgc-challenges/Accel/atof.c>: cgc_atof;
</home/andr/git/oscs-pub3/cgc-challenges/Accel/queue.c>: cgc_clear_queue;
cgc_dequeue_copy; cgc_enqueue; cgc_enqueue_copy;
</home/andr/git/oscs-pub3/cgc-challenges/Accel/stack.c>: cgc_clear_stack;
cgc_peek_top; cgc_pop_copy; cgc_push; cgc_push_copy;
[metrics] References to non-analyzed functions
------------------------------------
Function cgc_eval_formula calls cgc_push_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:395)
Function cgc_eval_formula calls cgc_infixtorpn (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:396)
Function cgc_eval_formula calls cgc_dequeue_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:405)
Function cgc_eval_formula calls cgc_push (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:409)
Function cgc_eval_formula calls cgc_eval_function (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:413)
Function cgc_eval_formula calls cgc_push_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:417)
Function cgc_eval_formula calls cgc_push_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:435)
Function cgc_eval_formula calls cgc_push_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:437)
Function cgc_eval_formula calls cgc_push_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:444)
Function cgc_eval_formula calls cgc_pop_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:455)
Function cgc_eval_formula calls cgc_atof (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:459)
Function cgc_eval_formula calls cgc_clear_queue (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:468)
Function cgc_eval_formula calls cgc_clear_queue (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:469)
Function cgc_eval_formula calls cgc_clear_stack (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:470)
Function cgc_eval_formula calls cgc_pop_copy (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:472)
Initializer of operators references cgc_handle_op_avg (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:60)
Initializer of operators references cgc_handle_op_count (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:61)
Initializer of operators references cgc_handle_op_max (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:62)
Initializer of operators references cgc_handle_op_median (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:63)
Initializer of operators references cgc_handle_op_min (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:64)
Initializer of operators references cgc_handle_op_stddev (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:65)
Initializer of operators references cgc_handle_op_abs (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:66)
Initializer of operators references cgc_handle_op_add (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:67)
Initializer of operators references cgc_handle_op_cos (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:68)
Initializer of operators references cgc_handle_op_ln (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:69)
Initializer of operators references cgc_handle_op_log10 (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:70)
Initializer of operators references cgc_handle_op_power (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:71)
Initializer of operators references cgc_handle_op_product (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:72)
Initializer of operators references cgc_handle_op_quotient (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:73)
Initializer of operators references cgc_handle_op_sin (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:74)
Initializer of operators references cgc_handle_op_sqrt (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:75)
Initializer of operators references cgc_handle_op_subtract (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:76)
Initializer of operators references cgc_handle_op_sum (at /home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:77)
[metrics] Statements analyzed by Eva
--------------------------
943 stmts in analyzed functions, 817 stmts analyzed (86.6%)
cgc_clear_cell: 12 stmts out of 12 (100.0%)
cgc_get_cell: 22 stmts out of 22 (100.0%)
cgc_get_op: 36 stmts out of 36 (100.0%)
cgc_get_rowcol: 71 stmts out of 71 (100.0%)
cgc_init_sheet: 33 stmts out of 33 (100.0%)
cgc_parsearg: 101 stmts out of 101 (100.0%)
cgc_print_assigned_cells: 25 stmts out of 25 (100.0%)
cgc_print_table: 2 stmts out of 2 (100.0%)
cgc_readline: 28 stmts out of 28 (100.0%)
cgc_receive: 9 stmts out of 9 (100.0%)
cgc_show_cell: 33 stmts out of 33 (100.0%)
cgc_valid_cell_id: 72 stmts out of 72 (100.0%)
cgc_parse_line: 140 stmts out of 146 (95.9%)
cgc_itoa: 56 stmts out of 59 (94.9%)
cgc_strtrim: 43 stmts out of 47 (91.5%)
cgc_set_cell: 39 stmts out of 45 (86.7%)
main: 28 stmts out of 33 (84.8%)
cgc_ftoa: 67 stmts out of 85 (78.8%)
cgc_eval_formula: 0 stmts out of 84 (0.0%)
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:157:[eva:garbled-mix] warning: The specification of function strcpy has generated a garbled mix for assigns clause assigns clause *
(dest + (0 .. strlen{Old}(src))).
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:157:[eva:garbled-mix] warning: The specification of function strcpy has generated a garbled mix for assigns clause assigns clause \result.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accelio.c:77:[eva:garbled-mix] warning: The specification of function toupper has generated a garbled mix for assigns clause assigns clause \result.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accelio.c:82:[eva:garbled-mix] warning: The specification of function toupper has generated a garbled mix for assigns clause assigns clause \result.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:217:[eva:garbled-mix] warning: The specification of function strcpy has generated a garbled mix for assigns clause assigns clause *
(dest + (0 .. strlen{Old}(src))).
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:220:[eva:garbled-mix] warning: The specification of function toupper has generated a garbled mix for assigns clause assigns clause \result.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:205:[eva:garbled-mix] warning: The specification of function printf_va_1 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:135:[eva:garbled-mix] warning: The specification of function printf_va_2 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:137:[eva:garbled-mix] warning: The specification of function printf_va_3 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:179:[eva:garbled-mix] warning: The specification of function printf_va_6 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:182:[eva:garbled-mix] warning: The specification of function printf_va_7 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:185:[eva:garbled-mix] warning: The specification of function printf_va_8 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:188:[eva:garbled-mix] warning: The specification of function printf_va_9 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:191:[eva:garbled-mix] warning: The specification of function printf_va_10 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:170:[eva:garbled-mix] warning: The specification of function printf_va_4 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:173:[eva:garbled-mix] warning: The specification of function printf_va_5 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:195:[eva:garbled-mix] warning: The specification of function printf_va_11 has generated a garbled mix for assigns clause assigns clause __fc_stdout->__fc_FILE_data.
[eva:garbled-mix] warning: Garbled mix generated during analysis:
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:153}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:114}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:116}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:120}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:122}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:124}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:132}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:179}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:180}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:146}) }}
{{ garbled mix of &{__malloc_w_cgc_set_cell_l153}
(origin: Misaligned
{/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:147}) }}
This diff is collapsed.
[metrics] Defined functions (63)
======================
cgc__terminate (0 call); cgc_allocate (0 call); cgc_atof (32 calls);
cgc_check_timeout (1 call); cgc_clear_cell (1 call);
cgc_clear_queue (3 calls); cgc_clear_stack (21 calls);
cgc_copy_cgc_fd_set (2 calls); cgc_copy_os_fd_set (2 calls);
cgc_deallocate (0 call); cgc_dequeue_copy (1 call); cgc_enqueue (6 calls);
cgc_enqueue_copy (2 calls); cgc_eval_formula (2 calls);
cgc_eval_function (2 calls); cgc_fdwait (0 call); cgc_ftoa (3 calls);
cgc_get_cell (4 calls); cgc_get_op (3 calls); cgc_get_rowcol (1 call);
cgc_handle_op_abs (address taken) (0 call);
cgc_handle_op_add (address taken) (0 call);
cgc_handle_op_avg (address taken) (0 call);
cgc_handle_op_cos (address taken) (0 call);
cgc_handle_op_count (address taken) (0 call);
cgc_handle_op_ln (address taken) (0 call);
cgc_handle_op_log10 (address taken) (0 call);
cgc_handle_op_max (address taken) (0 call);
cgc_handle_op_median (address taken) (0 call);
cgc_handle_op_min (address taken) (0 call);
cgc_handle_op_power (address taken) (0 call);
cgc_handle_op_product (address taken) (0 call);
cgc_handle_op_quotient (address taken) (0 call);
cgc_handle_op_sin (address taken) (0 call);
cgc_handle_op_sqrt (address taken) (0 call);
cgc_handle_op_stddev (address taken) (0 call);
cgc_handle_op_subtract (address taken) (0 call);
cgc_handle_op_sum (address taken) (0 call); cgc_infixtorpn (1 call);
cgc_init_sheet (1 call); cgc_is_arg_arithmetic (1 call); cgc_itoa (4 calls);
cgc_parse_line (1 call); cgc_parsearg (5 calls); cgc_peek_front (0 call);
cgc_peek_top (13 calls); cgc_pop_copy (44 calls);
cgc_print_assigned_cells (1 call); cgc_print_table (1 call);
cgc_push (4 calls); cgc_push_copy (10 calls); cgc_random (0 call);
cgc_readline (1 call); cgc_receive (2 calls); cgc_sanitize_formula (1 call);
cgc_set_cell (1 call); cgc_show_cell (1 call); cgc_strtrim (2 calls);
cgc_transmit (0 call); cgc_try_init_prng (1 call);
cgc_valid_cell_id (2 calls); main (0 call); receive_bytes_iPcz (0 call);
Undefined functions (5)
=======================
cgc_aes_get_bytes (1 call); cgc_init_prng (1 call);
cgc_initialize_flag_page (0 call); cgc_prng (0 call); seed_prng (0 call);
'Extern' global variables (0)
=============================
Potential entry points (9)
==========================
cgc__terminate; cgc_allocate; cgc_deallocate; cgc_fdwait; cgc_peek_front;
cgc_random; cgc_transmit; main; receive_bytes_iPcz;
Global metrics
==============
Sloc = 2311
Decision point = 430
Global variables = 5
If = 412
Loop = 54
Goto = 275
Assignment = 897
Exit point = 63
Function = 68
Function call = 426
Pointer dereferencing = 300
Cyclomatic complexity = 493
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accel.c:372:[kernel:typing:no-proto] warning: Calling function cgc_clear_stack that is declared without prototype.
Its formals will be inferred from actual arguments
/home/andr/git/oscs-pub3/cgc-challenges/Accel/accelfunc.c:53:[kernel:typing:no-proto] warning: Calling function cgc_clear_stack that is declared without prototype.
Its formals will be inferred from actual arguments
/home/andr/git/oscs-pub3/cgc-challenges/Accel/ftoa.c:50:[kernel:parser:decimal-float] warning: Floating-point constant 0.001 is not represented exactly. Will use 0x1.0624dd2f1a9fcp-10.
(warn-once: no further messages from category 'parser:decimal-float' will be emitted)
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:51:[kernel:typing:no-proto] warning: Calling function cgc_print_assigned_cells that is declared without prototype.
Its formals will be inferred from actual arguments
/home/andr/git/oscs-pub3/cgc-challenges/Accel/main.c:165:[kernel:typing:no-proto] warning: Calling function cgc_init_sheet that is declared without prototype.
Its formals will be inferred from actual arguments
# Makefile template for Frama-C/Eva case studies.
# For details and usage information, see the Frama-C User Manual.
### Prologue. Do not modify this block. #######################################
-include path.mk
FRAMAC ?= frama-c
include $(shell $(FRAMAC)-config -scripts)/prologue.mk
###############################################################################
# Edit below as needed. MACHDEP is mandatory. Suggested flags are optional.
MACHDEP = x86_32
## Preprocessing flags (for -cpp-extra-args)
CPPFLAGS += \
-DPATCHED \
-I../../lib \
## General flags
FCFLAGS += \
-add-symbolic-path=..:. \
-kernel-warn-key annot:missing-spec=abort \
-kernel-warn-key typing:implicit-function-declaration=abort \
-absolute-valid-range 0x4347C000-0x4347FFFF \
## Eva-specific flags
EVAFLAGS += \
-eva-warn-key builtins:missing-spec=abort \
-eva-use-spec cgc_eval_formula \
## GUI-only flags
FCGUIFLAGS += \
## Analysis targets (suffixed with .eva)
TARGETS = Accel.eva
### Each target <t>.eva needs a rule <t>.parse with source files as prerequisites
Accel.parse: \
../../lib/common.c \
../../lib/libcgc.c \
../accel.c \
../accelfunc.c \
../accelio.c \
../atof.c \
../ftoa.c \
../itoa.c \
../main.c \
../queue.c \
../stack.c \
### Epilogue. Do not modify this block. #######################################
include $(shell $(FRAMAC)-config -scripts)/epilogue.mk
###############################################################################
../../frama-c-cgc-path.mk
\ No newline at end of file
# contains recursive calls (cgc_eval_formula), stubbed unsoundly
# KPRCA-00013
### DARPA performer group
Kaprica Security (KPRCA)
## Description
Accel is a spreadsheet program that enables a user to store information in a table and calculate numerical formulas based on cell data. Similar to other familiar spreadsheet programs, Accel is meant to assist in organizing large amounts of data that have interdependencies. The functions provided will enable a user to complete most simple financial and arithmetic needs.
### Feature List
Command Line Operations:
-------------------------
**Literal Assignment
A0=1
A0=This is a string
**Formula Assignment
A1==SQRT(9)
A2==A1+97
A3==SIN(A2/A1)
Supported String Commands:
----------------------
CLEAR - Clears a cell
Accel:-$ CLEAR A3
REPR - Show the representation of a cell (helpful with formulas)
Accel:-$ REPR A2 --> =A1+97
SHOW - Show the value of a cell, either literal or computer
Accel:-S SHOW A2 --> 100
Accel:-S SHOW A0 --> This is a string
SHOW TABLE - Shows the contents of the entire table
Accel:-S SHOW TABLE
EXIT - Exits the program
Accel:-S EXIT
Supported Functions:
------------------------------------------------
AVG - Calculate the average of a list
COUNT - Count the number of items in a list
MAX - Return the largest value in a list
MEDIAN - Calculate the median of a list
MIN - Return the smallest value in a list
STDDEV - Calculate the standard deviation of a list
ABS - Return the absolute value of a number
COS - Calculate the cosine function of a number
LN - Caclualte the natural log of a number
LOG10 - Calculate a log base 10 of a number
POWER - Raise a number to a power
SIN - Calculate the sine function of a number
SQRT - Take the square root of a number
SUM - Return the summation of a list
Supported Operators
------------------------------------------------
+ - Addition
* - Multiplication
/ - Division
- - Subtraction
## Vulnerability
In infixtorpn (accel.c:453), an attacker supplied string is parsed into its components. Every time a function name is encountered, it is stored in an array and the index (func_idx) is incremented. The check to test if the array needs to be enlarged is off by one, because the index is incremented between the check and the store. This results in an overflow of the heap buffer, which can allow the attacker to control the heap metadata (size) of the next heap block. Attacker control is limited because the memory is initially set to zero and then incremented every time a comma occurs, but an attacker only needs to get the value to greater than 32 or so to cause a segmentation fault. The fault occurs because the free method will try to split the memory even though it has wrong metadata and overwrite pointers on the heap.
Also, there is an uninitialized variable vulnerability in handle_op_median, where sorted variable wasn't initialized before being cleared.
### Generic class of vulnerability
Generic type: Heap-buffer overflow
Uninitialized variable
### CWE classification
CWE-193: Off-by-one Error
CWE-457: Use of Uninitialized Variable
## Challenges
This cb is meant to be difficult to analyze. The program should provide complexities that are will take some work to reason about. The bug is similar, in that it's difficult to detect what is or isn't a heap overflow especially when dealing with an off-by-one error.
/*
* Copyright (c) 2014 Kaprica Security, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "common.h"
#include "libcgc.h"
#include "cgc_accel.h"
#include "cgc_accelio.h"
#include "cgc_accelfunc.h"
#include "cgc_stack.h"
#include "cgc_queue.h"
#include "cgc_convert.h"
#define LINE_SIZE 512
#define TMP_STR_SIZE 512
#define MAX_ROWS 26 * 27
#define MAX_COLS 100
typedef enum { UNUSED, BAD_CELL, STRING, QUOTED_STRING, DOUBLE, FUNCTION, CELL_ID, FORMULA } cell_type_e;
typedef struct cell {
unsigned int id;
cell_type_e cell_type;
char *str;
char *formula;
} cell_t;
static operator_t *cgc_get_op(char *name);
static cell_type_e cgc_parsearg(char *arg);
static int cgc_is_arg_arithmetic(char *arg);
static cell_t *cgc_get_cell(char *cell_id);
static queue_t *cgc_infixtorpn(char *infix, size_t size);
static double cgc_eval_formula(char *formula, int *is_bad_formula, stack_t **cir_ref, int id);
static cell_t *_g_sheet = NULL;
static cell_t **g_sheet = NULL;
static operator_t operators[] =
{
{ "AVG", cgc_handle_op_avg },
{ "COUNT", cgc_handle_op_count },
{ "MAX", cgc_handle_op_max },
{ "MEDIAN", cgc_handle_op_median },
{ "MIN", cgc_handle_op_min },
{ "STDDEV", cgc_handle_op_stddev },
{ "ABS", cgc_handle_op_abs },
{ "+", cgc_handle_op_add },
{ "COS", cgc_handle_op_cos },
{ "LN", cgc_handle_op_ln },
{ "LOG10", cgc_handle_op_log10 },
{ "POWER", cgc_handle_op_power },
{ "*", cgc_handle_op_product },
{ "/", cgc_handle_op_quotient },
{ "SIN", cgc_handle_op_sin },
{ "SQRT", cgc_handle_op_sqrt },
{ "-", cgc_handle_op_subtract },
{ "SUM", cgc_handle_op_sum },
{ NULL, NULL}
};
int cgc_init_sheet()
{
size_t i, j;
unsigned int id = 0;
// LARGEST SHEET SIZE: ZZ99 (676 rows by 100 columns)
_g_sheet = calloc(MAX_ROWS * MAX_COLS, sizeof(cell_t));
if (_g_sheet == NULL)
return -1;
g_sheet = malloc(MAX_ROWS * sizeof(cell_t*));
if (g_sheet == NULL)
return -1;
for (i = 0; i < MAX_ROWS; i++)
g_sheet[i] = &_g_sheet[i * MAX_COLS];
for (i = 0; i < MAX_ROWS; i++)
for (j = 0; j < MAX_COLS; j++)
g_sheet[i][j].id = id++;
return 0;
}
char *cgc_show_cell(char *cell_id, int is_repr, char* val_str, size_t size)
{
int is_bad_formula;
double val = 0.0;
cell_t *cell = cgc_get_cell(cell_id);
if (cell == NULL)
return NULL;
if (cell->cell_type == UNUSED)
return "";
if (cell->cell_type == BAD_CELL)
return "!VALUE";
if (is_repr)
return cell->str;
if (cell->formula != NULL) {
stack_t *cir_ref = NULL;
val = cgc_eval_formula(cell->formula, &is_bad_formula, &cir_ref, cell->id);
if (is_bad_formula) {
return "!FORMULA: CIRREF/STR/DIV0";
}
cgc_ftoa(val, val_str, size);
return val_str;
} else {
return cell->str;
}
}
int cgc_set_cell(char *cell_id, char *cell_str, size_t size)
{
if (cell_str == NULL || strlen(cell_str) == 0 || strlen(cell_str) >= size)
return -1;
cell_t *cell = cgc_get_cell(cell_id);
if (cell == NULL)
return -1;
if (cell->cell_type != UNUSED) {
free(cell->str);
cell->str = NULL;
cell->cell_type = UNUSED;
cell->formula = NULL;
}
cell->str = malloc(strlen(cell_str) + 1);
if(cell->str == NULL)
return -1;
strcpy(cell->str, cell_str);
if (strlen(cell_str) >= 2 && cell_str[0] == '=') {
cell->formula = &cell->str[1];
cell->cell_type = FORMULA;
} else {
// Non functions can only be a double or a string
cell->cell_type = cgc_parsearg(cell->str);
if (cell->cell_type != DOUBLE)
cell->cell_type = STRING;
}
return 0;
}
int cgc_clear_cell(char *cell_id)
{
cell_t *cell = cgc_get_cell(cell_id);
if (cell == NULL)
return -1;
if (cell->cell_type != UNUSED) {
free(cell->str);
cell->str = NULL;
cell->cell_type = UNUSED;
cell->formula = NULL;
}
return 0;
}
void cgc_print_assigned_cells()
{
char row_id[3];
char col_id[4];
size_t i, j;
unsigned int id;
cell_t *cell;
for (i = 0; i < MAX_ROWS; i++) {
for (j = 0; j < MAX_COLS; j++) {
cell = &g_sheet[i][j];
if (cell->cell_type != UNUSED) {
id = cell->id;
cgc_itoa(id % 100, col_id, sizeof(col_id));
row_id[2] = '\0';
row_id[1] = (id / (100 * 26)) == 0 ? '\0' : ((id / 100) % 26) + 'A';
row_id[0] = (id / (100 * 26)) == 0 ? ((id / 100) % 26) + 'A' : (((id / (100 * 26)) - 1) % 26) + 'A';
printf("%s%s=%s\n", row_id, col_id, cell->str);
}
}
}
}
static operator_t *cgc_get_op(char *name)
{
if(name == NULL)
return NULL;
char *upper_name = (char *) malloc(strlen(name) + 1);
strcpy(upper_name, name);
size_t i, len = strlen(upper_name);
for (i = 0; i < len; i++)
upper_name[i] = toupper(upper_name[i]);
operator_t *op = NULL;
for (op = &operators[0]; op->name != NULL; op++) {
if (strcmp(op->name, upper_name) == 0)
break;
}
free(upper_name);
if (op->name == NULL)
return NULL;
else
return op;
}
static cell_type_e cgc_parsearg(char *arg)
{
if (arg == NULL)
return BAD_CELL;
int is_double = 0, has_period = 0, has_negative = 0;
int is_hard_string = 0, is_soft_string = 0;
char *beg_arg = arg;
while (*arg != '\0') {
if (*arg >= '0' && *arg <= '9') {
is_double++;
} else if (*arg == '-') {
is_double++;
has_negative++;
} else if (*arg == '.') {
is_double++;
has_period++;
} else if (*arg == '"') {
is_hard_string++;
} else {
is_soft_string++;
}
arg++;
}
arg = beg_arg;
if (is_hard_string) {
if (is_hard_string == 2 && *(--arg) == '"')
return QUOTED_STRING;
else
return STRING;
} else if (is_soft_string) {
if (has_period > 1 || has_negative > 1)
return STRING;
if (cgc_valid_cell_id(arg) == 0)
return CELL_ID;
if (cgc_get_op(arg) != NULL)
return FUNCTION;
return STRING;
} else if (is_double) {
if (has_period > 1 || has_negative > 1)
return STRING;
if ((has_period && is_double == 1) || (has_period && has_negative && is_double == 2))
return STRING;
if (has_negative && is_double == 1)
return FUNCTION;
return DOUBLE;
} else {
return BAD_CELL;
}
}
static int cgc_is_arg_arithmetic(char *arg)
{
return ((memcmp(arg, "+", 2) == 0) ||
(memcmp(arg, "-", 2) == 0) ||
(memcmp(arg, "/", 2) == 0) ||
(memcmp(arg, "*", 2) == 0));
}
static cell_t *cgc_get_cell(char *cell_id)
{
char row_str[3];
char col_str[3];
int row_idx = 0, col_idx = 0;
int i, len;
if (cgc_get_rowcol(cell_id, row_str, col_str, '\0') == -1)
return NULL;
len = strlen(row_str);
for (i = 0; i < len; i++)
row_idx += ((row_str[i] - 64) * pow(26, len - i - 1));
--row_idx;
col_idx = strtol(col_str, NULL, 10);
return &g_sheet[row_idx][col_idx];
}
static int cgc_eval_function(operator_t *op, stack_t **values, char *val_str, size_t size)
{
if (op == NULL || val_str == NULL || size <= 2)
return -1;
double val = 0.0;
char *arg;
char *op_name = (char *) op->name;
size_t i, num_args = 0;
int is_bad_formula = 0;
operator_t *nested_op;
stack_t *args = NULL;
if (cgc_is_arg_arithmetic(op_name)) {
num_args = 2;
} else {
char *arg_count = cgc_pop_copy(values);
if (arg_count == NULL)
goto error;
num_args = strtol(arg_count, NULL, 10);
free(arg_count);
}
for (i = 0; i < num_args; i++) {
arg = cgc_pop_copy(values);
//printf("arg[%d]==%s\n", i, arg);
if (cgc_parsearg(arg) == FUNCTION) {
nested_op = cgc_get_op(arg);
free(arg);
if (cgc_eval_function(nested_op, values, val_str, size) == 0)
cgc_push_copy(&args, val_str, size);
else
goto error;
} else if (cgc_push(&args, arg) != 0) {
goto error;
}
}
val = op->function(&args, &is_bad_formula);
if (is_bad_formula)
goto error;
if (cgc_ftoa(val, val_str, size) == NULL)
goto error;
return 0;
error:
cgc_clear_stack(&args);
return -1;
}
/*@
assigns \result \from \nothing;
assigns *is_bad_formula \from \nothing;
ensures \initialized(is_bad_formula);
*/
static double cgc_eval_formula(char *formula, int *is_bad_formula, stack_t **cir_ref, int id)
{
char val_str[TMP_STR_SIZE];
char tmp_id_str[TMP_STR_SIZE];
size_t size = TMP_STR_SIZE;
double val = 0.0;
double result = 0.0;
*is_bad_formula = 0;
cell_type_e cell_type;
char *arg;
if(cgc_itoa(id, tmp_id_str, size) == NULL)
goto error;
cgc_push_copy(cir_ref, tmp_id_str, strlen(tmp_id_str) + 1);
queue_t *rpn = cgc_infixtorpn(formula, strlen(formula) + 1);
queue_t *args = NULL;
stack_t *values = NULL;
stack_t *tmp = NULL;
operator_t *op = NULL;
while (rpn != NULL) {
arg = cgc_dequeue_copy(&rpn);
cell_type = cgc_parsearg(arg);
switch(cell_type) {
case DOUBLE:
cgc_push(&values, arg);
break;
case FUNCTION:
op = cgc_get_op(arg);
if (cgc_eval_function(op, &values, val_str, size) == -1) {
goto error;
}
cgc_push_copy(&values, val_str, size);
break;
case CELL_ID:
tmp = *cir_ref;
cell_t *cell = cgc_get_cell(arg);
if(cell == NULL)
goto error;
while (tmp != NULL) {
if(cgc_itoa(cell->id, tmp_id_str, size) == NULL)
goto error;
if (memcmp(tmp->data, tmp_id_str, strlen(tmp->data) + 1) == 0)
goto error; //Circular reference
tmp = tmp->next;
}
if (cell->cell_type == UNUSED) {
cgc_push_copy(&values, "0", sizeof("0"));
} else if (cell->cell_type == DOUBLE) {
cgc_push_copy(&values, cell->str, strlen(cell->str) + 1);
} else if(cell->cell_type == FORMULA) {
val = cgc_eval_formula(cell->formula, is_bad_formula, cir_ref, cell->id);
if(*is_bad_formula)
goto error;
cgc_ftoa(val, val_str, size);
cgc_push_copy(&values, val_str, size);
} else {
goto error;
}
break;
default:
goto error;
}
}
char *result_str = cgc_pop_copy(&values);
if (values != NULL)
goto error;
result = cgc_atof(result_str, size, is_bad_formula);
if (*is_bad_formula)
goto error;
goto cleanup;
error:
*is_bad_formula = 1;
val = 0.0;
cgc_clear_queue(&rpn);
cgc_clear_queue(&args);
cgc_clear_stack(&values);
cleanup:
free(cgc_pop_copy(cir_ref));
return result;
}
static queue_t *cgc_infixtorpn(char *infix, size_t size)
{
/* Use RPN */
int is_mismatched = 0;
int func_size = 16;
int func_idx = -1;
char *formula = malloc(size);
int *func_args = malloc(func_size * sizeof(int));
char *delims = "():,+-*/";
char *arg, *iter;
char delim;
char arith_op[2] = {'\0', '\0'};
char *value;
cell_type_e arg_type;
stack_t *operators = NULL;
queue_t *output_q = NULL;
memcpy(formula, infix, size);
if (cgc_sanitize_formula(formula, size) != 0)
goto cleanup;
arg = iter = formula;
size_t i = 0;
char prev_char = 0;
while ( i++ < size) {
if (strchr(delims, *iter) == NULL && *iter != '\0') {
prev_char = *iter;
iter++;
continue;
} else if (strchr(delims, *iter) != NULL) {
if (*iter == '-') {
if(i <= 1 || (prev_char != ')' && (prev_char < '0' || prev_char > '9'))) {
prev_char = *iter;
iter++;
continue;
}
}
}
prev_char = *iter;
delim = *iter;
*iter = '\0';
arg_type = cgc_parsearg(arg);
switch (arg_type) {
case DOUBLE:
case CELL_ID:
cgc_enqueue_copy(&output_q, arg, strlen(arg) + 1);
break;
case FUNCTION:
#ifdef PATCHED
if(func_idx == func_size-1) {
#else
if(func_idx == func_size) {
#endif
func_size *= 2;
int *temp = realloc(func_args, func_size * sizeof(int));
if (temp == NULL)
goto error;
func_args = temp;
}
func_args[++func_idx] = 0;
cgc_push_copy(&operators, arg, strlen(arg) + 1);
break;
case BAD_CELL:
break;
default:
goto error;
}
is_mismatched = 0;
switch(delim) {
case '(':
cgc_push_copy(&operators, "(", strlen("(") + 1);
break;
case ')':
is_mismatched = 1;
while (operators != NULL) {
if (strcmp(cgc_peek_top(operators), "(") == 0) {
value = cgc_pop_copy(&operators);
free(value);
is_mismatched = 0;
break;
} else {
cgc_enqueue(&output_q, cgc_pop_copy(&operators));
}
}
// handle parens without any operator
if (cgc_peek_top(operators) == NULL || func_idx < 0)
break;
char num_args_str[16];
if(strchr(delims, cgc_peek_top(operators)[0]) != NULL) {
break;
} else if (cgc_parsearg(cgc_peek_top(operators)) == FUNCTION) {
cgc_enqueue_copy(&output_q, cgc_itoa(func_args[func_idx--] + 1, num_args_str,
sizeof(num_args_str)), sizeof(num_args_str));
cgc_enqueue(&output_q, cgc_pop_copy(&operators));
}
break;
case ',':
is_mismatched = 1;
while (operators != NULL) {
if (strcmp(cgc_peek_top(operators), "(") == 0) {
if (func_idx >= 0)
func_args[func_idx]++;
is_mismatched = 0;
break;
} else {
cgc_enqueue(&output_q, cgc_pop_copy(&operators));
}
}
break;
case '+':
case '-':
//TODO - FIXME - precedence is broken
//TODO - FIXME - negative is still broken
// 4/5-5
arith_op[0] = delim;
while (operators != NULL) {
if (strcmp(cgc_peek_top(operators), "-") == 0 || strcmp(cgc_peek_top(operators), "+") == 0 ||
strcmp(cgc_peek_top(operators), "+") == 0 || strcmp(cgc_peek_top(operators), "/") == 0)
cgc_enqueue(&output_q, cgc_pop_copy(&operators));
else
break;
}
cgc_push_copy(&operators, arith_op, strlen(arith_op)+1);
break;
case '*':
case '/':
//TODO - FIXME - precedence is broken
arith_op[0] = delim;
while (operators != NULL) {
if (strcmp(cgc_peek_top(operators), "/") == 0 || strcmp(cgc_peek_top(operators), "*") == 0)
cgc_enqueue(&output_q, cgc_pop_copy(&operators));
else
break;
}
cgc_push_copy(&operators, arith_op, strlen(arith_op)+1);
break;
case '\0':
goto finish;
default:
goto error;
}
if (is_mismatched)
goto error;
arg = ++iter;
}
finish:
while (operators != NULL) {
if (strcmp(cgc_peek_top(operators), "(") == 0 || strcmp(cgc_peek_top(operators), ")") == 0)
goto error;
cgc_enqueue(&output_q, cgc_pop_copy(&operators));
}
goto cleanup;
error:
cgc_clear_queue(&output_q);
cgc_clear_stack(&operators);
cleanup:
free(formula);
free(func_args);
return output_q;
}
This diff is collapsed.
/*
* Copyright (c) 2014 Kaprica Security, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "common.h"
#include "cgc_accelio.h"
/* sides = 1, trim front
* sides = 2, trim back
* sides = 3, trim both
*/
int cgc_strtrim(char *str, size_t size, int sides)
{
int i, len;
len = strlen(str) + 1;
if (len > size)
return -1;
else if (len == 1)
return 0;
if (sides == TRIM_FRONT || sides == TRIM_ALL) {
char *tmp = str;
for (i = 0; i < len; i++, tmp++) {
if (strchr(WHITESPACE, *tmp) == NULL) {
memcpy(str, tmp, len - i);
break;
}
}
}
if ((sides == TRIM_BACK || sides == TRIM_ALL) && (len - 1 != 0)) {
for (i = len - 2; i >= 0 ; i--) {
if (strchr(WHITESPACE, str[i]) == NULL) {
str[i + 1] = '\0';
break;
} else if (i == 0) {
str[i] = '\0';
break;
}
}
}
return 0;
}
//row and col must be buffers of at least len 4
int cgc_valid_cell_id(char *input)
{
if (strlen(input) < 2)
return -1;
size_t i = 0, is_num = 0;
char row[3];
char col[3];
char delim = '\0';
char c = toupper(input[0]);
if (c < 'A' || c > 'Z')
return -1;
row[0] = c;
c = toupper(input[1]);
if (!(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9' ))
return -1;
if (c >= '0' && c <= '9') {
col[is_num++] = c;
row[1] = '\0';
} else {
row[1] = c;
row[2] = '\0';
}
for (i = 2; i < 5; i++) {
if (input[i] == delim && is_num) {
col[is_num] = '\0';
return 0;
}
if (input[i] >= '0' && input[i] <= '9' && is_num < 2) {
col[is_num++] = input[i];
}
else {
return -1;
}
}
return -1;
}
//row and col must be buffers of at least len 4
int cgc_get_rowcol(char *input, char *row, char *col, char delim)
{
if (strlen(input) < 2)
return -1;
size_t i = 0, is_num = 0;
char c = toupper(input[0]);
if (c < 'A' || c > 'Z')
return -1;
row[0] = c;
c = toupper(input[1]);
if (!(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9' ))
return -1;
if (c >= '0' && c <= '9') {
col[is_num++] = c;
row[1] = '\0';
} else {
row[1] = c;
row[2] = '\0';
}
for (i = 2; i < 5; i++) {
if (input[i] == delim && is_num) {
col[is_num] = '\0';
return 0;
}
if (input[i] >= '0' && input[i] <= '9' && is_num < 2) {
col[is_num++] = input[i];
}
else {
return -1;
}
}
return -1;
}
int cgc_sanitize_formula(char *formula, size_t size)
{
size_t i, j, len;
len = strlen(formula);
if (len > size)
return -1;
char *sanitized = calloc(1, size);
if (sanitized == NULL)
return -1;
for (i = 0, j=0; i < len; i++) {
if (strchr(WHITESPACE, formula[i]) == NULL)
sanitized[j++] = formula[i];
}
memcpy(formula, sanitized, size);
free(sanitized);
return 0;
}
/*
* Copyright (c) 2014 Kaprica Security, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "cgc_convert.h"
double cgc_atof(char *str, size_t size, int *bad_conversion)
{
if (str == NULL || strlen(str) >= size || strlen(str) == 0)
goto error;
double val = 0.0, exp = 0.0, dec_multiplier = 1.0;
int has_period = 0, has_exp = 0;
int negative = 1;
int num_dec = 0;
if (*str == '-') {
str++;
if (*str == '\0')
goto error;
negative = -1;
}
while (*str != '\0') {
if (*str >= '0' && *str <= '9') {
if (has_exp) {
exp = (exp * 10) + (*str - '0');
} else if (!has_period) {
val = (val * 10) + (*str - '0');
} else {
dec_multiplier *= 10;
num_dec++;
val += ((*str - '0') / dec_multiplier);
}
} else if (*str == '.') {
has_period++;
} else if (tolower(*str) == 'e') {
has_exp++;
} else {
goto error;
}
if (has_period > 1 || has_exp > 1)
goto error;
if (num_dec >= MAX_DEC)
goto done;
str++;
}
goto done;
error:
*bad_conversion = 1;
return 0.0;
done:
if (has_exp)
val *= pow(10, exp);
return val * negative;
}
#ifndef ACCEL_H_
#define ACCEL_H_
int cgc_init_sheet();
char *cgc_show_cell(char *cell_id, int is_repr, char* val_str, size_t size);
int cgc_set_cell(char *cell_id, char *cell_str, size_t size);
int cgc_clear_cell(char *cell_id);
void cgc_print_assigned_cells();
#endif /* ACCELL_H */
#include "cgc_stack.h"
#ifndef ACCELFUNC_H_
#define ACCELFUNC_H_
typedef double (*handle_op_t)(stack_t **args, int *is_bad_formula);
typedef struct {
const char *name;
handle_op_t function;
} operator_t;
double cgc_handle_op_avg(stack_t **args, int *is_bad_formula);
double cgc_handle_op_count(stack_t **args, int *is_bad_formula);
double cgc_handle_op_max(stack_t **args, int *is_bad_formula);
double cgc_handle_op_median(stack_t **args, int *is_bad_formula);
double cgc_handle_op_min(stack_t **args, int *is_bad_formula);
double cgc_handle_op_stddev(stack_t **args, int *is_bad_formula);
double cgc_handle_op_abs(stack_t **args, int *is_bad_formula);
double cgc_handle_op_add(stack_t **args, int *is_bad_formula);
double cgc_handle_op_cos(stack_t **args, int *is_bad_formula);
double cgc_handle_op_ln(stack_t **args, int *is_bad_formula);
double cgc_handle_op_log10(stack_t **args, int *is_bad_formula);
double cgc_handle_op_power(stack_t **args, int *is_bad_formula);
double cgc_handle_op_product(stack_t **args, int *is_bad_formula);
double cgc_handle_op_quotient(stack_t **args, int *is_bad_formula);
double cgc_handle_op_sin(stack_t **args, int *is_bad_formula);
double cgc_handle_op_sqrt(stack_t **args, int *is_bad_formula);
double cgc_handle_op_subtract(stack_t **args, int *is_bad_formula);
double cgc_handle_op_sum(stack_t **args, int *is_bad_formula);
#endif /* ACCELFUNC_H */
#ifndef ACCELIO_H_
#define ACCELIO_H_
#define TRIM_FRONT 1
#define TRIM_BACK 2
#define TRIM_ALL 3
#define WHITESPACE "\r\n\t "
#include "common.h"
int cgc_strtrim(char *str, size_t size, int sides);
int cgc_valid_cell_id(char *input);
int cgc_get_rowcol(char *input, char *row, char *col, char delim);
int cgc_sanitize_formula(char *formula, size_t size);
#endif /* ACCELIO_H */
#ifndef CONVERT_H_
#define CONVERT_H_
#define MAX_DEC 5
#include "common.h"
extern char *cgc_itoa(int value, char *str, size_t size);
extern char *cgc_ftoa(double value, char *str, size_t size);
extern double cgc_atof(char *str, size_t size, int *bad_conversion);
#endif /* CONVERT_H */
#ifndef QUEUE_H_
#define QUEUE_H_
#include "common.h"
typedef struct queue queue_t;
struct queue {
char *data;
queue_t *next;
};
char *cgc_peek_front(queue_t *queue);
int cgc_enqueue(queue_t **queue, char *data);
int cgc_enqueue_copy(queue_t **queue, char *data, size_t size);
char *cgc_dequeue_copy(queue_t **queue);
void cgc_clear_queue(queue_t **queue);
#endif /* QUEUE_H */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment