Merge pull request #4 from lucic71/main_1

Main 1
This commit is contained in:
Lucian 2021-03-25 11:23:20 +02:00 committed by GitHub
commit d5b883d06a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
97 changed files with 1972 additions and 945 deletions

View File

@ -4,7 +4,7 @@ LIBRARY=none
INCPATHS=include
LIBPATHS=
LDFLAGS=
CCFLAGS=-c -Wall -g -Wextra -Werror -pedantic-errors
CCFLAGS=-c -Wall -g -Wextra -Werror -pedantic-errors -std=c89
CC=gcc
CODING_STYLE_CHECKER=checkpatch_wrapper.sh
@ -13,10 +13,10 @@ OBJECTS=$(SOURCES:.c=.o)
INCFLAGS=$(foreach TMP,$(INCPATHS),-I$(TMP))
LIBFLAGS=$(foreach TMP,$(LIBPATHS),-L$(TMP))
all: $(SOURCES) $(OUTPUT)
build: $(SOURCES) $(OUTPUT)
coding_style:
./$(CODING_STYLE_CHECKER) $(SOURCES) $(INCPATHS)/*
./$(CODING_STYLE_CHECKER)
$(OUTPUT): $(OBJECTS)
$(CC) $(LIBFLAGS) $(OBJECTS) $(LDFLAGS) -o $@

26
Makefile Executable file
View File

@ -0,0 +1,26 @@
L=link
OUTPUT=so-cpp
SOURCES=expand_line.c hashmap.c line_handler.c pp.c pp_args.c pp_define.c pp_if.c pp_ifdef.c pp_inc.c so-cpp.c str_dyn_arr.c utils.c
LIBRARY=none
INCPATHS=include
CCFLAGS=/c /Wall /Zi /W4 /MD /nologo /D_CRT_SECURE_NO_WARNINGS
CC=cl
CODING_STYLE_CHECKER=checkpatch_wrapper.exe
OBJECTS=$(SOURCES:.c=.obj)
INCFLAGS=/Iinclude
build: $(SOURCES) $(OUTPUT)
coding_style:
./$(CODING_STYLE_CHECKER) $(SOURCES) $(INCPATHS)/*
$(OUTPUT): $(OBJECTS)
$(L) /nologo /out:$(OUTPUT) $(OBJECTS)
.c.obj:
$(CC) $(INCFLAGS) $(CCFLAGS) *.c
clean:
del /Q /F $(OUTPUT) $(OBJECTS)

17
Makefile.checker Normal file
View File

@ -0,0 +1,17 @@
.PHONY: all clean run pack build-pre build-post
all: build-pre run build-post
build-pre:
build-post:
run:
@./run_all.sh
pack:
zip -r run_test_lin.zip _test/ Makefile.checker \
run_all.sh README
clean:
rm -f *~

1
_test/inputs/test1.in Normal file
View File

@ -0,0 +1 @@
file passed through stdin

1
_test/inputs/test1.param Normal file
View File

@ -0,0 +1 @@
bad.file

10
_test/inputs/test10.in Normal file
View File

@ -0,0 +1,10 @@
#define ABC "10"
#define BCD 20 + 4
int main() {
printf("%s\n", ABC);
int x = BCD + 20;
printf("%x\n", x);
return 0;
}

10
_test/inputs/test11.in Normal file
View File

@ -0,0 +1,10 @@
#define ABC 10
#define ABCD 2
#define BCD ABC + 15
int main() {
printf("%d\n", ABC);
int x = BCD + 20;
return 0;
}

11
_test/inputs/test12.in Normal file
View File

@ -0,0 +1,11 @@
#define VAR0 1 \
+ 2\
+ 3\
+ 4
int main() {
int y = VAR0 + 1;
printf("%d\n", VAR0);
return 0;
}

6
_test/inputs/test13.in Normal file
View File

@ -0,0 +1,6 @@
int main() {
#if 1
printf("Yes!\n");
#endif
return 0;
}

6
_test/inputs/test14.in Normal file
View File

@ -0,0 +1,6 @@
int main() {
#if 0
printf("No!\n");
#endif
return 0;
}

8
_test/inputs/test15.in Normal file
View File

@ -0,0 +1,8 @@
#define TEST 1
int main() {
#if TEST
printf("Yes!\n");
#endif
return 0;
}

8
_test/inputs/test16.in Normal file
View File

@ -0,0 +1,8 @@
#define TEST 0
int main() {
#if TEST
printf("Yes!\n");
#endif
return 0
}

8
_test/inputs/test17.in Normal file
View File

@ -0,0 +1,8 @@
int main() {
#if 1
printf("True!\n");
#else
printf("False!\n");
#endif
return 0;
}

8
_test/inputs/test18.in Normal file
View File

@ -0,0 +1,8 @@
int main() {
#if 0
printf("True!\n");
#else
printf("False!\n");
#endif
return 0;
}

10
_test/inputs/test19.in Normal file
View File

@ -0,0 +1,10 @@
#define TEST 1
int main() {
#if TEST
printf("True!\n");
#else
printf("False!\n");
#endif
return 0;
}

1
_test/inputs/test2.param Normal file
View File

@ -0,0 +1 @@
-X bad param

9
_test/inputs/test20.in Normal file
View File

@ -0,0 +1,9 @@
int main() {
#if TEST
printf("True!\n");
#else
printf("False!\n");
#endif
return 0;
}

View File

@ -0,0 +1 @@
-D TEST=0

12
_test/inputs/test21.in Normal file
View File

@ -0,0 +1,12 @@
#define FALSE 0
#define NOT 0
#define TRUE 1
int main() {
#if FALSE
printf("False!\n");
#elif NOT
printf("True!\n");
#endif
return 0;
}

12
_test/inputs/test22.in Normal file
View File

@ -0,0 +1,12 @@
#define FALSE 0
#define NOT 0
#define TRUE 1
int main() {
#if FALSE
printf("False!\n");
#elif TRUE
printf("True!\n");
#endif
return 0;
}

14
_test/inputs/test23.in Normal file
View File

@ -0,0 +1,14 @@
#define FALSE 0
#define NOT 0
#define TRUE 1
int main() {
#if FALSE
printf("False!\n");
#elif TRUE
printf("True!\n");
#else
printf("Bad!\n");
#endif
return 0;
}

14
_test/inputs/test24.in Normal file
View File

@ -0,0 +1,14 @@
#define FALSE 0
#define NOT 0
#define TRUE 1
int main() {
#if FALSE
printf("False!\n");
#elif NOT
printf("True!\n");
#else
printf("Good!\n");
#endif
return 0;
}

23
_test/inputs/test25.in Normal file
View File

@ -0,0 +1,23 @@
#define VAR0 1
#define TEST_IF 5
int main() {
#if 0
printf("No\n");
#elif 0
printf("Maybe\n");
#elif VAR0
printf("ABC\n");
#else
printf("Yes\n");
#endif
#if TEST_IF
printf("#defines working in #ifs\n");
#endif
int y = VAR0 + 1;
printf("%d\n", VAR0);
return 0;
}

7
_test/inputs/test26.in Normal file
View File

@ -0,0 +1,7 @@
int main()
{
#ifdef DEBUG
printf("DEBUG\n");
#endif
return 0;
}

7
_test/inputs/test27.in Normal file
View File

@ -0,0 +1,7 @@
int main()
{
#ifdef DEBUG
printf("DEBUG\n");
#endif
return 0;
}

View File

@ -0,0 +1 @@
-DDEBUG

9
_test/inputs/test28.in Normal file
View File

@ -0,0 +1,9 @@
#ifndef VAR0
#define VAR0 1
#endif
int main()
{
printf("VAR0 = %d\n", VAR0);
return 0;
}

9
_test/inputs/test29.in Normal file
View File

@ -0,0 +1,9 @@
#ifdef VAR0
#undef VAR0
#endif
int main()
{
printf("VAR0 = %d\n", VAR0);
return 0;
}

View File

@ -0,0 +1 @@
-D VAR0

1
_test/inputs/test3.in Normal file
View File

@ -0,0 +1 @@
input error file

1
_test/inputs/test3.param Normal file
View File

@ -0,0 +1 @@
_test/inputs/test3.in test3.out test3.err

6
_test/inputs/test30.in Normal file
View File

@ -0,0 +1,6 @@
#include "no-file.h"
int main()
{
return 0;
}

View File

@ -0,0 +1 @@
_test/inputs/test30.in

5
_test/inputs/test31.in Normal file
View File

@ -0,0 +1,5 @@
int main()
{
printf("%d\n", VAR0 + VAR1);
return 0;
}

View File

@ -0,0 +1 @@
-D VAR0=0 -D VAR1=1

1
_test/inputs/test32.h Normal file
View File

@ -0,0 +1 @@
int var;

7
_test/inputs/test32.in Normal file
View File

@ -0,0 +1,7 @@
#include "test32.h"
int main()
{
printf("var = %d\n", var);
return 0;
}

View File

@ -0,0 +1 @@
int var;

7
_test/inputs/test33.in Normal file
View File

@ -0,0 +1,7 @@
#include "test33.dir/test33.h"
int main()
{
printf("var = %d\n", var);
return 0;
}

View File

@ -0,0 +1 @@
int var;

8
_test/inputs/test34.in Normal file
View File

@ -0,0 +1,8 @@
#include "test34.h"
int main()
{
printf("var = %d\n", var);
return 0;
}

View File

@ -0,0 +1 @@
-I _test/inputs/test34.dir

View File

@ -0,0 +1 @@
#define VAR 1

View File

@ -0,0 +1 @@
#define VAR 2

1
_test/inputs/test35.h Normal file
View File

@ -0,0 +1 @@
#define VAR 0

8
_test/inputs/test35.in Normal file
View File

@ -0,0 +1,8 @@
#include "test35.h"
int main()
{
printf("VAR = %d\n", VAR);
return 0;
}

View File

@ -0,0 +1 @@
-I _test/inputs/test35.dir -I _test/inputs/test35.dir/test35.subdir

View File

@ -0,0 +1 @@
#define VAR 1

View File

@ -0,0 +1 @@
#define VAR 2

8
_test/inputs/test36.in Normal file
View File

@ -0,0 +1,8 @@
#include "test36.h"
int main()
{
printf("VAR = %d\n", VAR);
return 0;
}

View File

@ -0,0 +1,2 @@
-I _test/inputs/test36.dir -I _test/inputs/test36.dir/test36.subdir

6
_test/inputs/test37.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _TEST_33_H_
#define _TEST_33_H_
int var;
#endif /* TEST_33_H_ */

7
_test/inputs/test37.in Normal file
View File

@ -0,0 +1,7 @@
#include "test37.h"
int main()
{
printf("var = %d\n", var);
return 0;
}

View File

@ -0,0 +1,14 @@
#ifndef _DEBUG_H_
#define _DEBUG_H_
#ifndef DEBUG_STR
#define DEBUG_STR "debuging"
#endif
#if DEBUG
#define debug fprintf(stderr, DEBUG_STR "\n")
#else
#define debug
#endif
#endif /* _DEBUG_H_ */

12
_test/inputs/test38.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _TEST38_H_
#define _TEST38_H_
#ifdef CUSTOM_DBG
#define DEBUG_STR CUSTOM_DBG
#else
#define DEBUG_STR "my debugging"
#endif
#include "debug.h"
#endif /* _TEST38_H_ */

View File

@ -0,0 +1 @@
-D DEBUG=1 -D CUSTOM_DBG=custom-debugging -I _test/inputs/test38.dir

1
_test/inputs/test4.in Normal file
View File

@ -0,0 +1 @@
file passed through standard input

1
_test/inputs/test5.in Normal file
View File

@ -0,0 +1 @@
file passed through parameter

1
_test/inputs/test6.in Normal file
View File

@ -0,0 +1 @@
file passed as output

8
_test/inputs/test7.in Normal file
View File

@ -0,0 +1,8 @@
#define VAR0 1
int main() {
int y = VAR0 + 1;
printf("%d\n", VAR0);
return 0;
}

6
_test/inputs/test8.in Normal file
View File

@ -0,0 +1,6 @@
int main() {
int y = VAR0 + 1;
printf("%d\n", VAR0);
return 0;
}

1
_test/inputs/test8.param Normal file
View File

@ -0,0 +1 @@
-D VAR0=1

10
_test/inputs/test9.in Normal file
View File

@ -0,0 +1,10 @@
#define VAR0 1
int main() {
int y = VAR0 + 1;
printf("%d\n", VAR0);
#undef VAR0
printf("%d\n", VAR0);
return 0;
}

254
_test/run_test.sh Executable file
View File

@ -0,0 +1,254 @@
#!/bin/bash
#
# Tema1 Test Suite
#
# 2020, Operating Systems
#
# ----------------- General declarations and util functions ------------------ #
INPUT_DIR=_test/inputs
REF_DIR=_test/ref
OUT_DIR=_test/outputs
EXEC_NAME=./so-cpp
max_points=95
TEST_LIB=_test/test_lib.sh
MEMCHECK=""
CPP="cpp -P"
[ $(uname -s) == "Linux" ]
IS_LINUX=$?
if [ $IS_LINUX -eq 0 ]; then
MEMCHECK="valgrind --leak-check=full \
--show-reachable=yes \
--vex-iropt-register-updates=allregs-at-mem-access \
--show-leak-kinds=all \
--error-exitcode=1 \
$MEMCHECK_EXTRA \
--log-file=_log "
else
MEMCHECK="drmemory -batch \
-exit_code_if_errors 1 \
-quiet \
$MEMCHECK_EXTRA \
-- "
fi
# load the lib functions
if ! [ -e "$TEST_LIB" ]; then
echo "Test library not found. Check \$TEST_LIB ($TEST_LIB)"
exit 1
fi
source "$TEST_LIB"
# ---------------------------------------------------------------------------- #
# ----------------- Init and cleanup tests ----------------------------------- #
init_test()
{
if ! [ -e "$EXEC_NAME" ]; then
echo "$EXEC_NAME not found! Cannot run the test"
exit 1
fi
unset malloc_limit
unset calloc_limit
unset realloc_limit
input_f=$INPUT_DIR"/test"$test_index".in"
param_f=$INPUT_DIR"/test"$test_index".param"
ref_f=$OUT_DIR"/test"$test_index".ref"
out_f=$OUT_DIR"/test"$test_index".out"
params="$(test -f $param_f && cat $param_f || echo "")"
}
cleanup_test()
{
rm -f $out_f
}
init_world()
{
print_header "Testing - SO Preprocessor"
mkdir -p $OUT_DIR
}
cleanup_world()
{
rm -rf $OUT_DIR &> /dev/null
}
# ---------------------------------------------------------------------------- #
# ----------------- Test Suite ----------------------------------------------- #
test_cpp()
{
init_test
$CPP $params $input_f > $ref_f
$MEMCHECK $EXEC_NAME $params $input_f > $out_f
mem_res=$?
basic_test compare $out_f $ref_f
memory_test $mem_res
cleanup_test
}
test_cpp_stdin()
{
init_test
$CPP $params < $input_f > $ref_f
$MEMCHECK $EXEC_NAME $params < $input_f > $out_f
mem_res=$?
basic_test compare $out_f $ref_f
memory_test $mem_res
cleanup_test
}
test_cpp_stdout()
{
init_test
$CPP $params $input_f $ref_f
$MEMCHECK $EXEC_NAME $params $input_f $out_f
mem_res=$?
basic_test compare $out_f $ref_f
memory_test $mem_res
cleanup_test
}
test_bad_params()
{
init_test
$EXEC_NAME $params 2> /dev/null
basic_test test $? -ne 0
cleanup_test
}
run_until_success()
{
REF_CODE=12 # ENOMEM
NR_RUNS=1000 # How many times to run
for ((i = 0; i < $NR_RUNS; i++)); do
init_test
export "$1_limit"=$i
if [ $IS_LINUX -eq 0 ]; then
LD_PRELOAD="./libso.so" $EXEC_NAME $params $input_f > $out_f
else
"./run.exe" "$EXEC_NAME $params $input_f" > $out_f
fi
retcode=$?
# If there is no error then the output file must be checked
if test $retcode -eq 0; then
return $?
fi
if test $retcode -ne $REF_CODE; then
basic_test false
return -1
fi
if test $1 != "realloc"; then
cleanup_test
fi
done
basic_test false
return -1
}
test_so_alloc()
{
if [ $IS_LINUX -eq 0 ]; then
lines=$(find . -maxdepth 1 -name "libso.so" | wc -l)
else
lines=$(find . -maxdepth 1 -name "run.exe" | wc -l)
fi
if [ $lines -eq 0 ]; then
basic_test false
else
init_test
$CPP $input_f $params > $ref_f
run_until_success "malloc"
if test $? -ne 0; then
return
fi
run_until_success "calloc"
if test $? -ne 0; then
return
fi
run_until_success "realloc"
basic_test compare $out_f $ref_f
cleanup_test
fi
}
test_fun_array=( \
test_coding_style "Sources check" 5 0 \
test_bad_params "Test bad input" 1 0 \
test_bad_params "Test bad parameters" 1 0 \
test_bad_params "Test multiple files" 1 0 \
test_cpp_stdin "Test stdin file" 1 1 \
test_cpp "Test simple file" 1 1 \
test_cpp_stdout "Test simple out file" 1 1 \
test_cpp "Test simple define" 2 1 \
test_cpp "Test param define" 2 1 \
test_cpp "Test simple define/undef" 2 1 \
test_cpp "Test multiple defines" 2 1 \
test_cpp "Test nested defines" 3 1 \
test_cpp "Test multi-lines defines" 2 1 \
test_cpp "Test simple if true" 1 1 \
test_cpp "Test simple if false" 1 1 \
test_cpp "Test define if true" 1 1 \
test_cpp "Test define if false" 1 1 \
test_cpp "Test simple if-else true" 1 1 \
test_cpp "Test simple if-else false" 1 1 \
test_cpp "Test define if-else true" 1 1 \
test_cpp "Test define param if-else false" 1 1 \
test_cpp "Test simple elif false" 1 1 \
test_cpp "Test simple elif true" 1 1 \
test_cpp "Test simple elif-else true" 1 1 \
test_cpp "Test simple elif-else false" 1 1 \
test_cpp "Test complex if-elif-else" 2 1 \
test_cpp "Test simple ifdef false" 1 1 \
test_cpp "Test simple ifdef true" 1 1 \
test_cpp "Test simple ifndef" 1 1 \
test_cpp "Test simple ifndef undef" 1 1 \
test_bad_params "Test bad include" 1 0 \
test_cpp "Test double define params" 1 1 \
test_cpp "Test simple include" 2 1 \
test_cpp "Test include directory" 1 1 \
test_cpp "Test include param" 1 1 \
test_cpp "Test include order" 1 1 \
test_cpp "Test include order no main" 1 1 \
test_cpp "Test include guard" 2 1 \
test_so_alloc "Test everything" 10 0 \
)
# ---------------------------------------------------------------------------- #
# ----------------- Run test ------------------------------------------------- #
# first we check if we have everything defined
check_tests
# run tests
run_tests $@
exit 0

229
_test/test_lib.sh Executable file
View File

@ -0,0 +1,229 @@
#!/bin/bash
#
# Tema1 Test Suite
#
# 2012-2018, Operating Systems
#
# ----------------- General declarations and util functions ------------------ #
# Enable/disable exiting when program fails.
EXIT_IF_FAIL=0
# Enable/disable debug (1/0).
DEBUG_=0
# checkpatch.pl URL
CHECKPATCH_URL="https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl"
COMMON_IGNORE_FLAGS="
SPLIT_STRING,SSCANF_TO_KSTRTO,NEW_TYPEDEFS,VOLATILE,INLINE,USE_FUNC,AVOID_EXTERNS,CONST_STRUCT,SPDX_LICENSE_TAG"
LIN_IGNORE_FLAGS="$COMMON_IGNORE_FLAGS"
WIN_IGNORE_FLAGS="$COMMON_IGNORE_FLAGS,DOS_LINE_ENDINGS"
if [ $(uname -s) == "Linux" ]; then
CHECKPATCH_IGNORE_FLAGS=$LIN_IGNORE_FLAGS
else
CHECKPATCH_IGNORE_FLAGS=$WIN_IGNORE_FLAGS
fi
CHECKPATCH_ARGS="
--no-tree
--no-summary
--terse
--ignore $CHECKPATCH_IGNORE_FLAGS
--show-types"
DEBUG()
{
if test "x$DEBUG_" = "x1"; then
$@ 1>&2
fi
}
print_header()
{
header="${1}"
header_len=${#header}
printf "\n"
if [ $header_len -lt 71 ]; then
padding=$(((71 - $header_len) / 2))
for ((i = 0; i < $padding; i++)); do
printf " "
done
fi
printf "= %s =\n\n" "${header}"
}
test_do_fail()
{
printf "failed [ 0/%02d]\n" "$max_points"
if test "x$EXIT_IF_FAIL" = "x1"; then
exit 1
fi
}
test_do_pass()
{
printf "passed [%02d/%02d]\n" "$1" "$max_points"
}
DF=${DF:--BEbwu}
# Compares to files and prints the first 10
# lines if the files differ
function compare()
{
diff $DF $1 $2 > __result
ret=$?
if [ $ret != 0 ] ; then
echo "$1 vs $2:"
cat __result | head -n 10
fi
rm -f __result
return $ret
}
memory_test()
{
DEBUG echo "MEM TEST"
res=$1
memcheck_description="$description - memcheck"
printf "%02d) %s" "$test_index" "$memcheck_description"
for ((i = 0; i < 56 - ${#memcheck_description}; i++)); do
printf "."
done
if test $res -eq 0; then
test_do_pass "$mem_points"
else
test_do_fail "$mem_poits"
fi
}
basic_test()
{
DEBUG echo "TEST: $@"
$@
res=$?
printf "%02d) %s" "$test_index" "$description"
for ((i = 0; i < 56 - ${#description}; i++)); do
printf "."
done
if test $res -eq 0; then
test_do_pass "$points"
return 0
else
test_do_fail "$points"
return -1
fi
}
check_source()
{
# check to see if we have checkpatch
check_patch=$(which checkpatch.pl 2> /dev/null)
if ! [ -x "$check_patch" ]; then
echo "'checkpatch.pl' tool not found on your system."\
"Skipping source check..."
echo "Please download 'checkpatch.pl' from '$CHECKPATCH_URL'"\
"and install it in your \$PATH."
echo
return
fi
# try to find sources in the current directory
src_files="$(find "${SRC_DIR:-.}" -type f -iregex \
'.*\.\(c\|h\|cpp\|hpp\|cc\|hh\|cxx\|hxx\)')"
if [ -z "$src_files" ]; then
read -t 60 -e -p 'Please provide path to your sources: ' SRC_DIR
if [ "$?" -ne "0" -o -z "$SRC_DIR" ]; then
echo -e "No path provided! Skipping source check...\n"
return
fi
if ! [ -e "$SRC_DIR" ]; then
echo -e "File or directory '$SRC_DIR' does not exist. " \
"Skipping source check...\n"
return
fi
src_files="$(find "$SRC_DIR" -type f -iregex \
'.*\.\(c\|h\|cpp\|hpp\|cc\|hh\|cxx\|hxx\)')"
if [ -z "$src_files" ]; then
echo -e "No sources found in '$SRC_DIR'. " \
"Skipping source check...\n"
return
fi
fi
# now we have sources in $SRC_DIR or .
OUT=$(find "${SRC_DIR:-.}" -type f -iregex \
'.*\.\(c\|h\|cpp\|hpp\|cc\|hh\|cxx\|hxx\)' | \
xargs $check_patch $CHECKPATCH_ARGS -f 2>&1 | tail -n +2 | \
sort -u -t":" -k4,4 | head -n 20)
echo "$OUT"
}
test_coding_style()
{
check_source
[ -n "$src_files" -a -z "$OUT" ]
basic_test [ $? -eq 0 ]
}
check_tests()
{
# we need to have the test_fun_array defined
if [ -z "$test_fun_array" ]; then
echo "test_fun_array is not defined - don't know what to run" 1>&2
exit 1
fi
# max_points
if [ -z "$max_points" ]; then
echo "max_points is not defined - don't the total number of points" 1>&2
exit 1
fi
}
run_tests()
{
if test $# -ne 1; then
echo "Usage: $0 test_number | init | cleanup" 1>&2
exit 1
fi
test_index=$1
if test $test_index == "init"; then
init_world
exit 0
fi
if test $test_index == "cleanup"; then
cleanup_world
exit 0
fi
if test $test_index == "check"; then
check_source
exit 0
fi
arr_index=$(($test_index * 4))
last_test=$((${#test_fun_array[@]} / 4))
description=${test_fun_array[$(($arr_index + 1))]}
points=${test_fun_array[$(($arr_index + 2))]}
mem_points=${test_fun_array[$(($arr_index + 3))]}
if test "$test_index" -gt "$last_test" -o "$arr_index" -lt 0; then
echo "Error: Test index is out range (1 < test_index <= $last_test)." 1>&2
exit 1
fi
# Run proper function
${test_fun_array[$(($arr_index))]}
}

248
expand_line.c Normal file
View File

@ -0,0 +1,248 @@
#include "expand_line.h"
#include "utils.h"
#include <string.h>
#include <stdlib.h>
#define DELIMS "\t []{}<>=+-*/%!&|^.,:;()\\"
char *_compute_expanded_line(void *def_map, char *line);
int _concat_expanded_token_to_line(void *def_map, char *token, char **line);
int _concat_delim_to_line(char *delim, int delim_size, char **line);
char *_get_expanded_token(void *def_map, char *token);
int _concat_delim_to_line(char *delim, int delim_size, char **line);
int _concat_expanded_token_to_line(void *def_map, char *token, char **line);
int _is_delim_at_str_start(char *token, char *str_start);
int _compute_delim_start(char *token, char *line);
int _compute_delim_end(char *token, char *line, char *line_copy);
int write_expanded_line(void *def_map, char *line, FILE *out)
{
char *exp_line;
int line_len;
int ret;
exp_line = get_expanded_line(def_map, line);
if (!exp_line)
return PP_FAILED;
line_len = strlen(exp_line);
ret = fprintf(out, "%s", exp_line);
free(exp_line);
if (ret < 0)
return PP_FAILED;
return ret == line_len ? PP_OK : PP_FAILED;
}
char *get_expanded_line(void *def_map, char *line)
{
char *exp_line;
char *prev_exp_line;
exp_line = NULL;
prev_exp_line = NULL;
exp_line = _compute_expanded_line(def_map, line);
if (!exp_line)
return NULL;
prev_exp_line = l_strdup(line);
if (!prev_exp_line)
goto free_and_exit;
while (strcmp(prev_exp_line, exp_line)) {
free(prev_exp_line);
prev_exp_line = exp_line;
exp_line = _compute_expanded_line(def_map, prev_exp_line);
if (!exp_line)
goto free_and_exit;
}
free(prev_exp_line);
return exp_line;
free_and_exit:
free(prev_exp_line);
free(exp_line);
return NULL;
}
char *_compute_expanded_line(void *def_map, char *line)
{
char *_line;
char *line_start;
char *line_copy;
char *token;
char *exp_line;
int delim_start;
int delim_end;
int ret;
int token_len;
_line = NULL;
line_copy = NULL;
exp_line = NULL;
_line = l_strdup(line);
if (!_line)
goto free_and_exit;
line_start = _line;
line_copy = l_strdup(_line);
if (!line_copy)
goto free_and_exit;
exp_line = calloc(1, sizeof(char));
if (!exp_line)
goto free_and_exit;
token = strtok(_line, DELIMS);
if (_is_delim_at_str_start(token, line_start)) {
ret = _concat_delim_to_line(
line_start,
token - line_start,
&exp_line
);
if (ret == PP_FAILED)
goto free_and_exit;
}
ret = _concat_expanded_token_to_line(def_map, token, &exp_line);
if (ret == PP_FAILED)
goto free_and_exit;
while (token) {
delim_start = _compute_delim_start(token, _line);
token = strtok(NULL, DELIMS);
delim_end = _compute_delim_end(token, _line, line_copy);
ret = _concat_delim_to_line(
line_copy + delim_start,
delim_end - delim_start,
&exp_line
);
if (ret == PP_FAILED)
goto free_and_exit;
if (token) {
token_len = strlen(token);
if (token[token_len - 1] == '\n')
token[token_len - 1] = 0x00;
_concat_expanded_token_to_line(
def_map,
token,
&exp_line
);
if (token[token_len - 1] == 0x00) {
token[token_len - 1] = '\n';
_concat_delim_to_line("\n", 1, &exp_line);
}
if (ret == PP_FAILED)
goto free_and_exit;
} else {
break;
}
}
free(line_copy);
free(_line);
return exp_line;
free_and_exit:
free(_line);
free(line_copy);
free(exp_line);
return NULL;
}
char *_get_expanded_token(void *def_map, char *token)
{
char *exp;
char *exp_copy;
int ret;
int token_len;
exp = NULL;
exp_copy = NULL;
ret = hashmap_get(def_map, token, &exp);
if (ret != MAP_OK) {
token_len = strlen(token);
exp_copy = calloc(token_len + 1, sizeof(char));
if (!exp_copy)
goto free_and_exit;
strcpy(exp_copy, token);
} else {
exp_copy = l_strdup(exp);
if (!exp_copy)
goto free_and_exit;
}
return exp_copy;
free_and_exit:
free(exp_copy);
return NULL;
}
int _concat_delim_to_line(char *delim, int delim_size, char **line)
{
char *_delim;
int ret;
_delim = NULL;
_delim = calloc(delim_size + 1, sizeof(char));
if (!_delim)
return PP_FAILED;
strncpy(_delim, delim, delim_size);
ret = a_strcat(line, _delim);
free(_delim);
return ret == -1 ? PP_FAILED : PP_OK;
}
int _concat_expanded_token_to_line(void *def_map, char *token, char **line)
{
char *exp;
int ret;
exp = _get_expanded_token(def_map, token);
if (!exp)
return PP_FAILED;
ret = a_strcat(line, exp);
free(exp);
return ret == -1 ? PP_FAILED : PP_OK;
}
int _is_delim_at_str_start(char *token, char *str_start)
{
return token - str_start;
}
int _compute_delim_start(char *token, char *line)
{
return token - line + strlen(token);
}
int _compute_delim_end(char *token, char *line, char *line_copy)
{
return token != NULL ? token - line : (int) strlen(line_copy);
}

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: BSD-2
/* SPDX-License-Identifier: BSD-2 */
#include <hashmap.h>
#include <stdlib.h>
@ -19,7 +19,7 @@ struct hashmap_map {
struct hashmap_elem *data;
};
string_map_t hashmap_new(void)
void *hashmap_new(void)
{
struct hashmap_map *m;
@ -67,7 +67,8 @@ int _get_next_avail_pos(struct hashmap_map *m, char *key)
if (!m->data[pos].in_use)
return pos;
if (!strncmp(m->data[pos].key, key) && m->data[pos].in_use)
if (!strncmp(m->data[pos].key, key, strlen(key))
&& m->data[pos].in_use)
return MAP_ALREADY_USED;
pos = (pos + 1) % m->max_size;
@ -107,7 +108,7 @@ int _rehash(struct hashmap_map *m)
return MAP_OK;
}
int hashmap_put(string_map_t map, char *key, char *value)
int hashmap_put(void *map, char *key, char *value)
{
int pos;
struct hashmap_map *m;
@ -127,7 +128,10 @@ int hashmap_put(string_map_t map, char *key, char *value)
pos = _get_next_avail_pos(m, key);
}
m->data[pos] = (struct hashmap_elem) {key, 1, value};
m->data[pos].key = key;
m->data[pos].in_use = 1;
m->data[pos].val = value;
m->curr_size++;
return MAP_OK;
@ -135,10 +139,11 @@ int hashmap_put(string_map_t map, char *key, char *value)
int _is_desired_pos(struct hashmap_map *m, char *key, int pos)
{
return m->data[pos].key && key && !strcmp(m->data[pos].key, key) && m->data[pos].in_use;
return m->data[pos].key && key
&& !strcmp(m->data[pos].key, key) && m->data[pos].in_use;
}
int hashmap_get(string_map_t map, char *key, char **ret_val)
int hashmap_get(void *map, char *key, char **ret_val)
{
int pos;
int i;
@ -165,7 +170,7 @@ int hashmap_get(string_map_t map, char *key, char **ret_val)
return MAP_MISSING;
}
int hashmap_del(string_map_t map, char *key)
int hashmap_del(void *map, char *key)
{
int pos;
int i;
@ -197,14 +202,17 @@ int hashmap_del(string_map_t map, char *key)
return MAP_MISSING;
}
void hashmap_free(string_map_t map)
void hashmap_free(void *map)
{
struct hashmap_map *m;
int i;
m = (struct hashmap_map *) map;
for (i = 0; i < m->max_size; i++) {
if (!m)
return;
for (i = 0; m->data && i < m->max_size; i++) {
free(m->data[i].key);
free(m->data[i].val);
}

BIN
hooks.dll Normal file

Binary file not shown.

BIN
hooks.lib Normal file

Binary file not shown.

View File

@ -1,20 +0,0 @@
/* SPDX-License-Identifier: BSD-2 */
#ifndef _char_dyn_arr
#define _char_dyn_arr
#define CHAR_DYN_ARR_OK 0
#define CHAR_DYN_ARR_FAILED -1
struct char_dyn_arr {
char **data;
int used;
int size;
};
extern struct char_dyn_arr *init_char_dyn_arr(int size);
extern int insert_char_dyn_arr(struct char_dyn_arr *a, char *e);
extern void free_char_dyn_arr(struct char_dyn_arr *a);
#endif

11
include/expand_line.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _expand_line_h
#define _expand_line_h
#include "pp_defines.h"
#include "hashmap.h"
#include <stdio.h>
extern int write_expanded_line(void *def_map, char *line, FILE *);
extern char *get_expanded_line(void *def_map, char *line);
#endif

View File

@ -10,13 +10,11 @@
#define MAP_BAD_ARGS -4
#define MAP_ALREADY_USED -5
typedef void *string_map_t;
extern void *hashmap_new(void);
extern void hashmap_free(void *map);
extern string_map_t hashmap_new(void);
extern void hashmap_free(string_map_t map);
extern int hashmap_put(string_map_t map, char *key, char *val);
extern int hashmap_get(string_map_t map, char *key, char **ret_val);
extern int hashmap_del(string_map_t map, char *key);
extern int hashmap_put(void *map, char *key, char *val);
extern int hashmap_get(void *map, char *key, char **ret_val);
extern int hashmap_del(void *map, char *key);
#endif

17
include/line_handler.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _line_handler_h
#define _line_handler_h
#include "pp_defines.h"
#include "hashmap.h"
#include "str_dyn_arr.h"
#include <stdio.h>
extern int line_handler(
char *line,
void *def_map,
const struct str_dyn_arr *inc_dirs,
FILE*,
FILE*
);
#endif

View File

@ -1,12 +1,11 @@
/* SPDX-License-Identifier: BSD-2 */
#ifndef _pp_h
#define _pp_h
#include "hashmap.h"
#include "char_dyn_arr.h"
#include "str_dyn_arr.h"
#include <stdio.h>
extern int pp_start(string_map_t define_map, struct char_dyn_arr *inc_dirs, FILE *source, FILE *output);
extern int pp_compute(void *def_map, const struct str_dyn_arr *inc_dirs,
FILE*in, FILE*);
#endif

View File

@ -4,15 +4,15 @@
#define _pp_args
#include "hashmap.h"
#include "char_dyn_arr.h"
#include "str_dyn_arr.h"
struct args {
struct char_dyn_arr *inc_dirs;
struct str_dyn_arr *inc_dirs;
char *in_file;
char *out_file;
};
extern void pp_free_args(struct args *args);
extern struct args *pp_parse_args(int argc, char **argv, string_map_t define_map);
extern struct args *pp_parse_args(int argc, char **argv, void *def_map);
#endif

View File

@ -1,13 +1,13 @@
/* SPDX-License-Identifier: BSD-2 */
#ifndef _pp_define_h
#define _pp_define_h
#ifndef _pp_define
#define _pp_define
#include "pp_defines.h"
#include "str_dyn_arr.h"
#include "hashmap.h"
#include <stdio.h>
extern int pp_expand_defines(string_map_t define_map, FILE *source, FILE *output);
extern char *pp_strerr(int pp_errno);
extern int collect_def(char *line, void *def_map, FILE *in);
extern int apply_undef(char *line, void *def_map);
#endif

View File

@ -13,6 +13,4 @@
#define PP_LINE_LEN 256
extern int pp_errno;
#endif

View File

@ -1,10 +1,12 @@
/* SPDX-License-Identifier: BSD-2 */
#ifndef _pp_if_h
#define _pp_if_h
#include "pp_defines.h"
#include "hashmap.h"
#include "str_dyn_arr.h"
#include <stdio.h>
extern int pp_expand_ifs(FILE *source, FILE *output);
extern int expand_if(void *def_map, const struct str_dyn_arr *inc_dirs,
FILE*, FILE*);
#endif

View File

@ -1,11 +1,12 @@
/* SPDX-License-Identifier: BSD-2 */
#ifndef _pp_ifdef_h
#define _pp_ifdef_h
#include <stdio.h>
#include "pp_defines.h"
#include "hashmap.h"
#include "str_dyn_arr.h"
#include <stdio.h>
extern int pp_expand_ifdefs(string_map_t define_map, FILE *source, FILE *output);
extern int expand_ifdef(void *def_map, const struct str_dyn_arr *inc_dirs,
FILE*, FILE*);
#endif

12
include/pp_inc.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _pp_inc_h
#define _pp_inc_h
#include "pp_defines.h"
#include "hashmap.h"
#include "str_dyn_arr.h"
#include <stdio.h>
extern int expand_inc(void *def_map, const struct str_dyn_arr *inc_dirs,
FILE*, FILE*);
#endif

49
include/pp_line_id.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef _pp_line_id_h
#define _pp_line_id_h
#include <string.h>
#define IF_LINE_START "#if "
#define IF_LINE_START_SZ (sizeof(IF_LINE_START) - 1)
#define IS_IF_LINE(line) (!strncmp(line, IF_LINE_START, IF_LINE_START_SZ))
#define ELSE_LINE_START "#else"
#define ELSE_LINE_START_SZ (sizeof(ELSE_LINE_START) - 1)
#define IS_ELSE_LINE(line) (!strncmp(line, ELSE_LINE_START, ELSE_LINE_START_SZ))
#define ELIF_LINE_START "#elif "
#define ELIF_LINE_START_SZ (sizeof(ELIF_LINE_START) - 1)
#define IS_ELIF_LINE(line) (!strncmp(line, ELIF_LINE_START, ELIF_LINE_START_SZ))
#define ENDIF_LINE_START "#endif"
#define ENDIF_LINE_START_SZ (sizeof(ENDIF_LINE_START) - 1)
#define IS_ENDIF_LINE(line) \
(!strncmp(line, ENDIF_LINE_START, ENDIF_LINE_START_SZ))
#define DEF_LINE_START "#define"
#define DEF_LINE_START_SZ (sizeof(DEF_LINE_START) - 1)
#define IS_DEF_LINE(line) (!strncmp(line, DEF_LINE_START, DEF_LINE_START_SZ))
#define UNDEF_LINE_START "#undef"
#define UNDEF_LINE_START_SZ (sizeof(UNDEF_LINE_START) - 1)
#define IS_UNDEF_LINE(line) \
(!strncmp(line, UNDEF_LINE_START, UNDEF_LINE_START_SZ))
#define IFDEF_LINE_START "#ifdef "
#define IFDEF_LINE_START_SZ (sizeof(IFDEF_LINE_START) - 1)
#define IS_IFDEF_LINE(line) \
(!strncmp(line, IFDEF_LINE_START, IFDEF_LINE_START_SZ))
#define IFNDEF_LINE_START "#ifndef "
#define IFNDEF_LINE_START_SZ (sizeof(IFNDEF_LINE_START) - 1)
#define IS_IFNDEF_LINE(line) \
(!strncmp(line, IFNDEF_LINE_START, IFNDEF_LINE_START_SZ))
#define INC_LINE_START "#include"
#define INC_LINE_START_SZ (sizeof(INC_LINE_START) - 1)
#define IS_INC_LINE(line) (!strncmp(line, INC_LINE_START, INC_LINE_START_SZ))
#define IS_IF_CURR_BRANCH_END(line) \
(IS_ELSE_LINE(line) || IS_ELIF_LINE(line) || IS_ENDIF_LINE(line))
#endif

20
include/str_dyn_arr.h Normal file
View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: BSD-2 */
#ifndef _str_dyn_arr
#define _str_dyn_arr
#define CHAR_DYN_ARR_OK 0
#define CHAR_DYN_ARR_FAILED -1
struct str_dyn_arr {
char **data;
int used;
int size;
};
extern struct str_dyn_arr *init_str_dyn_arr(int size);
extern int insert_str_dyn_arr(struct str_dyn_arr *a, char *e);
extern void free_str_dyn_arr(struct str_dyn_arr *a);
#endif

View File

@ -3,7 +3,21 @@
#include <stdio.h>
int write_line_to_file(FILE *f, char *line);
#define SKIP_UNTIL_CURR_BRANCH_END 1
#define SKIP_UNTIL_ENDIF_LINE 2
extern int write_line_to_file(FILE *out, char *line);
extern char *l_strdup(char *str);
extern void strip_spaces_in_def(char *def);
extern int a_strcat(char **dest, char *src);
extern int get_next_whitespace_idx(char *s);
extern char *skip_word(char *s);
extern int is_cond_null(char *cond_line);
extern int skip_until(FILE *f, int until);
#endif

BIN
libso.so Normal file

Binary file not shown.

72
line_handler.c Normal file
View File

@ -0,0 +1,72 @@
#include "line_handler.h"
#include "pp_define.h"
#include "pp_line_id.h"
#include "expand_line.h"
#include "pp_if.h"
#include "pp_ifdef.h"
#include "pp_inc.h"
int line_handler(char *line, void *def_map, const struct str_dyn_arr *inc_dirs,
FILE *source, FILE *out)
{
int ret;
int line_len;
if (IS_DEF_LINE(line))
return collect_def(line, def_map, source);
if (IS_UNDEF_LINE(line))
return apply_undef(line, def_map);
if (IS_IF_LINE(line)) {
line_len = strlen(line);
ret = fseek(source, -line_len, SEEK_CUR);
if (ret == -1)
return PP_FAILED;
ret = expand_if(def_map, inc_dirs, source, out);
if (ret == PP_FAILED)
return ret;
return PP_OK;
}
if (IS_IFDEF_LINE(line) || IS_IFNDEF_LINE(line)) {
line_len = strlen(line);
ret = fseek(source, -line_len, SEEK_CUR);
if (ret == -1)
return PP_FAILED;
ret = expand_ifdef(def_map, inc_dirs, source, out);
if (ret == PP_FAILED)
return ret;
return PP_OK;
}
if (IS_INC_LINE(line)) {
line_len = strlen(line);
ret = fseek(source, -line_len, SEEK_CUR);
if (ret == -1)
return PP_FAILED;
ret = expand_inc(def_map, inc_dirs, source, out);
if (ret == PP_FAILED)
return ret;
return PP_OK;
}
if (IS_ENDIF_LINE(line))
return PP_OK;
ret = write_expanded_line(def_map, line, out);
if (ret == PP_FAILED)
return ret;
return PP_OK;
}

39
pp.c
View File

@ -1,37 +1,28 @@
// SPDX-License-Identifier: BSD-2
#include "pp.h"
#include "pp_define.h"
#include "pp_if.h"
#include "pp_defines.h"
#include "char_dyn_arr.h"
#include "line_handler.h"
#define IF_TEMP_FILE "temp_if"
#include <stdio.h>
int pp_start(string_map_t define_map, struct char_dyn_arr *inc_dirs, FILE *source, FILE *output)
int pp_compute(void *def_map, const struct str_dyn_arr *inc_dirs, FILE *source,
FILE *out)
{
char line[PP_LINE_LEN + 1];
int read_lines;
int ret;
FILE *temp;
temp = fopen(IF_TEMP_FILE, "w+");
if (!temp)
return PP_FAILED;
read_lines = 0;
ret = pp_expand_defines(define_map, source, temp);
if (ret == PP_FAILED)
goto free_and_exit;
while (fgets(line, PP_LINE_LEN, source)) {
read_lines++;
ret = fseek(temp, 0, SEEK_SET);
if (ret == -1) {
ret = PP_FAILED;
goto free_and_exit;
ret = line_handler(line, def_map, inc_dirs, source, out);
if (ret == PP_FAILED)
return ret;
}
ret = pp_expand_ifs(temp, output);
if (ret == PP_FAILED)
goto free_and_exit;
if (ferror(source) || !read_lines)
return PP_FAILED;
free_and_exit:
fclose(temp);
return ret;
return PP_OK;
}

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: BSD-2
/* SPDX-License-Identifier: BSD-2 */
#include "pp_args.h"
#include "pp_defines.h"
#include "utils.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
@ -53,15 +54,13 @@ int _is_unrecognized_flag(char *flag)
int _calloc_and_check(char **p, int sz)
{
*p = calloc(sz, sizeof(char));
if (!(*p)) {
pp_errno = PP_OMEM;
if (!(*p))
return PP_FAILED;
}
return PP_OK;
}
int _add_sym_mapp_to_map(string_map_t define_map, char *sym_mapp)
int _add_sym_mapp_to_map(void *def_map, char *sym_mapp)
{
char *sym;
char *mapp;
@ -93,7 +92,7 @@ int _add_sym_mapp_to_map(string_map_t define_map, char *sym_mapp)
strncpy(sym, sym_mapp, sym_len);
res = hashmap_put(define_map, sym, mapp);
res = hashmap_put(def_map, sym, mapp);
if (res != MAP_OK)
return PP_FAILED;
@ -119,7 +118,7 @@ int _add_sym_mapp_to_map(string_map_t define_map, char *sym_mapp)
strncpy(mapp, eq_pos, mapp_len);
ret = hashmap_put(define_map, sym, mapp);
ret = hashmap_put(def_map, sym, mapp);
if (ret == MAP_OK)
return PP_OK;
@ -142,23 +141,29 @@ struct args *_create_struct_args(void)
if (!ret)
goto free_and_exit;
ret->inc_dirs = init_char_dyn_arr(2);
ret->inc_dirs = init_str_dyn_arr(2);
if (!(ret->inc_dirs))
goto free_and_exit;
return ret;
free_and_exit:
free_char_dyn_arr(ret->inc_dirs);
if (ret)
free_str_dyn_arr(ret->inc_dirs);
free(ret);
return NULL;
}
int _collect_inc_dirs(struct args *args, char *inc_dir)
{
char *a_inc_dir;
int res;
res = insert_char_dyn_arr(args->inc_dirs, inc_dir);
a_inc_dir = l_strdup(inc_dir);
if (!a_inc_dir)
return PP_FAILED;
res = insert_str_dyn_arr(args->inc_dirs, a_inc_dir);
if (res == CHAR_DYN_ARR_OK)
return PP_OK;
@ -202,7 +207,7 @@ int _add_out_file_to_args(struct args *args, char *out_file)
return PP_OK;
}
struct args *pp_parse_args(int argc, char **argv, string_map_t define_map)
struct args *pp_parse_args(int argc, char **argv, void *def_map)
{
struct args *args;
@ -224,14 +229,16 @@ struct args *pp_parse_args(int argc, char **argv, string_map_t define_map)
for (i = 0; i < argc; i++) {
is_flag = 0;
if (_is_unrecognized_flag(argv[i])) {
pp_errno = PP_BAD_ARGS;
if (_is_unrecognized_flag(argv[i]))
goto free_and_exit;
}
if (_is_split_define_flag(argv[i])) {
if (i + 1 < argc) {
res = _add_sym_mapp_to_map(define_map, argv[i + 1]);
res = _add_sym_mapp_to_map(
def_map,
argv[i + 1]
);
if (res == PP_FAILED)
goto free_and_exit;
is_flag = 1;
@ -245,7 +252,7 @@ struct args *pp_parse_args(int argc, char **argv, string_map_t define_map)
if (_is_tied_define_flag(argv[i])) {
sym_mapp = argv[i] + DEFINE_FLAG_SZ;
res = _add_sym_mapp_to_map(define_map, sym_mapp);
res = _add_sym_mapp_to_map(def_map, sym_mapp);
if (res == PP_FAILED)
goto free_and_exit;
is_flag = 1;
@ -279,22 +286,26 @@ struct args *pp_parse_args(int argc, char **argv, string_map_t define_map)
continue;
}
if (!is_flag && !in_file_found && i - 1 >= 0 && _is_in_out_file_arg(argv[i - 1])) {
if (!is_flag && !in_file_found && i - 1 >= 0
&& _is_in_out_file_arg(argv[i - 1])) {
res = _add_in_file_to_args(args, argv[i]);
if (res == PP_FAILED)
goto free_and_exit;
in_file_found = 1;
} else if (!is_flag && in_file_found && i - 1 >= 0 && _is_in_out_file_arg(argv[i - 1])) {
if (out_file_found) {
pp_errno = PP_BAD_ARGS;
} else if (!is_flag && in_file_found && i - 1 >= 0
&& _is_in_out_file_arg(argv[i - 1])) {
if (out_file_found)
goto free_and_exit;
}
res = _add_out_file_to_args(args, argv[i]);
if (res == PP_FAILED)
goto free_and_exit;
out_file_found = 1;
}
}
@ -310,8 +321,9 @@ void pp_free_args(struct args *args)
if (!args)
return;
free_char_dyn_arr(args->inc_dirs);
free_str_dyn_arr(args->inc_dirs);
free(args->in_file);
free(args->out_file);
free(args);
}

View File

@ -1,541 +1,86 @@
// SPDX-License-Identifier: BSD-2
#include "pp_define.h"
#include "pp_defines.h"
#include "pp_ifdef.h"
#include "line_handler.h"
#include "pp_line_id.h"
#include "utils.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#define DEFINE_LINE_START "#define"
#define DEFINE_LINE_START_SZ (sizeof(DEFINE_LINE_START) - 1)
#define UNDEF_LINE_START "#undef"
#define UNDEF_LINE_START_SZ (sizeof(UNDEF_LINE_START) - 1)
int _collect_sym_mapp(void *def_map, char *def_line);
char *_get_sym(char *def_line);
char *_get_mapp(char *def_line);
#define IF_LINE_START "#if"
#define IF_LINE_START_SZ (sizeof(IF_LINE_START) - 1)
#define IS_IF_LINE(line) (!strncmp(line, IF_LINE_START, IF_LINE_START_SZ))
#define DELIMS "\t []{}<>=+-*/%!&|^.,:;()\\"
#define TEMP_PRECOMP "temp"
#define TEMP_PRECOMP_1 "temp1"
int pp_errno = PP_OK;
int _is_define_line(char *line)
int collect_def(char *line, void *def_map, FILE *source)
{
return !strncmp(line, DEFINE_LINE_START, DEFINE_LINE_START_SZ);
}
int _is_undef_line(char *line)
{
return !strncmp(line, UNDEF_LINE_START, UNDEF_LINE_START_SZ);
}
int _get_next_whitespace_index(char *str)
{
int c;
c = 0;
while (!isspace(*str)) {
str++;
c++;
}
return c;
}
void _strip_extra_spaces_in_define(char *str)
{
int i;
int x;
int inside_quotes;
inside_quotes = 0;
for (i = x = 0; str[i]; i++) {
if (i > 0 && str[i] == '\"' && str[i - 1] != '\\' && !inside_quotes)
inside_quotes = 1;
else if (i > 0 && str[i] == '\"' && str[i - 1] != '\\' && inside_quotes)
inside_quotes = 0;
if (!inside_quotes && (!isspace(str[i]) || (i > 0 && !isspace(str[i - 1]))))
str[x++] = str[i];
else if (inside_quotes)
x++;
}
str[x] = 0x00;
}
char *_skip_word(char *str)
{
char *s;
s = str;
while (!isspace(*s++));
return s;
}
char *_get_symbol(char *define_line)
{
char *symbol;
int symbol_end_index;
define_line = _skip_word(define_line);
if (!(*define_line)) {
pp_errno = PP_BAD_DEFINE_SYMBOL;
return NULL;
}
symbol_end_index = _get_next_whitespace_index(define_line);
symbol = calloc(symbol_end_index + 1, sizeof(char));
if (!symbol) {
pp_errno = PP_OMEM;
return NULL;
}
strncpy(symbol, define_line, symbol_end_index);
return symbol;
}
char *_get_mapping(char *define_line)
{
char *mapping;
define_line = _skip_word(define_line);
if (!(*define_line)) {
pp_errno = PP_BAD_DEFINE_SYMBOL;
return NULL;
}
define_line = _skip_word(define_line);
if (!(*define_line)) {
pp_errno = PP_BAD_DEFINE_MAPPING;
return NULL;
}
mapping = calloc(strlen(define_line), sizeof(char));
if (!mapping) {
pp_errno = PP_OMEM;
return NULL;
}
strncpy(mapping, define_line, strlen(define_line) - 1);
return mapping;
}
int _add_symbol_mapping_to_hashmap(string_map_t *map, char *define_line)
{
int ret;
char *symbol;
char *mapping;
symbol = _get_symbol(define_line);
if (!symbol)
return PP_FAILED;
mapping = _get_mapping(define_line);
if (!mapping)
return PP_FAILED;
ret = hashmap_put(map, symbol, mapping);
if (ret == MAP_OMEM) {
pp_errno = PP_OMEM;
return PP_FAILED;
}
return PP_OK;
}
int _concat_str(char **str1, char *str2)
{
char *result;
char *temp;
int needed;
needed = strlen(*str1) + strlen(str2) + 1;
result = calloc(needed, sizeof(char));
if (!result) {
pp_errno = PP_OMEM;
return PP_FAILED;
}
sprintf(result, "%s%s", *str1, str2);
temp = *str1;
*str1 = result;
free(temp);
return PP_OK;
}
int _collect_multiline_define(string_map_t *map, char *define_line, FILE *f)
{
char *define_multiline;
char *line;
size_t len;
ssize_t read;
char *def_multiline;
char read_line[PP_LINE_LEN + 1];
int len;
int ret;
_strip_extra_spaces_in_define(define_line);
def_multiline = NULL;
len = strlen(line);
if (define_line[strlen(define_line) - 2] != '\\') {
ret = _add_symbol_mapping_to_hashmap(map, define_line);
strip_spaces_in_def(line);
if (line[len - 2] != '\\') {
ret = _collect_sym_mapp(def_map, line);
if (ret == PP_FAILED) {
ret = PP_FAILED;
goto free_and_exit;
}
} else {
define_multiline = strdup(define_line);
if (!define_multiline)
def_multiline = l_strdup(line);
if (!def_multiline)
return PP_FAILED;
line = NULL;
len = 0;
while (fgets(read_line, PP_LINE_LEN, source)) {
strip_spaces_in_def(read_line);
while ((read = getline(&line, &len, f)) != -1) {
_strip_extra_spaces_in_define(line);
len = strlen(def_multiline);
def_multiline[len - 2] = 0x00;
define_multiline[strlen(define_multiline) - 2] = 0x00;
_concat_str(&define_multiline, line);
ret = a_strcat(&def_multiline, read_line);
if (ret == -1) {
ret = PP_FAILED;
goto free_and_exit;
}
if (line[strlen(line) - 2] != '\\')
len = strlen(read_line);
if (read_line[len - 2] != '\\')
break;
}
free(line);
ret = _add_symbol_mapping_to_hashmap(map, define_multiline);
free(define_multiline);
}
return ret;
}
int pp_collect_defines(string_map_t map, FILE *f)
{
char *line;
size_t len;
ssize_t read;
int ret;
ret = PP_OK;
line = NULL;
len = 0;
while ((read = getline(&line, &len, f)) != -1) {
if (_is_define_line(line)) {
ret = _collect_multiline_define(map, line, f);
if (ret == PP_FAILED)
goto free_resources_and_exit;
}
}
free_resources_and_exit:
free(line);
return ret;
}
int _is_inside_multiline_define(char *curr_line)
{
static int is_inside;
if (_is_define_line(curr_line))
is_inside = 1;
if (is_inside && curr_line[strlen(curr_line) - 2] != '\\')
is_inside = 0;
return is_inside;
}
int _can_skip_multiline_define(int is_inside, int prev_is_inside)
{
return !(is_inside || (!is_inside && prev_is_inside));
}
int pp_create_file_without_defines(FILE *in, FILE *out)
{
char *line;
size_t len;
ssize_t read;
char *stripped_line;
int is_inside_multiline_define;
int prev_is_inside_multiline_define;
int fwritten_bytes;
int ret;
ret = PP_OK;
line = NULL;
len = 0;
is_inside_multiline_define = 0;
prev_is_inside_multiline_define = 0;
while ((read = getline(&line, &len, in)) != -1) {
stripped_line = strdup(line);
if (!stripped_line) {
pp_errno = PP_OMEM;
ret = _collect_sym_mapp(def_map, def_multiline);
if (ret == PP_FAILED) {
ret = PP_FAILED;
goto free_resources_and_exit;
}
prev_is_inside_multiline_define = is_inside_multiline_define;
is_inside_multiline_define = _is_inside_multiline_define(stripped_line);
free(stripped_line);
if (!_is_define_line(line)) {
if (_can_skip_multiline_define(is_inside_multiline_define, prev_is_inside_multiline_define)) {
fwritten_bytes = fprintf(out, "%s", line);
if (fwritten_bytes < 0 || fwritten_bytes != read) {
pp_errno = PP_BAD_FILE_OP;
ret = PP_FAILED;
goto free_resources_and_exit;
}
}
goto free_and_exit;
}
}
free_resources_and_exit:
free(line);
ret = PP_OK;
free_and_exit:
free(def_multiline);
return ret;
}
char *_get_expanded_token(string_map_t map, char *token)
{
char *expanded;
char *expanded_copy;
int res;
int size;
res = hashmap_get(map, token, &expanded);
if (res != MAP_OK) {
size = strlen(token);
expanded_copy = calloc(size + 1, sizeof(char));
if (!expanded_copy) {
pp_errno = PP_OMEM;
return NULL;
}
strcpy(expanded_copy, token);
} else {
expanded_copy = strdup(expanded);
if (!expanded_copy) {
pp_errno = PP_OMEM;
return NULL;
}
}
return expanded_copy;
}
int _concat_delim_to_line(char *delim, int delim_size, char **line)
{
char *d_delim;
char res;
d_delim = calloc(delim_size + 1, sizeof(char));
if (!d_delim) {
pp_errno = PP_OMEM;
return PP_FAILED;
}
strncpy(d_delim, delim, delim_size);
res = _concat_str(line, d_delim);
free(d_delim);
return res;
}
int _concat_expanded_token_to_line(string_map_t map, char *token, char **line)
{
char *expanded;
int res;
expanded = _get_expanded_token(map, token);
if (!expanded) {
pp_errno = PP_OMEM;
return PP_FAILED;
}
res = _concat_str(line, expanded);
free(expanded);
return res;
}
int _is_delim_at_str_start(char *token, char *str_start)
{
return token - str_start;
}
int _compute_delim_start(char *token, char *line)
{
return token - line + strlen(token);
}
int _compute_delim_end(char *token, char *line, char *line_copy)
{
return token != NULL ? token - line : (int) strlen(line_copy);
}
char *_compute_expanded_line(string_map_t map, char *line)
{
char *int_line;
char *line_start;
char *line_copy;
char *token;
char *expanded_line;
int delim_start;
int delim_end;
int res;
int token_len;
int_line = strdup(line);
if (!int_line) {
pp_errno = PP_OMEM;
return NULL;
}
line_start = int_line;
line_copy = strdup(int_line);
if (!line_copy) {
pp_errno = PP_OMEM;
return NULL;
}
expanded_line = calloc(1, sizeof(char));
if (!expanded_line) {
pp_errno = PP_OMEM;
return NULL;
}
token = strtok(int_line, DELIMS);
if (_is_delim_at_str_start(token, line_start)) {
res = _concat_delim_to_line(line_start, token - line_start, &expanded_line);
if (res == PP_FAILED)
return NULL;
}
res = _concat_expanded_token_to_line(map, token, &expanded_line);
if (res == PP_FAILED)
return NULL;
while (token) {
delim_start = _compute_delim_start(token, int_line);
token = strtok(NULL, DELIMS);
delim_end = _compute_delim_end(token, int_line, line_copy);
res = _concat_delim_to_line(line_copy + delim_start, delim_end - delim_start, &expanded_line);
if (res == PP_FAILED)
return NULL;
if (token) {
token_len = strlen(token);
if (token[token_len - 1] == '\n')
token[token_len - 1] = 0x00;
_concat_expanded_token_to_line(map, token, &expanded_line);
if (token[token_len - 1] == 0x00) {
token[token_len - 1] = '\n';
_concat_expanded_token_to_line(map, "\n", &expanded_line);
}
if (res == PP_FAILED)
return NULL;
} else {
break;
}
}
free(line_copy);
free(int_line);
return expanded_line;
}
char *_get_expanded_line(string_map_t map, char *line)
{
char *expanded_line;
char *prev_expanded_line;
expanded_line = _compute_expanded_line(map, line);
if (!expanded_line)
return NULL;
prev_expanded_line = strdup(line);
if (!prev_expanded_line) {
pp_errno = PP_OMEM;
return NULL;
}
while (strcmp(prev_expanded_line, expanded_line)) {
free(prev_expanded_line);
prev_expanded_line = expanded_line;
expanded_line = _compute_expanded_line(map, prev_expanded_line);
if (!expanded_line)
return NULL;
}
free(prev_expanded_line);
return expanded_line;
}
int _write_expanded_line(string_map_t map, char *line, FILE *out)
{
char *expanded_line;
int line_size;
int res;
expanded_line = _get_expanded_line(map, line);
if (!expanded_line)
return PP_FAILED;
line_size = strlen(expanded_line);
res = fprintf(out, "%s", expanded_line);
if (res < 0) {
pp_errno = PP_BAD_FILE_OP;
return PP_FAILED;
}
free(expanded_line);
return res == line_size ? PP_OK : PP_FAILED;
}
int _delete_sym_from_map(string_map_t *map, char *undef_line)
int apply_undef(char *line, void *map)
{
char *sym;
int sym_len;
int res;
int ret;
sym = undef_line + UNDEF_LINE_START_SZ + 1;
sym = line + UNDEF_LINE_START_SZ + 1;
sym_len = strlen(sym);
sym[sym_len - 1] = 0x00;
res = hashmap_del(map, sym);
if (res == MAP_BAD_ARGS) {
ret = hashmap_del(map, sym);
if (ret == MAP_BAD_ARGS) {
ret = PP_FAILED;
goto restore_undef_line_and_exit;
}
@ -547,98 +92,80 @@ restore_undef_line_and_exit:
return ret;
}
int pp_write_expanded_defines_to_file(string_map_t map, FILE *in, FILE *out)
{
char *line;
size_t len;
ssize_t read;
int ret;
ret = PP_OK;
line = NULL;
len = 0;
while ((read = getline(&line, &len, in)) != -1) {
if (_is_undef_line(line)) {
ret = _delete_sym_from_map(map, line);
if (ret == PP_FAILED)
goto free_resources_and_exit;
memcpy(line, "\n\x00", 2);
}
ret = _write_expanded_line(map, line, out);
if (ret == PP_FAILED)
goto free_resources_and_exit;
}
free_resources_and_exit:
free(line);
return ret;
}
char *pp_strerr(int pp_errno)
{
switch (pp_errno) {
case PP_BAD_DEFINE_SYMBOL:
return "bad define symbol";
case PP_BAD_DEFINE_MAPPING:
return "bad define mapping";
default:
return strerror(errno);
}
}
int pp_expand_defines(string_map_t define_map, FILE *source, FILE *output)
int _collect_sym_mapp(void *def_map, char *def_line)
{
int ret;
FILE *temp_precomp;
FILE *temp_precomp_1;
ret = pp_collect_defines(define_map, source);
if (ret != PP_OK)
return ret;
char *sym;
char *mapp;
ret = fseek(source, 0, SEEK_SET);
if (ret == -1) {
ret = PP_FAILED;
goto close_file_and_exit;
sym = NULL;
mapp = NULL;
sym = _get_sym(def_line);
if (!sym)
goto free_and_exit;
mapp = _get_mapp(def_line);
if (!mapp) {
mapp = calloc(1, sizeof(char));
if (!mapp)
goto free_and_exit;
a_strcat(&mapp, "");
}
temp_precomp = fopen(TEMP_PRECOMP, "w+");
if (!temp_precomp)
return PP_FAILED;
ret = hashmap_put(def_map, sym, mapp);
temp_precomp_1 = fopen(TEMP_PRECOMP_1, "w+");
if (!temp_precomp_1)
return PP_FAILED;
if (ret == MAP_OMEM)
goto free_and_exit;
ret = pp_create_file_without_defines(source, temp_precomp);
if (ret != PP_OK)
goto close_file_and_exit;
return PP_OK;
fseek(temp_precomp, 0, SEEK_SET);
if (ret == -1) {
ret = PP_FAILED;
goto close_file_and_exit;
}
ret = pp_expand_ifdefs(define_map, temp_precomp, temp_precomp_1);
if (ret != PP_OK)
goto close_file_and_exit;
fseek(temp_precomp_1, 0, SEEK_SET);
ret = pp_write_expanded_defines_to_file(define_map, temp_precomp_1, output);
if (ret != PP_OK)
goto close_file_and_exit;
ret = PP_OK;
close_file_and_exit:
fclose(temp_precomp);
fclose(temp_precomp_1);
remove(TEMP_PRECOMP);
remove(TEMP_PRECOMP_1);
return ret;
free_and_exit:
free(sym);
free(mapp);
return PP_FAILED;
}
char *_get_sym(char *def_line)
{
char *sym;
int sym_end_index;
def_line = skip_word(def_line);
if (!(*def_line))
return NULL;
sym_end_index = get_next_whitespace_idx(def_line);
sym = calloc(sym_end_index + 1, sizeof(char));
if (!sym)
return NULL;
strncpy(sym, def_line, sym_end_index);
return sym;
}
char *_get_mapp(char *def_line)
{
char *mapp;
int mapp_len;
def_line = skip_word(def_line);
if (!(*def_line))
return NULL;
def_line = skip_word(def_line);
if (!(*def_line))
return NULL;
mapp_len = strlen(def_line) - 1;
mapp = calloc(strlen(def_line) + 1, sizeof(char));
if (!mapp)
return NULL;
strncpy(mapp, def_line, mapp_len);
return mapp;
}

145
pp_if.c
View File

@ -1,72 +1,17 @@
// SPDX-License-Identifier: BSD-2
#include "pp_if.h"
#include "pp_defines.h"
#include "pp_line_id.h"
#include "line_handler.h"
#include "utils.h"
#include <string.h>
#include "expand_line.h"
#include <stdlib.h>
#define IF_LINE_START "#if "
#define IF_LINE_START_SZ (sizeof(IF_LINE_START) - 1)
#define IS_IF_LINE(line) (!strncmp(line, IF_LINE_START, IF_LINE_START_SZ))
#define ELSE_LINE_START "#else"
#define ELSE_LINE_START_SZ (sizeof(ELSE_LINE_START) - 1)
#define IS_ELSE_LINE(line) (!strncmp(line, ELSE_LINE_START, ELSE_LINE_START_SZ))
#define ELIF_LINE_START "#elif "
#define ELIF_LINE_START_SZ (sizeof(ELIF_LINE_START) - 1)
#define IS_ELIF_LINE(line) (!strncmp(line, ELIF_LINE_START, ELIF_LINE_START_SZ))
#define ENDIF_LINE_START "#endif"
#define ENDIF_LINE_START_SZ (sizeof(ENDIF_LINE_START) - 1)
#define IS_ENDIF_LINE(line) (!strncmp(line, ENDIF_LINE_START, ENDIF_LINE_START_SZ))
#define IS_CURR_BRANCH_END(line) (IS_ELSE_LINE(line) || IS_ELIF_LINE(line) || IS_ENDIF_LINE(line))
#define SKIP_UNTIL_CURR_BRANCH_END 1
#define SKIP_UNTIL_ENDIF_LINE 2
int _is_cond_null(char *cond_line)
{
char *cond;
if (!strncmp(cond_line, IF_LINE_START, IF_LINE_START_SZ))
cond = cond_line + IF_LINE_START_SZ;
else if (!strncmp(cond_line, ELIF_LINE_START, ELIF_LINE_START_SZ))
cond = cond_line + ELIF_LINE_START_SZ;
return cond[0] == '0'; // de schimbat
}
int _skip_until(FILE *f, int until)
int expand_if(void *def_map, const struct str_dyn_arr *inc_dirs, FILE *source,
FILE *out)
{
char line[PP_LINE_LEN + 1];
char *exp_line;
int line_len;
int res;
while (fgets(line, PP_LINE_LEN, f)) {
if (until == SKIP_UNTIL_CURR_BRANCH_END && IS_CURR_BRANCH_END(line))
break;
if (until == SKIP_UNTIL_ENDIF_LINE && IS_ENDIF_LINE(line))
break;
}
line_len = strlen(line);
res = fseek(f, -line_len, SEEK_CUR);
if (res == -1)
return PP_FAILED;
return PP_OK;
}
int _expand_if(FILE *source, FILE *output)
{
char line[PP_LINE_LEN + 1];
int res;
int ret;
int line_len;
int if_en;
int else_en;
@ -79,68 +24,62 @@ int _expand_if(FILE *source, FILE *output)
break;
if (if_en && (IS_ELSE_LINE(line) || IS_ELIF_LINE(line))) {
res = _skip_until(source, SKIP_UNTIL_ENDIF_LINE);
if (res == PP_FAILED)
return res;
ret = skip_until(source, SKIP_UNTIL_ENDIF_LINE);
if (ret == -1)
return PP_FAILED;
if_en = 0;
}
if (if_en || else_en) {
res = write_line_to_file(output, line);
if (res == -1)
return res;
ret = line_handler(
line,
def_map,
inc_dirs,
source,
out
);
if (ret == PP_FAILED)
return ret;
}
if (IS_IF_LINE(line) || IS_ELIF_LINE(line)) {
if (_is_cond_null(line)) {
res = _skip_until(source, SKIP_UNTIL_CURR_BRANCH_END);
if (res == PP_FAILED)
return res;
exp_line = get_expanded_line(def_map, line);
if (!exp_line)
return PP_FAILED;
if (is_cond_null(exp_line)) {
ret = skip_until(
source,
SKIP_UNTIL_CURR_BRANCH_END
);
if (ret == -1)
return PP_FAILED;
fgets(line, PP_LINE_LEN, source);
if (IS_ELSE_LINE(line)) {
else_en = 1;
} else {
line_len = strlen(line);
res = fseek(source, -line_len, SEEK_CUR);
ret = fseek(
source,
-line_len,
SEEK_CUR
);
if (res == -1)
if (ret == -1)
return PP_FAILED;
}
} else {
if_en = 1;
}
free(exp_line);
}
}
return PP_OK;
}
int pp_expand_ifs(FILE *source, FILE *output)
{
char line[PP_LINE_LEN + 1];
int res;
int line_len;
while (fgets(line, PP_LINE_LEN, source)) {
if (IS_IF_LINE(line)) {
line_len = strlen(line);
res = fseek(source, -line_len, SEEK_CUR);
if (res == -1)
return PP_FAILED;
_expand_if(source, output);
} else {
res = write_line_to_file(output, line);
if (res == -1)
return PP_FAILED;
}
}
return PP_OK;
}

View File

@ -1,89 +1,20 @@
// SPDX-License-Identifier: BSD-2
#include "pp_ifdef.h"
#include "pp_defines.h"
#include "expand_line.h"
#include "utils.h"
#include "hashmap.h"
#include <stdio.h>
#include <string.h>
#include "pp_line_id.h"
#include "line_handler.h"
#include <stdlib.h>
#define IFDEF_LINE_START "#ifdef "
#define IFDEF_LINE_START_SZ (sizeof(IFDEF_LINE_START) - 1)
#define IS_IFDEF_LINE(line) (!strncmp(line, IFDEF_LINE_START, IFDEF_LINE_START_SZ))
int _is_sym_defined(void *def_map, char *ifdef_line);
#define ELSE_LINE_START "#else"
#define ELSE_LINE_START_SZ (sizeof(ELSE_LINE_START) - 1)
#define IS_ELSE_LINE(line) (!strncmp(line, ELSE_LINE_START, ELSE_LINE_START_SZ))
#define IFNDEF_LINE_START "#ifndef "
#define IFNDEF_LINE_START_SZ (sizeof(IFNDEF_LINE_START) - 1)
#define IS_IFNDEF_LINE(line) (!strncmp(line, IFNDEF_LINE_START, IFNDEF_LINE_START_SZ))
#define ENDIF_LINE_START "#endif"
#define ENDIF_LINE_START_SZ (sizeof(ENDIF_LINE_START) - 1)
#define IS_ENDIF_LINE(line) (!strncmp(line, ENDIF_LINE_START, ENDIF_LINE_START_SZ))
#define IS_CURR_BRANCH_END(line) (IS_ELSE_LINE(line) || IS_ENDIF_LINE(line))
#define SKIP_UNTIL_CURR_BRANCH_END 1
#define SKIP_UNTIL_ENDIF_LINE 2
int _is_sym_defined(string_map_t define_map, char *ifdef_line)
{
char *sym;
char *mapp;
int sym_len;
int res;
if (!strncmp(ifdef_line, IFDEF_LINE_START, IFDEF_LINE_START_SZ))
sym = ifdef_line + IFDEF_LINE_START_SZ;
else if (!strncmp(ifdef_line, IFNDEF_LINE_START, IFNDEF_LINE_START_SZ))
sym = ifdef_line + IFNDEF_LINE_START_SZ;
sym_len = strlen(sym);
sym[sym_len - 1] = 0x00;
res = hashmap_get(define_map, sym, &mapp);
if (res == MAP_BAD_ARGS)
goto restore_line_and_exit;
return res == MAP_OK && mapp;
restore_line_and_exit:
sym[sym_len - 1] = '\n';
return -1;
}
int _ifdef_skip_until(FILE *f, int until)
int expand_ifdef(void *def_map, const struct str_dyn_arr *inc_dirs,
FILE *source, FILE *out)
{
char line[PP_LINE_LEN + 1];
char *exp_line;
int line_len;
int res;
while (fgets(line, PP_LINE_LEN, f)) {
if (until == SKIP_UNTIL_CURR_BRANCH_END && IS_CURR_BRANCH_END(line))
break;
if (until == SKIP_UNTIL_ENDIF_LINE && IS_ENDIF_LINE(line))
break;
}
line_len = strlen(line);
res = fseek(f, -line_len, SEEK_CUR);
if (res == -1)
return PP_FAILED;
return PP_OK;
}
int _expand_ifdef(string_map_t define_map, FILE *source, FILE *output)
{
char line[PP_LINE_LEN + 1];
int res;
int ret;
int line_len;
int if_en;
int else_en;
@ -96,88 +27,142 @@ int _expand_ifdef(string_map_t define_map, FILE *source, FILE *output)
break;
if (if_en && IS_ELSE_LINE(line)) {
res = _ifdef_skip_until(source, SKIP_UNTIL_ENDIF_LINE);
if (res == PP_FAILED)
return res;
ret = skip_until(source, SKIP_UNTIL_ENDIF_LINE);
if (ret == -1)
return PP_FAILED;
if_en = 0;
continue;
}
if (if_en || else_en) {
res = write_line_to_file(output, line);
if (res == -1)
return res;
ret = line_handler(
line,
def_map,
inc_dirs,
source,
out
);
if (ret == PP_FAILED)
return ret;
continue;
}
if (IS_IFDEF_LINE(line)) {
if (!_is_sym_defined(define_map, line)) {
res = _ifdef_skip_until(source, SKIP_UNTIL_CURR_BRANCH_END);
if (res == PP_FAILED)
return res;
exp_line = get_expanded_line(def_map, line);
if (!exp_line)
return PP_FAILED;
if (!_is_sym_defined(def_map, line)) {
ret = skip_until(
source,
SKIP_UNTIL_CURR_BRANCH_END
);
if (ret == -1)
return PP_FAILED;
fgets(line, PP_LINE_LEN, source);
if (IS_ELSE_LINE(line)) {
else_en = 1;
} else {
line_len = strlen(line);
res = fseek(source, -line_len, SEEK_CUR);
ret = fseek(
source,
-line_len,
SEEK_CUR
);
if (res == -1)
if (ret == -1)
return PP_FAILED;
}
} else {
if_en = 1;
}
free(exp_line);
continue;
}
if (IS_IFNDEF_LINE(line)) {
if (_is_sym_defined(define_map, line)) {
res = _ifdef_skip_until(source, SKIP_UNTIL_CURR_BRANCH_END);
if (res == PP_FAILED)
return res;
exp_line = get_expanded_line(def_map, line);
if (!exp_line)
return PP_FAILED;
if (_is_sym_defined(def_map, line)) {
ret = skip_until(
source,
SKIP_UNTIL_CURR_BRANCH_END
);
if (ret == -1)
return PP_FAILED;
fgets(line, PP_LINE_LEN, source);
if (IS_ELSE_LINE(line)) {
else_en = 1;
} else {
line_len = strlen(line);
res = fseek(source, -line_len, SEEK_CUR);
ret = fseek(
source,
-line_len,
SEEK_CUR
);
if (res == -1)
if (ret == -1)
return PP_FAILED;
}
} else {
if_en = 1;
}
}
free(exp_line);
continue;
}
}
return PP_OK;
}
int pp_expand_ifdefs(string_map_t define_map, FILE *source, FILE *output)
int _is_sym_defined(void *def_map, char *ifdef_line)
{
char line[PP_LINE_LEN + 1];
char *sym;
char *mapp;
int res;
int line_len;
int sym_len;
int ret;
while (fgets(line, PP_LINE_LEN, source)) {
if (IS_IFDEF_LINE(line) || IS_IFNDEF_LINE(line)) {
line_len = strlen(line);
sym = NULL;
mapp = NULL;
res = fseek(source, -line_len, SEEK_CUR);
if (res == -1)
return PP_FAILED;
if (!strncmp(ifdef_line, IFDEF_LINE_START, IFDEF_LINE_START_SZ))
sym = ifdef_line + IFDEF_LINE_START_SZ;
else if (!strncmp(ifdef_line, IFNDEF_LINE_START, IFNDEF_LINE_START_SZ))
sym = ifdef_line + IFNDEF_LINE_START_SZ;
_expand_ifdef(define_map, source, output);
} else {
res = write_line_to_file(output, line);
if (res == -1)
return PP_FAILED;
}
if (!sym)
return 0;
sym_len = strlen(sym);
sym[sym_len - 1] = 0x00;
ret = hashmap_get(def_map, sym, &mapp);
if (ret == MAP_BAD_ARGS) {
ret = 0;
goto rettore_line_and_exit;
}
return PP_OK;
ret = ret == MAP_OK && mapp;
rettore_line_and_exit:
sym[sym_len - 1] = '\n';
return ret;
}

97
pp_inc.c Normal file
View File

@ -0,0 +1,97 @@
#include "pp_inc.h"
#include "pp_line_id.h"
#include "utils.h"
#include "pp.h"
#include <string.h>
#include <stdlib.h>
char *_get_filename_from_inc(char *inc);
int _compute_inc_file(void *def_map, const struct str_dyn_arr *inc_dirs,
char *inc_filename, FILE *out);
int expand_inc(void *def_map, const struct str_dyn_arr *inc_dirs, FILE *source,
FILE *out)
{
char line[PP_LINE_LEN + 1];
char *fgets_ret;
char *inc_filename;
char *full_inc_filename;
int i;
int ret;
fgets_ret = fgets(line, PP_LINE_LEN, source);
if (!fgets_ret)
return PP_FAILED;
inc_filename = _get_filename_from_inc(line);
full_inc_filename = l_strdup("_test/inputs/");
if (!full_inc_filename)
return PP_FAILED;
a_strcat(&full_inc_filename, inc_filename);
ret = _compute_inc_file(def_map, inc_dirs, full_inc_filename, out);
free(full_inc_filename);
if (ret == PP_OK)
return PP_OK;
for (i = 0; i < inc_dirs->used; i++) {
full_inc_filename = l_strdup(inc_dirs->data[i]);
if (!full_inc_filename)
return PP_FAILED;
a_strcat(&full_inc_filename, "/");
a_strcat(&full_inc_filename, inc_filename);
ret = _compute_inc_file(
def_map,
inc_dirs,
full_inc_filename,
out
);
free(full_inc_filename);
if (ret == PP_OK)
return PP_OK;
}
return PP_FAILED;
}
char *_get_filename_from_inc(char *inc)
{
char *filename;
int filename_len;
filename = inc;
filename += INC_LINE_START_SZ + 1;
filename += 1;
filename_len = strlen(filename);
filename[filename_len - 2] = 0x00;
return filename;
}
int _compute_inc_file(void *def_map, const struct str_dyn_arr *inc_dirs,
char *inc_filename, FILE *out)
{
FILE *inc_file;
int ret;
inc_file = fopen(inc_filename, "rb");
if (inc_file) {
ret = pp_compute(def_map, inc_dirs, inc_file, out);
fclose(inc_file);
return ret == PP_OK ? PP_OK : PP_FAILED;
}
return PP_FAILED;
}

BIN
run.exe Executable file

Binary file not shown.

37
run_all.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/bash
#
# Tema1 Test Suite
#
# 2020, Operating Systems
#
first_test=0
last_test=38
script=./_test/run_test.sh
# Call init to set up testing environment
bash "$script" init
# check the source (disabled, part of tests now)
#bash "$script" check
for i in $(seq $first_test $last_test); do
bash "$script" $i
done | tee results.txt
cat results.txt | grep -a '\[.*\]$' | awk -F '[] /[]+' '
BEGIN {
sum=0
}
{
sum += $(NF-2);
}
END {
printf "\n%66s [%02d/95]\n", "Total:", sum;
}'
# Cleanup testing environment
bash "$script" cleanup
rm -f results.txt

View File

@ -1,5 +1,4 @@
// SPDX-License-Identifier: BSD-2
/* SPDX-License-Identifier: BSD-2 */
#include "hashmap.h"
#include "pp.h"
#include "pp_defines.h"
@ -7,43 +6,41 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv)
{
string_map_t define_map;
void *def_map;
struct args *args;
FILE *in;
FILE *source;
FILE *out;
int ret;
define_map = NULL;
def_map = NULL;
args = NULL;
in = NULL;
source = NULL;
out = NULL;
define_map = hashmap_new();
args = pp_parse_args(argc, argv, define_map);
def_map = hashmap_new();
args = pp_parse_args(argc, argv, def_map);
if (!args) {
if (errno) {
if (errno)
ret = errno;
goto free_and_exit;
}
if (pp_errno != PP_OK) {
ret = pp_errno;
goto free_and_exit;
}
else
ret = PP_FAILED;
goto free_and_exit;
}
if (args->in_file) {
in = fopen(args->in_file, "r");
if (!in) {
source = fopen(args->in_file, "rb");
if (!source) {
ret = errno;
goto free_and_exit;
}
} else {
in = stdin;
source = stdin;
}
if (args->out_file) {
@ -56,20 +53,31 @@ int main(int argc, char **argv)
out = stdout;
}
ret = pp_start(define_map, in, out);
if (ret != PP_OK)
ret = pp_compute(def_map, args->inc_dirs, source, out);
if (ret == PP_FAILED && errno == ENOMEM) {
ret = ENOMEM;
goto free_and_exit;
}
if (ret == PP_OK && errno == ENOENT) {
ret = PP_OK;
goto free_and_exit;
}
if (ret == PP_FAILED)
goto free_and_exit;
ret = errno;
free_and_exit:
hashmap_free(define_map);
hashmap_free(def_map);
pp_free_args(args);
if (in)
fclose(in);
if (source)
fclose(source);
if (out)
fclose(out);
return ret;
}

View File

@ -1,16 +1,16 @@
// SPDX-License-Identifier: BSD-2
/* SPDX-License-Identifier: BSD-2 */
#include "char_dyn_arr.h"
#include "str_dyn_arr.h"
#include <errno.h>
#include <stdlib.h>
struct char_dyn_arr *init_char_dyn_arr(int size)
struct str_dyn_arr *init_str_dyn_arr(int size)
{
struct char_dyn_arr *a;
struct str_dyn_arr *a;
a = NULL;
a = calloc(1, sizeof(struct char_dyn_arr));
a = calloc(1, sizeof(struct str_dyn_arr));
if (!a)
goto free_and_exit;
@ -24,13 +24,14 @@ struct char_dyn_arr *init_char_dyn_arr(int size)
return a;
free_and_exit:
if (a)
free(a->data);
free(a);
free(a->data);
return NULL;
}
int insert_char_dyn_arr(struct char_dyn_arr *a, char *e)
int insert_str_dyn_arr(struct str_dyn_arr *a, char *e)
{
if (a->used == a->size) {
a->size *= 2;
@ -50,7 +51,7 @@ free_and_exit:
return CHAR_DYN_ARR_FAILED;
}
extern void free_char_dyn_arr(struct char_dyn_arr *a)
extern void free_str_dyn_arr(struct str_dyn_arr *a)
{
int i;

135
utils.c
View File

@ -1,6 +1,10 @@
#include "utils.h"
#include "pp_defines.h"
#include "pp_line_id.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int write_line_to_file(FILE *f, char *line)
{
@ -16,3 +20,134 @@ int write_line_to_file(FILE *f, char *line)
return 0;
}
char *l_strdup(char *s)
{
int size;
char *p;
if (!s)
return NULL;
size = strlen(s) + 1;
p = calloc(size, sizeof(char));
if (p)
memcpy(p, s, size);
return p;
}
void strip_spaces_in_def(char *def)
{
int i;
int x;
int in_quotes;
in_quotes = 0;
for (i = x = 0; def[i]; i++) {
if (i > 0 && def[i] == '\"' && def[i - 1] != '\\' && !in_quotes)
in_quotes = 1;
else if (i > 0 && def[i] == '\"' && def[i - 1] != '\\'
&& in_quotes)
in_quotes = 0;
if (!in_quotes && (!isspace(def[i]) || (i > 0
&& !isspace(def[i - 1]))))
def[x++] = def[i];
else if (in_quotes)
x++;
}
def[x] = 0x00;
}
int a_strcat(char **dest, char *src)
{
char *result;
char *temp;
int needed;
needed = strlen(*dest) + strlen(src) + 1;
result = calloc(needed, sizeof(char));
if (!result)
return -1;
sprintf(result, "%s%s", *dest, src);
temp = *dest;
*dest = result;
free(temp);
return 0;
}
int get_next_whitespace_idx(char *s)
{
int c;
c = 0;
while (!isspace(*s)) {
s++;
c++;
}
return c;
}
char *skip_word(char *s)
{
char *_s;
_s = s;
while (!isspace(*_s))
_s++;
_s++;
return _s;
}
int is_cond_null(char *cond_line)
{
char *cond;
cond = NULL;
if (!strncmp(cond_line, IF_LINE_START, IF_LINE_START_SZ))
cond = cond_line + IF_LINE_START_SZ;
else if (!strncmp(cond_line, ELIF_LINE_START, ELIF_LINE_START_SZ))
cond = cond_line + ELIF_LINE_START_SZ;
if (!cond)
return 0;
return cond[0] == '0';
}
int skip_until(FILE *f, int until)
{
char line[PP_LINE_LEN + 1];
int line_len;
int res;
while (fgets(line, PP_LINE_LEN, f)) {
if (until == SKIP_UNTIL_CURR_BRANCH_END
&& IS_IF_CURR_BRANCH_END(line))
break;
if (until == SKIP_UNTIL_ENDIF_LINE && IS_ENDIF_LINE(line))
break;
}
line_len = strlen(line);
res = fseek(f, -line_len, SEEK_CUR);
if (res == -1)
return -1;
return 0;
}