Bring in basecode from development repo.
This commit is contained in:
commit
595cae98a1
29
.gitlab-ci.yml
Normal file
29
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
image: hwrunner:latest
|
||||||
|
variables:
|
||||||
|
GIT_SSL_NO_VERIFY: "true"
|
||||||
|
EXEC: argo
|
||||||
|
HW_DIR: hw1
|
||||||
|
CPU_LIMIT: 60
|
||||||
|
FILE_LIMIT: 1000000
|
||||||
|
before_script:
|
||||||
|
- make clean all -C ${HW_DIR}
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- run
|
||||||
|
- test
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- echo "Build done"
|
||||||
|
run:
|
||||||
|
stage: run
|
||||||
|
script:
|
||||||
|
- ulimit -t ${CPU_LIMIT}
|
||||||
|
- ulimit -f ${FILE_LIMIT}
|
||||||
|
- cd ${HW_DIR} && bin/${EXEC} -h
|
||||||
|
test:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- ulimit -t ${CPU_LIMIT}
|
||||||
|
- ulimit -f ${FILE_LIMIT}
|
||||||
|
- cd ${HW_DIR} && bin/${EXEC}_tests -S --verbose=0 --timeout 30
|
6
hw1/.gitignore
vendored
Normal file
6
hw1/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
bin/
|
||||||
|
build/
|
||||||
|
test_output/
|
||||||
|
*~
|
||||||
|
*.out
|
||||||
|
*.bak
|
61
hw1/Makefile
Normal file
61
hw1/Makefile
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
CC := gcc
|
||||||
|
SRCD := src
|
||||||
|
TSTD := tests
|
||||||
|
BLDD := build
|
||||||
|
BIND := bin
|
||||||
|
INCD := include
|
||||||
|
LIBD := lib
|
||||||
|
|
||||||
|
EXEC := argo
|
||||||
|
TEST_EXEC := $(EXEC)_tests
|
||||||
|
|
||||||
|
MAIN := $(BLDD)/main.o
|
||||||
|
LIB := $(LIBD)/$(EXEC).a
|
||||||
|
|
||||||
|
ALL_SRCF := $(shell find $(SRCD) -type f -name *.c)
|
||||||
|
ALL_OBJF := $(patsubst $(SRCD)/%,$(BLDD)/%,$(ALL_SRCF:.c=.o))
|
||||||
|
ALL_FUNCF := $(filter-out $(MAIN) $(AUX), $(ALL_OBJF))
|
||||||
|
|
||||||
|
TEST_ALL_SRCF := $(shell find $(TSTD) -type f -name *.c)
|
||||||
|
TEST_SRCF := $(filter-out $(TEST_REF_SRCF), $(TEST_ALL_SRCF))
|
||||||
|
|
||||||
|
INC := -I $(INCD)
|
||||||
|
|
||||||
|
CFLAGS := -Wall -Werror -Wno-unused-variable -Wno-unused-function -MMD -fcommon
|
||||||
|
COLORF := -DCOLOR
|
||||||
|
DFLAGS := -g -DDEBUG -DCOLOR
|
||||||
|
PRINT_STAMENTS := -DERROR -DSUCCESS -DWARN -DINFO
|
||||||
|
|
||||||
|
STD := -std=gnu11
|
||||||
|
TEST_LIB := -lcriterion
|
||||||
|
LIBS := $(LIB)
|
||||||
|
|
||||||
|
CFLAGS += $(STD)
|
||||||
|
|
||||||
|
.PHONY: clean all setup debug
|
||||||
|
|
||||||
|
all: setup $(BIND)/$(EXEC) $(BIND)/$(TEST_EXEC)
|
||||||
|
|
||||||
|
debug: CFLAGS += $(DFLAGS) $(PRINT_STAMENTS) $(COLORF)
|
||||||
|
debug: all
|
||||||
|
|
||||||
|
setup: $(BIND) $(BLDD)
|
||||||
|
$(BIND):
|
||||||
|
mkdir -p $(BIND)
|
||||||
|
$(BLDD):
|
||||||
|
mkdir -p $(BLDD)
|
||||||
|
|
||||||
|
$(BIND)/$(EXEC): $(ALL_OBJF)
|
||||||
|
$(CC) $^ -o $@ $(LIBS)
|
||||||
|
|
||||||
|
$(BIND)/$(TEST_EXEC): $(ALL_FUNCF) $(TEST_SRCF)
|
||||||
|
$(CC) $(CFLAGS) $(INC) $(ALL_FUNCF) $(TEST_SRCF) $(TEST_LIB) $(LIBS) -o $@
|
||||||
|
|
||||||
|
$(BLDD)/%.o: $(SRCD)/%.c
|
||||||
|
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BLDD) $(BIND)
|
||||||
|
|
||||||
|
.PRECIOUS: $(BLDD)/*.d
|
||||||
|
-include $(BLDD)/*.d
|
50
hw1/hw1.sublime-project
Normal file
50
hw1/hw1.sublime-project
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"folders":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path":".",
|
||||||
|
"name":"Project Base"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "src",
|
||||||
|
"name": "C Source",
|
||||||
|
"follow_symlinks": false,
|
||||||
|
"file_include_patterns":["*.c"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "include",
|
||||||
|
"name": "C Headers",
|
||||||
|
"follow_symlinks": false,
|
||||||
|
"file_include_patterns":["*.h"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "tests",
|
||||||
|
"name": "Tests",
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"path": "rsrc",
|
||||||
|
"name": "Resource Files",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings":
|
||||||
|
{
|
||||||
|
},
|
||||||
|
"build_systems":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Release (full build)",
|
||||||
|
"working_dir":"$project_path",
|
||||||
|
"shell_cmd": "make clean all",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug (full build)",
|
||||||
|
"working_dir":"$project_path",
|
||||||
|
"shell_cmd": "make clean debug",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Test",
|
||||||
|
"working_dir":"$project_path",
|
||||||
|
"shell_cmd": "bin/${project_base_name}_tests}",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
242
hw1/include/argo.h
Normal file
242
hw1/include/argo.h
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* DO NOT MODIFY THE CONTENTS OF THIS FILE.
|
||||||
|
* IT WILL BE REPLACED DURING GRADING
|
||||||
|
*/
|
||||||
|
#ifndef ARGO_H
|
||||||
|
#define ARGO_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for "Argo" (aka JSON).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* USAGE macro to be called from main() to print a help message and exit
|
||||||
|
* with a specified exit status.
|
||||||
|
*/
|
||||||
|
#define USAGE(program_name, retcode) do { \
|
||||||
|
fprintf(stderr, "USAGE: %s %s\n", program_name, \
|
||||||
|
"[-h] [-c|-v] [-p INDENT]\n" \
|
||||||
|
" -h Help: displays this help menu.\n" \
|
||||||
|
" -v Validate: the program reads from standard input and checks whether\n" \
|
||||||
|
" it is syntactically correct JSON. If there is any error, then a message\n" \
|
||||||
|
" describing the error is printed to standard error before termination.\n" \
|
||||||
|
" No other output is produced.\n" \
|
||||||
|
" -c Canonicalize: once the input has been read and validated, it is\n" \
|
||||||
|
" re-emitted to standard output in 'canonical form'. Unless -p has been\n" \
|
||||||
|
" specified, the canonicalized output contains no whitespace (except within\n" \
|
||||||
|
" strings that contain whitespace characters).\n" \
|
||||||
|
" -p Pretty-print: This option is only permissible if -c has also been specified.\n" \
|
||||||
|
" In that case, newlines and spaces are used to format the canonical output\n" \
|
||||||
|
" in a more human-friendly way. For the precise requirements on where this\n" \
|
||||||
|
" whitespace must appear, see the assignment handout.\n" \
|
||||||
|
" The INDENT is an optional nonnegative integer argument that specifies the\n" \
|
||||||
|
" number of additional spaces to be output at the beginning of a line for each\n" \
|
||||||
|
" for each increase in indentation level. If no value is specified, then a\n" \
|
||||||
|
" default value of 4 is used.\n" \
|
||||||
|
); \
|
||||||
|
exit(retcode); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type used to represent an input character. It is intended to
|
||||||
|
* represent a Unicode code point (4 bytes max), so the C type
|
||||||
|
* "char" is not used. It is signed, so that we can represent
|
||||||
|
* the out-of-band value EOF (-1) as a value of this type.
|
||||||
|
*/
|
||||||
|
typedef int ARGO_CHAR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type codes for Argo values.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ARGO_NO_TYPE = 0,
|
||||||
|
ARGO_BASIC_TYPE = 1,
|
||||||
|
ARGO_NUMBER_TYPE = 2,
|
||||||
|
ARGO_STRING_TYPE = 3,
|
||||||
|
ARGO_OBJECT_TYPE = 4,
|
||||||
|
ARGO_ARRAY_TYPE = 5
|
||||||
|
} ARGO_VALUE_TYPE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic Argo values, represented by the (unquoted) tokens
|
||||||
|
* "true", "false", or "null" in Argo code.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ARGO_NULL, ARGO_TRUE, ARGO_FALSE
|
||||||
|
} ARGO_BASIC;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to hold a string value.
|
||||||
|
* The content field is maintained as an array of char, which is not null-terminated
|
||||||
|
* and which might contain '\0' characters. This data is interpreted as Unicode text,
|
||||||
|
* represented as an array of ARGO_CHAR values, each of which represents a single
|
||||||
|
* Unicode code point. The length field gives the length in bytes of the data.
|
||||||
|
* The capacity field records the actual size of the data area. This is included so
|
||||||
|
* that the size can be dynamically increased while the string is being read.
|
||||||
|
*/
|
||||||
|
typedef struct argo_string {
|
||||||
|
size_t capacity; // Current total size of space in the content.
|
||||||
|
size_t length; // Current length of the content.
|
||||||
|
ARGO_CHAR *content; // Unicode code points (not null terminated).
|
||||||
|
} ARGO_STRING;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to hold a number.
|
||||||
|
* The "text_value" field holds a printable/parseable representation of the number
|
||||||
|
* as Unicode text, conforming to the Argo standard.
|
||||||
|
* The "int_value" field holds the value of the number in integer format, if the
|
||||||
|
* number can be exactly represented as such.
|
||||||
|
* The "float_value" field holds the value of the number in floating-point format.
|
||||||
|
* The "valid_text" field is nonzero if the "text_valid" field contains a valid
|
||||||
|
* representation of the value.
|
||||||
|
* The "valid_int" field is nonzero if the "int_value" field contains a valid
|
||||||
|
* representation of the value.
|
||||||
|
* The "valid_float" field is nonzero if the "float_value" field contains a valid
|
||||||
|
* representation of the value.
|
||||||
|
*
|
||||||
|
* If multiple representations of the value of the number are present, they should
|
||||||
|
* agree with each other.
|
||||||
|
* It is up to an application to determine which representation is the appropriate
|
||||||
|
* one to use, based on the semantics of the data being represented.
|
||||||
|
*/
|
||||||
|
typedef struct argo_number {
|
||||||
|
struct argo_string string_value; // Value represented in textual format.
|
||||||
|
long int_value; // Value represented in integer format.
|
||||||
|
double float_value; // Value represented in floating-point format.
|
||||||
|
char valid_string; // Nonzero if string representation is valid.
|
||||||
|
char valid_int; // Nonzero if integer representation is valid.
|
||||||
|
char valid_float; // Nonzero if floating point representation is valid.
|
||||||
|
} ARGO_NUMBER;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An "object" has a list of members, each of which has a name and a value.
|
||||||
|
* To store the members, we use a circular, doubly linked list, with the next and
|
||||||
|
* previous pointers stored in the "next" and "prev" fields of the ARGO_VALUE structure
|
||||||
|
* and the member name stored in the "name" field of the ARGO_VALUE structure.
|
||||||
|
* The "member_list" field of the ARGO_OBJECT structure serves as the sentinel at
|
||||||
|
* the head of the list. This element does not represent one of the members;
|
||||||
|
* rather, its "next" field points to the first member and its "prev" field points
|
||||||
|
* to the last member. An empty list of members is represented by the situation in
|
||||||
|
* which both the "next" and "prev" fields point back to the sentinel object itself.
|
||||||
|
*
|
||||||
|
* Note that the collection of members of an object is supposed to be regarded as unordered,
|
||||||
|
* which would permit it to be represented using a hash map or similar data structure,
|
||||||
|
* which we are not doing here.
|
||||||
|
*/
|
||||||
|
typedef struct argo_object {
|
||||||
|
struct argo_value *member_list;
|
||||||
|
} ARGO_OBJECT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An "array" has an ordered sequence of elements, each of which is just a value.
|
||||||
|
* Here we represent the elements as a circular, doubly linked list, in the same
|
||||||
|
* way as for the members of an object. The "element_list" field in the ARGO_ARRAY
|
||||||
|
* structure serves as the sentinel at the head of the list.
|
||||||
|
*
|
||||||
|
* Note that elements of an array do not have any name, so the "name" field in each
|
||||||
|
* of the elements will be NULL. Arrays could be represented as actual arrays,
|
||||||
|
* but we are not doing that here.
|
||||||
|
*/
|
||||||
|
typedef struct argo_array {
|
||||||
|
struct argo_value *element_list;
|
||||||
|
} ARGO_ARRAY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ARGO_VALUE structure is used to represent all kinds of Argo values.
|
||||||
|
* The "type" field tells what type of value it represents.
|
||||||
|
* It has "next" and "prev" fields so that it can be linked into "members"
|
||||||
|
* or "elements" lists. It has a "name" field which will hold the name in case
|
||||||
|
* it is a member of an object. The "content" field is the union of the structures
|
||||||
|
* that represent the various Argo types. Depending on the value of the "type" field,
|
||||||
|
* one of the "object", "array", or "string", "number", or "basic" variants of this union
|
||||||
|
* will be valid.
|
||||||
|
*/
|
||||||
|
typedef struct argo_value {
|
||||||
|
ARGO_VALUE_TYPE type;
|
||||||
|
struct argo_value *next; // Next value in list of members or elements.
|
||||||
|
struct argo_value *prev; // Previous value in list of members or element.
|
||||||
|
struct argo_string name; // NULL unless value is an object member.
|
||||||
|
union {
|
||||||
|
struct argo_object object;
|
||||||
|
struct argo_array array;
|
||||||
|
struct argo_string string;
|
||||||
|
struct argo_number number;
|
||||||
|
ARGO_BASIC basic;
|
||||||
|
} content;
|
||||||
|
} ARGO_VALUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following value is the maximum number of digits that will be printed
|
||||||
|
* for a floating point value.
|
||||||
|
*/
|
||||||
|
#define ARGO_PRECISION 15
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros that define particular character values mentioned in the Argo standard.
|
||||||
|
* You should use these macros where reference to these character values is required,
|
||||||
|
* rather than "hard-coding" the values as C character constants.
|
||||||
|
*/
|
||||||
|
#define ARGO_COLON ':'
|
||||||
|
#define ARGO_LBRACE '{'
|
||||||
|
#define ARGO_RBRACE '}'
|
||||||
|
#define ARGO_LBRACK '['
|
||||||
|
#define ARGO_RBRACK ']'
|
||||||
|
#define ARGO_QUOTE '"'
|
||||||
|
#define ARGO_BSLASH '\\'
|
||||||
|
#define ARGO_FSLASH '/'
|
||||||
|
#define ARGO_COMMA ','
|
||||||
|
#define ARGO_PERIOD '.'
|
||||||
|
#define ARGO_PLUS '+'
|
||||||
|
#define ARGO_MINUS '-'
|
||||||
|
#define ARGO_DIGIT0 '0'
|
||||||
|
#define ARGO_B 'b'
|
||||||
|
#define ARGO_E 'e'
|
||||||
|
#define ARGO_F 'f'
|
||||||
|
#define ARGO_N 'n'
|
||||||
|
#define ARGO_R 'r'
|
||||||
|
#define ARGO_T 't'
|
||||||
|
#define ARGO_U 'u'
|
||||||
|
#define ARGO_BS '\b'
|
||||||
|
#define ARGO_FF '\f'
|
||||||
|
#define ARGO_LF '\n'
|
||||||
|
#define ARGO_CR '\r'
|
||||||
|
#define ARGO_HT '\t'
|
||||||
|
#define ARGO_SPACE ' '
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros that define particular classes of characters mentioned in the Argo standard.
|
||||||
|
* You should use these macros when it is necessary to test whether a character belongs
|
||||||
|
* to a particular class, rather than "hard-coding" expressions involving C character
|
||||||
|
* constants.
|
||||||
|
*/
|
||||||
|
#define argo_is_whitespace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || c == '\t')
|
||||||
|
#define argo_is_exponent(c) ((c) == 'e' || (c) == 'E')
|
||||||
|
#define argo_is_digit(c) ((c) >= '0' && (c) <= '9')
|
||||||
|
#define argo_is_hex(c) (argo_is_digit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
|
||||||
|
#define argo_is_control(c) ((c) >= 0 && (c) < ' ')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros that define the tokens used to represent the basic values
|
||||||
|
* "true", "false", and "null", defined by the Argo standard.
|
||||||
|
* You should use these macros rather than "hard-coding" C string literals
|
||||||
|
* into your program.
|
||||||
|
*/
|
||||||
|
#define ARGO_TRUE_TOKEN "true"
|
||||||
|
#define ARGO_FALSE_TOKEN "false"
|
||||||
|
#define ARGO_NULL_TOKEN "null"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variable that is reset to zero at the beginning of each line and is
|
||||||
|
* incremented each time a character is read by function argo_read_char().
|
||||||
|
* It is intended to be used for error messages and debugging. It can be
|
||||||
|
* assigned to if it is necessary to reset the value for some reason,
|
||||||
|
* such as if reading from multiple sources is done.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following function is used to append a character to a string.
|
||||||
|
* An implementation has been provided for you.
|
||||||
|
*/
|
||||||
|
int argo_append_char(ARGO_STRING *, ARGO_CHAR);
|
||||||
|
|
||||||
|
#endif
|
88
hw1/include/debug.h
Normal file
88
hw1/include/debug.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#ifndef DEBUG_H
|
||||||
|
#define DEBUG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define NL "\n"
|
||||||
|
|
||||||
|
#ifdef COLOR
|
||||||
|
#define KNRM "\033[0m"
|
||||||
|
#define KRED "\033[1;31m"
|
||||||
|
#define KGRN "\033[1;32m"
|
||||||
|
#define KYEL "\033[1;33m"
|
||||||
|
#define KBLU "\033[1;34m"
|
||||||
|
#define KMAG "\033[1;35m"
|
||||||
|
#define KCYN "\033[1;36m"
|
||||||
|
#define KWHT "\033[1;37m"
|
||||||
|
#define KBWN "\033[0;33m"
|
||||||
|
#else
|
||||||
|
#define KNRM ""
|
||||||
|
#define KRED ""
|
||||||
|
#define KGRN ""
|
||||||
|
#define KYEL ""
|
||||||
|
#define KBLU ""
|
||||||
|
#define KMAG ""
|
||||||
|
#define KCYN ""
|
||||||
|
#define KWHT ""
|
||||||
|
#define KBWN ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VERBOSE
|
||||||
|
#define DEBUG
|
||||||
|
#define INFO
|
||||||
|
#define WARN
|
||||||
|
#define ERROR
|
||||||
|
#define SUCCESS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define debug(S, ...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, KMAG "DEBUG: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||||
|
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define debug(S, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INFO
|
||||||
|
#define info(S, ...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, KBLU "INFO: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||||
|
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define info(S, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WARN
|
||||||
|
#define warn(S, ...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, KYEL "WARN: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||||
|
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define warn(S, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SUCCESS
|
||||||
|
#define success(S, ...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, KGRN "SUCCESS: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||||
|
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define success(S, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ERROR
|
||||||
|
#define error(S, ...) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, KRED "ERROR: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||||
|
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define error(S, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* DEBUG_H */
|
87
hw1/include/global.h
Normal file
87
hw1/include/global.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* DO NOT MODIFY THE CONTENTS OF THIS FILE.
|
||||||
|
* IT WILL BE REPLACED DURING GRADING
|
||||||
|
*/
|
||||||
|
#ifndef GLOBAL_H
|
||||||
|
#define GLOBAL_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Options info, set by validargs.
|
||||||
|
* If -h is specified, then the HELP_OPTION bit is set.
|
||||||
|
* If -v is specified, then the VALIDATE_OPTION bit is set.
|
||||||
|
* If -c is specified, then the CANONICALIZE_OPTION bit is set.
|
||||||
|
* If -p is specified, then the PRETTY_PRINT_OPTION bit is set.
|
||||||
|
* If PRETTY_PRINT_OPTION is set, then CANONICALIZE_OPTION must also be set.
|
||||||
|
* The least-significant byte contains the number of additional spaces
|
||||||
|
* to add at the beginning of each output line, for each increase
|
||||||
|
* in the indentation level of the value being output.
|
||||||
|
*/
|
||||||
|
int global_options;
|
||||||
|
|
||||||
|
#define HELP_OPTION (0x80000000)
|
||||||
|
#define VALIDATE_OPTION (0x40000000)
|
||||||
|
#define CANONICALIZE_OPTION (0x20000000)
|
||||||
|
#define PRETTY_PRINT_OPTION (0x10000000)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables that keep track of the current amount of input data that has been
|
||||||
|
* read. Variable "argo_lines_read" starts at zero and is incremented each time
|
||||||
|
* a newline character is read by function argo_read_char(). Variable
|
||||||
|
* "argo_chars_read" starts at zero, is reset to zero at the beginning of each
|
||||||
|
* line, and is incremented each time a character is read by function argo_read_char().
|
||||||
|
* These variables are intended to be used for error messages and debugging.
|
||||||
|
* They can be assigned to if it is necessary to reset their values for some reason,
|
||||||
|
* such as if reading from multiple sources is done.
|
||||||
|
*/
|
||||||
|
int argo_lines_read;
|
||||||
|
int argo_chars_read;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variable that keeps track of the current indent level while pretty printing.
|
||||||
|
* See the assignment handout for a description of how the indent level is to
|
||||||
|
* be maintained and used.
|
||||||
|
*/
|
||||||
|
int indent_level;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following array contains statically allocated space for Argo values.
|
||||||
|
* You *must* use the elements of this array to store your values.
|
||||||
|
* The "argo_next_value" variable contains the index of the next unused slot
|
||||||
|
* in the array. As you use the elements of the array, you should increment
|
||||||
|
* this value. Pay attention to when all elements are used, so that you don't
|
||||||
|
* use a "value" beyond the end of the array and corrupt something else in memory!
|
||||||
|
*/
|
||||||
|
#define NUM_ARGO_VALUES 100000
|
||||||
|
ARGO_VALUE argo_value_storage[NUM_ARGO_VALUES];
|
||||||
|
int argo_next_value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following array contains storage to hold digits of an integer during
|
||||||
|
* output conversion (the digits are naturally generated in the reverse order
|
||||||
|
* from which they will be output). You *must* use this array to hold the
|
||||||
|
* digits; you may not declare your own arrays!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ARGO_MAX_DIGITS 10
|
||||||
|
ARGO_CHAR argo_digits[ARGO_MAX_DIGITS];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes for functions that you must implement.
|
||||||
|
* For detailed specifications of these functions, refer to the
|
||||||
|
* stubs in the file "argo.c", as well as to the assignment handout.
|
||||||
|
* Note that you will almost certainly want to implement additional
|
||||||
|
* functions besides those specified here.
|
||||||
|
*/
|
||||||
|
ARGO_VALUE *argo_read_value(FILE *);
|
||||||
|
int argo_read_string(ARGO_STRING *s, FILE *);
|
||||||
|
int argo_read_number(ARGO_NUMBER *n, FILE *);
|
||||||
|
|
||||||
|
int argo_write_value(ARGO_VALUE *, FILE *);
|
||||||
|
int argo_write_string(ARGO_STRING *, FILE *);
|
||||||
|
int argo_write_number(ARGO_NUMBER *, FILE *);
|
||||||
|
|
||||||
|
int validargs(int argc, char **argv);
|
||||||
|
|
||||||
|
#endif
|
BIN
hw1/lib/argo.a
Normal file
BIN
hw1/lib/argo.a
Normal file
Binary file not shown.
17
hw1/rsrc/numbers.json
Normal file
17
hw1/rsrc/numbers.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"0": 0,
|
||||||
|
"2147483648": 2147483648,
|
||||||
|
"-2147483649": 2147483649,
|
||||||
|
"0.0": 0.0,
|
||||||
|
"1": 1,
|
||||||
|
"789": 789,
|
||||||
|
"1.0": 1.0,
|
||||||
|
"-1.0": -1.0,
|
||||||
|
"1e3": 1e3,
|
||||||
|
"1E3": 1E3,
|
||||||
|
"1e-3": 1e-3,
|
||||||
|
"1.234": 1.234,
|
||||||
|
"-1.234": -1.234,
|
||||||
|
"1.234e3": 1.234e3,
|
||||||
|
"1.234e-3": 1.234e-3
|
||||||
|
}
|
2419
hw1/rsrc/package-lock.json
generated
Normal file
2419
hw1/rsrc/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
hw1/rsrc/strings.json
Normal file
11
hw1/rsrc/strings.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"a",
|
||||||
|
" ",
|
||||||
|
"\\",
|
||||||
|
"\"",
|
||||||
|
"\u005c",
|
||||||
|
"\u0020",
|
||||||
|
"\b\f\n\t\r",
|
||||||
|
"\u0008\u000c\u000a\u0009\u000b"
|
||||||
|
]
|
148
hw1/src/argo.c
Normal file
148
hw1/src/argo.c
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "argo.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read JSON input from a specified input stream, parse it,
|
||||||
|
* and return a data structure representing the corresponding value.
|
||||||
|
* @details This function reads a sequence of 8-bit bytes from
|
||||||
|
* a specified input stream and attempts to parse it as a JSON value,
|
||||||
|
* according to the JSON syntax standard. If the input can be
|
||||||
|
* successfully parsed, then a pointer to a data structure representing
|
||||||
|
* the corresponding value is returned. See the assignment handout for
|
||||||
|
* information on the JSON syntax standard and how parsing can be
|
||||||
|
* accomplished. As discussed in the assignment handout, the returned
|
||||||
|
* pointer must be to one of the elements of the argo_value_storage
|
||||||
|
* array that is defined in the const.h header file.
|
||||||
|
* In case of an error (these include failure of the input to conform
|
||||||
|
* to the JSON standard, premature EOF on the input stream, as well as
|
||||||
|
* other I/O errors), a one-line error message is output to standard error
|
||||||
|
* and a NULL pointer value is returned.
|
||||||
|
*
|
||||||
|
* @param f Input stream from which JSON is to be read.
|
||||||
|
* @return Zero if the operation is completely successful,
|
||||||
|
* nonzero if there is any error.
|
||||||
|
*/
|
||||||
|
ARGO_VALUE *argo_read_value(FILE *f) {
|
||||||
|
// TO BE IMPLEMENTED.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read JSON input from a specified input stream, attempt to
|
||||||
|
* parse it as a JSON string literal, and return a data structure
|
||||||
|
* representing the corresponding string.
|
||||||
|
* @details This function reads a sequence of 8-bit bytes from
|
||||||
|
* a specified input stream and attempts to parse it as a JSON string
|
||||||
|
* literal, according to the JSON syntax standard. If the input can be
|
||||||
|
* successfully parsed, then a pointer to a data structure representing
|
||||||
|
* the corresponding value is returned.
|
||||||
|
* In case of an error (these include failure of the input to conform
|
||||||
|
* to the JSON standard, premature EOF on the input stream, as well as
|
||||||
|
* other I/O errors), a one-line error message is output to standard error
|
||||||
|
* and a NULL pointer value is returned.
|
||||||
|
*
|
||||||
|
* @param f Input stream from which JSON is to be read.
|
||||||
|
* @return Zero if the operation is completely successful,
|
||||||
|
* nonzero if there is any error.
|
||||||
|
*/
|
||||||
|
int argo_read_string(ARGO_STRING *s, FILE *f) {
|
||||||
|
// TO BE IMPLEMENTED.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read JSON input from a specified input stream, attempt to
|
||||||
|
* parse it as a JSON number, and return a data structure representing
|
||||||
|
* the corresponding number.
|
||||||
|
* @details This function reads a sequence of 8-bit bytes from
|
||||||
|
* a specified input stream and attempts to parse it as a JSON numeric
|
||||||
|
* literal, according to the JSON syntax standard. If the input can be
|
||||||
|
* successfully parsed, then a pointer to a data structure representing
|
||||||
|
* the corresponding value is returned. The returned value must contain
|
||||||
|
* (1) a string consisting of the actual sequence of characters read from
|
||||||
|
* the input stream; (2) a floating point representation of the corresponding
|
||||||
|
* value; and (3) an integer representation of the corresponding value,
|
||||||
|
* in case the input literal did not contain any fraction or exponent parts.
|
||||||
|
* In case of an error (these include failure of the input to conform
|
||||||
|
* to the JSON standard, premature EOF on the input stream, as well as
|
||||||
|
* other I/O errors), a one-line error message is output to standard error
|
||||||
|
* and a NULL pointer value is returned.
|
||||||
|
*
|
||||||
|
* @param f Input stream from which JSON is to be read.
|
||||||
|
* @return Zero if the operation is completely successful,
|
||||||
|
* nonzero if there is any error.
|
||||||
|
*/
|
||||||
|
int argo_read_number(ARGO_NUMBER *n, FILE *f) {
|
||||||
|
// TO BE IMPLEMENTED.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write canonical JSON representing a specified value to
|
||||||
|
* a specified output stream.
|
||||||
|
* @details Write canonical JSON representing a specified value
|
||||||
|
* to specified output stream. See the assignment document for a
|
||||||
|
* detailed discussion of the data structure and what is meant by
|
||||||
|
* canonical JSON.
|
||||||
|
*
|
||||||
|
* @param v Data structure representing a value.
|
||||||
|
* @param f Output stream to which JSON is to be written.
|
||||||
|
* @return Zero if the operation is completely successful,
|
||||||
|
* nonzero if there is any error.
|
||||||
|
*/
|
||||||
|
int argo_write_value(ARGO_VALUE *v, FILE *f) {
|
||||||
|
// TO BE IMPLEMENTED.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write canonical JSON representing a specified string
|
||||||
|
* to a specified output stream.
|
||||||
|
* @details Write canonical JSON representing a specified string
|
||||||
|
* to specified output stream. See the assignment document for a
|
||||||
|
* detailed discussion of the data structure and what is meant by
|
||||||
|
* canonical JSON. The argument string may contain any sequence of
|
||||||
|
* Unicode code points and the output is a JSON string literal,
|
||||||
|
* represented using only 8-bit bytes. Therefore, any Unicode code
|
||||||
|
* with a value greater than or equal to U+00FF cannot appear directly
|
||||||
|
* in the output and must be represented by an escape sequence.
|
||||||
|
* There are other requirements on the use of escape sequences;
|
||||||
|
* see the assignment handout for details.
|
||||||
|
*
|
||||||
|
* @param v Data structure representing a string (a sequence of
|
||||||
|
* Unicode code points).
|
||||||
|
* @param f Output stream to which JSON is to be written.
|
||||||
|
* @return Zero if the operation is completely successful,
|
||||||
|
* nonzero if there is any error.
|
||||||
|
*/
|
||||||
|
int argo_write_string(ARGO_STRING *s, FILE *f) {
|
||||||
|
// TO BE IMPLEMENTED.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write canonical JSON representing a specified number
|
||||||
|
* to a specified output stream.
|
||||||
|
* @details Write canonical JSON representing a specified number
|
||||||
|
* to specified output stream. See the assignment document for a
|
||||||
|
* detailed discussion of the data structure and what is meant by
|
||||||
|
* canonical JSON. The argument number may contain representations
|
||||||
|
* of the number as any or all of: string conforming to the
|
||||||
|
* specification for a JSON number (but not necessarily canonical),
|
||||||
|
* integer value, or floating point value. This function should
|
||||||
|
* be able to work properly regardless of which subset of these
|
||||||
|
* representations is present.
|
||||||
|
*
|
||||||
|
* @param v Data structure representing a number.
|
||||||
|
* @param f Output stream to which JSON is to be written.
|
||||||
|
* @return Zero if the operation is completely successful,
|
||||||
|
* nonzero if there is any error.
|
||||||
|
*/
|
||||||
|
int argo_write_number(ARGO_NUMBER *n, FILE *f) {
|
||||||
|
// TO BE IMPLEMENTED.
|
||||||
|
abort();
|
||||||
|
}
|
47
hw1/src/const.c
Normal file
47
hw1/src/const.c
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* DO NOT MODIFY THE CONTENTS OF THIS FILE.
|
||||||
|
* IT WILL BE REPLACED DURING GRADING
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "argo.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append a specified character to a specified string.
|
||||||
|
* @details This function takes a pointer to an ARGO_STRING structure,
|
||||||
|
* which is assumed previously to have been initialized (an ARGO_STRING
|
||||||
|
* is initialized to empty by zeroing its fields) and an ARGO_CHAR
|
||||||
|
* value, representing an arbitrary Unicode code point, and it appends
|
||||||
|
* the character to the string, taking care of reallocating the string
|
||||||
|
* content into a new memory area if its length has grown to exceed
|
||||||
|
* the area already allocated for it.
|
||||||
|
*
|
||||||
|
* @return Zero if the operation completes without error, nonzero if
|
||||||
|
* there was a failure to allocate additional memory required to
|
||||||
|
* accomodate the string.
|
||||||
|
*/
|
||||||
|
int argo_append_char(ARGO_STRING *s, ARGO_CHAR c) {
|
||||||
|
if(s->capacity == 0) {
|
||||||
|
s->capacity = 10;
|
||||||
|
s->content = malloc(s->capacity * sizeof(ARGO_CHAR));
|
||||||
|
if(!s->content) {
|
||||||
|
fprintf(stderr, "[%d] Failed to allocate space for string text",
|
||||||
|
argo_lines_read);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(s->length == s->capacity) {
|
||||||
|
s->capacity *= 2;
|
||||||
|
s->content = realloc(s->content, s->capacity * sizeof(ARGO_CHAR));
|
||||||
|
if(!s->content) {
|
||||||
|
fprintf(stderr, "[%d] Failed to allocate space for string text",
|
||||||
|
argo_lines_read);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s->content[s->length++] = c;
|
||||||
|
return 0;
|
||||||
|
}
|
33
hw1/src/main.c
Normal file
33
hw1/src/main.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "argo.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#ifdef _STRING_H
|
||||||
|
#error "Do not #include <string.h>. You will get a ZERO."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _STRINGS_H
|
||||||
|
#error "Do not #include <strings.h>. You will get a ZERO."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _CTYPE_H
|
||||||
|
#error "Do not #include <ctype.h>. You will get a ZERO."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if(validargs(argc, argv))
|
||||||
|
USAGE(*argv, EXIT_FAILURE);
|
||||||
|
if(global_options == HELP_OPTION)
|
||||||
|
USAGE(*argv, EXIT_SUCCESS);
|
||||||
|
// TO BE IMPLEMENTED
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just a reminder: All non-main functions should
|
||||||
|
* be in another file not named main.c
|
||||||
|
*/
|
26
hw1/src/validargs.c
Normal file
26
hw1/src/validargs.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "argo.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates command line arguments passed to the program.
|
||||||
|
* @details This function will validate all the arguments passed to the
|
||||||
|
* program, returning 0 if validation succeeds and -1 if validation fails.
|
||||||
|
* Upon successful return, the various options that were specified will be
|
||||||
|
* encoded in the global variable 'global_options', where it will be
|
||||||
|
* accessible elsewhere in the program. For details of the required
|
||||||
|
* encoding, see the assignment handout.
|
||||||
|
*
|
||||||
|
* @param argc The number of arguments passed to the program from the CLI.
|
||||||
|
* @param argv The argument strings passed to the program from the CLI.
|
||||||
|
* @return 0 if validation succeeds and -1 if validation fails.
|
||||||
|
* @modifies global variable "global_options" to contain an encoded representation
|
||||||
|
* of the selected program options.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int validargs(int argc, char **argv) {
|
||||||
|
// TO BE IMPLEMENTED
|
||||||
|
abort();
|
||||||
|
}
|
95
hw1/tests/basecode_tests.c
Normal file
95
hw1/tests/basecode_tests.c
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include <criterion/criterion.h>
|
||||||
|
#include <criterion/logging.h>
|
||||||
|
|
||||||
|
#include "argo.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
static char *progname = "bin/argo";
|
||||||
|
|
||||||
|
Test(basecode_suite, validargs_help_test) {
|
||||||
|
char *argv[] = {progname, "-h", NULL};
|
||||||
|
int argc = (sizeof(argv) / sizeof(char *)) - 1;
|
||||||
|
int ret = validargs(argc, argv);
|
||||||
|
int exp_ret = 0;
|
||||||
|
int opt = global_options;
|
||||||
|
int flag = HELP_OPTION;
|
||||||
|
cr_assert_eq(ret, exp_ret, "Invalid return for validargs. Got: %d | Expected: %d",
|
||||||
|
ret, exp_ret);
|
||||||
|
cr_assert_eq(opt & flag, flag, "Correct bit (0x%x) not set for -h. Got: %x",
|
||||||
|
flag, opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(basecode_suite, validargs_validate_test) {
|
||||||
|
char *argv[] = {progname, "-v", NULL};
|
||||||
|
int argc = (sizeof(argv) / sizeof(char *)) - 1;
|
||||||
|
int ret = validargs(argc, argv);
|
||||||
|
int exp_ret = 0;
|
||||||
|
int opt = global_options;
|
||||||
|
int exp_opt = VALIDATE_OPTION;
|
||||||
|
cr_assert_eq(ret, exp_ret, "Invalid return for validargs. Got: %d | Expected: %d",
|
||||||
|
ret, exp_ret);
|
||||||
|
cr_assert_eq(opt, exp_opt, "Invalid options settings. Got: 0x%x | Expected: 0x%x",
|
||||||
|
opt, exp_opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(basecode_suite, validargs_canonicalize_test) {
|
||||||
|
char *argv[] = {progname, "-c", NULL};
|
||||||
|
int argc = (sizeof(argv) / sizeof(char *)) - 1;
|
||||||
|
int ret = validargs(argc, argv);
|
||||||
|
int exp_ret = 0;
|
||||||
|
int opt = global_options;
|
||||||
|
int exp_opt = CANONICALIZE_OPTION | 0x4;
|
||||||
|
cr_assert_eq(ret, exp_ret, "Invalid return for validargs. Got: %d | Expected: %d",
|
||||||
|
ret, exp_ret);
|
||||||
|
cr_assert_eq(opt, exp_opt, "Invalid options settings. Got: 0x%x | Expected: 0x%x",
|
||||||
|
opt, exp_opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(basecode_suite, validargs_pretty_print_test) {
|
||||||
|
char *argv[] = {progname, "-c", "-p", "13", NULL};
|
||||||
|
int argc = (sizeof(argv) / sizeof(char *)) - 1;
|
||||||
|
int ret = validargs(argc, argv);
|
||||||
|
int exp_ret = 0;
|
||||||
|
int opt = global_options;
|
||||||
|
int exp_opt = CANONICALIZE_OPTION | PRETTY_PRINT_OPTION | 13;
|
||||||
|
cr_assert_eq(ret, exp_ret, "Invalid return for validargs. Got: %d | Expected: %d",
|
||||||
|
ret, exp_ret);
|
||||||
|
cr_assert_eq(opt, exp_opt, "Invalid options settings. Got: 0x%x | Expected: 0x%x",
|
||||||
|
opt, exp_opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(basecode_suite, validargs_error_test) {
|
||||||
|
char *argv[] = {progname, "-v", "-p", NULL};
|
||||||
|
int argc = (sizeof(argv) / sizeof(char *)) - 1;
|
||||||
|
int exp_ret = -1;
|
||||||
|
int ret = validargs(argc, argv);
|
||||||
|
cr_assert_eq(ret, exp_ret, "Invalid return for validargs. Got: %d | Expected: %d",
|
||||||
|
ret, exp_ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(basecode_suite, help_system_test) {
|
||||||
|
char *cmd = "bin/argo -h > /dev/null 2>&1";
|
||||||
|
|
||||||
|
// system is a syscall defined in stdlib.h
|
||||||
|
// it takes a shell command as a string and runs it
|
||||||
|
// we use WEXITSTATUS to get the return code from the run
|
||||||
|
// use 'man 3 system' to find out more
|
||||||
|
int return_code = WEXITSTATUS(system(cmd));
|
||||||
|
|
||||||
|
cr_assert_eq(return_code, EXIT_SUCCESS,
|
||||||
|
"Program exited with 0x%x instead of EXIT_SUCCESS",
|
||||||
|
return_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(basecode_suite, argo_basic_test) {
|
||||||
|
char *cmd = "bin/argo -c < rsrc/strings.json > test_output/strings_-c.json";
|
||||||
|
char *cmp = "cmp test_output/strings_-c.json tests/rsrc/strings_-c.json";
|
||||||
|
|
||||||
|
int return_code = WEXITSTATUS(system(cmd));
|
||||||
|
cr_assert_eq(return_code, EXIT_SUCCESS,
|
||||||
|
"Program exited with 0x%x instead of EXIT_SUCCESS",
|
||||||
|
return_code);
|
||||||
|
return_code = WEXITSTATUS(system(cmp));
|
||||||
|
cr_assert_eq(return_code, EXIT_SUCCESS,
|
||||||
|
"Program output did not match reference output.");
|
||||||
|
}
|
1
hw1/tests/rsrc/strings_-c.json
Normal file
1
hw1/tests/rsrc/strings_-c.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
["","a"," ","\\","\"","\\"," ","\b\f\n\t\r","\b\f\n\t\u000b"]
|
Loading…
Reference in New Issue
Block a user