Bring in basecode from development repo.

This commit is contained in:
Gene Stark 2022-01-15 16:47:59 -05:00
commit 595cae98a1
17 changed files with 3360 additions and 0 deletions

29
.gitlab-ci.yml Normal file
View 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
View File

@ -0,0 +1,6 @@
bin/
build/
test_output/
*~
*.out
*.bak

61
hw1/Makefile Normal file
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

17
hw1/rsrc/numbers.json Normal file
View 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

File diff suppressed because it is too large Load Diff

11
hw1/rsrc/strings.json Normal file
View 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
View 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
View 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
View 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
View 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();
}

View 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.");
}

View File

@ -0,0 +1 @@
["","a"," ","\\","\"","\\"," ","\b\f\n\t\r","\b\f\n\t\u000b"]