remove stuff till HS21, backup at other branch
This commit is contained in:
parent
accc615d03
commit
0765adb9ed
|
@ -1,52 +0,0 @@
|
|||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
319
Doxyfile
319
Doxyfile
|
@ -1,319 +0,0 @@
|
|||
# Doxyfile 1.8.11
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "SNP - Labs"
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY =
|
||||
CREATE_SUBDIRS = NO
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF =
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES =
|
||||
TCL_SUBST =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
AUTOLINK_SUPPORT = YES
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
CITE_BIB_FILES =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = .
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.h *.c *.dox
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = test*/*
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
SOURCE_TOOLTIPS = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
CLANG_OPTIONS =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = doc
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
MATHJAX_EXTENSIONS =
|
||||
MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHENGINE_URL =
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
EXTERNAL_SEARCH_ID =
|
||||
EXTRA_SEARCH_MAPPINGS =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_STYLESHEET =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
RTF_SOURCE_CODE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_SUBDIR =
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the DOCBOOK output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_DOCBOOK = NO
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
DOCBOOK_PROGRAMLISTING = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = NO
|
||||
COLLABORATION_GRAPH = NO
|
||||
GROUP_GRAPHS = NO
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = NO
|
||||
INCLUDED_BY_GRAPH = NO
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = NO
|
||||
DIRECTORY_GRAPH = NO
|
||||
DOT_IMAGE_FORMAT = png
|
||||
INTERACTIVE_SVG = NO
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
PLANTUML_JAR_PATH =
|
||||
PLANTUML_INCLUDE_PATH =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = NO
|
||||
DOT_CLEANUP = NO
|
32
Makefile
32
Makefile
|
@ -1,32 +0,0 @@
|
|||
EMPTY :=
|
||||
SPACE := $(EMPTY) $(EMPTY)
|
||||
NL := $(EMPTY)\\n$(EMPTY)
|
||||
|
||||
LABS := $(sort $(wildcard P[0-9][0-9]*))
|
||||
EXAMPLE := $(if $(firstword $(LABS)),$(firstword $(LABS)),"Pxx")
|
||||
|
||||
default:
|
||||
@echo "**** SNP Labs ****"
|
||||
@echo "$(subst $(SPACE),$(NL),$(LABS))"
|
||||
@echo ""
|
||||
@echo "**** Prerequisites ****"
|
||||
@echo "1. Change into the testlib directory"
|
||||
@echo " cd testlib"
|
||||
@echo "2. Build and install the library, e.g."
|
||||
@echo " make clean"
|
||||
@echo " make default"
|
||||
@echo " make test"
|
||||
@echo " make install"
|
||||
@echo " Caution: make sure the tests and installation does not produce any error."
|
||||
@echo ""
|
||||
@echo "**** How to build and run a lab? ****"
|
||||
@echo "1. Change into the respective directory, e.g."
|
||||
@echo " cd $(EXAMPLE)"
|
||||
@echo "2. Build the lab, e.g."
|
||||
@echo " make"
|
||||
@echo " The resulting executable is located in the bin folder."
|
||||
@echo "3. Build and run the tests, e.g."
|
||||
@echo " make test"
|
||||
@echo "Notes:"
|
||||
@echo "- You may cleanup the builds, e.g."
|
||||
@echo " make clean"
|
Binary file not shown.
|
@ -1,26 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# produces a tabular output of all executables as found over the $PATH environment variable
|
||||
# - output format: [1-based index of $PATH entry]:[$PATH entry]:[name of the executable]
|
||||
# - e.g. 6:/bin:bash
|
||||
# - the first argument (if given) is used as alternative to $PATH (e.g. for testing purposes)
|
||||
# usage: ./get-exec-list-arg.sh # examines $PATH
|
||||
# usage: ./get-exec-list-arg.sh "$PATH" # equivalent to the above call
|
||||
# usage: ./get-exec-list-arg.sh ".:~/bin" # examines the current directory (.) and ~/bin
|
||||
|
||||
# argument handling
|
||||
path="$1"
|
||||
[ -n "$path" ] || path="$PATH"
|
||||
|
||||
# input-field-separator: tells the shell to split in the 'for' loop the $var by ":"
|
||||
IFS=":"
|
||||
|
||||
for p in $path
|
||||
do
|
||||
i=$((i+1))
|
||||
[ -n "$p" ] || p="."
|
||||
if [ -d "$p" ] && [ -x "$p" ]
|
||||
then
|
||||
find -L "$p" -maxdepth 1 -type f -executable -printf "$i:%h:%f\n" 2>/dev/null
|
||||
fi
|
||||
done
|
|
@ -1,35 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# produces a crude HTML table from a tabular file (given on stdin) with columns separated by ":"
|
||||
# usage: tab2html < inbut.txt > output.html
|
||||
|
||||
awk $* -- '
|
||||
BEGIN {
|
||||
FS=":" # field-separator: which character separats fields in a record (i.e. in a line)
|
||||
print "<!DOCTYPE html>"
|
||||
print "<html>"
|
||||
print " <head>"
|
||||
print " <style>"
|
||||
print " table{border:1px solid black;border-collapse:collapse;}"
|
||||
print " tr:nth-child(even){background-color: #f2f2f2;}"
|
||||
print " td{border:1px solid black;padding:15px;}"
|
||||
print " </style>"
|
||||
print " <title>Tabular Data</title>"
|
||||
print " </head>"
|
||||
print " <body>"
|
||||
print " <div style=\"overflow-x:auto;\">"
|
||||
print " <table>"
|
||||
}
|
||||
{
|
||||
print " <tr>"
|
||||
for (i = 1; i <= NF; i++) { print " <td>"$i"</td>" }
|
||||
print " </tr>"
|
||||
}
|
||||
END {
|
||||
print " </table>"
|
||||
print " </div>"
|
||||
print " </body>"
|
||||
print "</html>"
|
||||
}
|
||||
'
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# produces an XML file from a tabular file (given on stdin) with columns separated by ":"
|
||||
# usage: tab2xml < inbut.txt > output.xml
|
||||
|
||||
awk $* -- '
|
||||
BEGIN {
|
||||
FS=":" # field-separator: which character separats fields in a record (i.e. in a line)
|
||||
print "<?xml version=\"1.0\" standalone=\"yes\"?>"
|
||||
print "<Table>"
|
||||
}
|
||||
{
|
||||
print " <Row>"
|
||||
for (i = 1; i <= NF; i++) { print " <Col>"$i"</Col>" }
|
||||
print " </Row>"
|
||||
}
|
||||
END {
|
||||
print "</Table>"
|
||||
}
|
||||
'
|
||||
|
Binary file not shown.
|
@ -1,7 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/term-qr-code
|
||||
SOURCES := src/main.c
|
||||
TSTSOURCES := tests/tests.c
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P02 QR Code
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab to display a QR code on the color terminal.
|
||||
*
|
||||
*/
|
|
@ -1,35 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab P02 QR Code
|
||||
* @remark prerequisite: sudo apt install qrencode
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// define local macros
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @returns always success (0)
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
############## ######## ##############
|
||||
## ## ## ## ##
|
||||
## ###### ## #### ## ###### ##
|
||||
## ###### ## ###### ## ###### ##
|
||||
## ###### ## ## ## ## ###### ##
|
||||
## ## #### ## ##
|
||||
############## ## ## ## ##############
|
||||
######
|
||||
#### #### ## ######## ## ##
|
||||
## ## ## ## ## ##
|
||||
## #### #### #### ## ## ##
|
||||
## ######## ######
|
||||
## #### #### ## #### ######
|
||||
###### ## ## ## ## ##
|
||||
############## ###### ####
|
||||
## ## ## ## ####
|
||||
## ###### ## ############ ## ######
|
||||
## ###### ## ## #### ##
|
||||
## ###### ## #### #### #### ####
|
||||
## ## ## #### ######
|
||||
############## ############ ## ##
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
/// @brief The input data
|
||||
#define SNP_INPUT "snp.input"
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
|
||||
/// @brief Reset
|
||||
#define N "\033[0m\n"
|
||||
/// @brief Black
|
||||
#define X "\033[40m "
|
||||
/// @brief White
|
||||
#define _ "\033[47m "
|
||||
|
||||
// tests
|
||||
static void test_empty_input(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] =
|
||||
{ N
|
||||
, N
|
||||
};
|
||||
const char *err_txt[] = { NULL };
|
||||
// act
|
||||
int exit_code = system(XSTR(TARGET) "</dev/null 1>" OUTFILE " 2>" ERRFILE);
|
||||
// assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(exit_code), EXIT_SUCCESS);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
static void test_black_and_white_input(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] =
|
||||
{ N
|
||||
, _ X _ N
|
||||
, N
|
||||
};
|
||||
const char *err_txt[] = { NULL };
|
||||
// act
|
||||
int exit_code = system("echo ' # ' | " XSTR(TARGET) " 1>" OUTFILE " 2>" ERRFILE);
|
||||
// assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(exit_code), EXIT_SUCCESS);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
static void test_snp_input(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] =
|
||||
{ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X X X X X X X X X X X X X _ _ X X X X X X X X _ _ _ _ X X X X X X X X X X X X X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ X X X X X X _ _ X X _ _ _ _ X X X X _ _ _ _ _ _ X X _ _ X X X X X X _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ X X X X X X _ _ X X _ _ _ _ _ _ X X X X X X _ _ X X _ _ X X X X X X _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ X X X X X X _ _ X X _ _ _ _ _ _ X X _ _ X X _ _ X X _ _ X X X X X X _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ X X X X _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X X X X X X X X X X X X X _ _ X X _ _ X X _ _ X X _ _ X X X X X X X X X X X X X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ X X X X X X _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X X X _ _ X X X X _ _ X X _ _ _ _ X X X X X X X X _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ X X _ _ X X _ _ _ _ _ _ _ _ X X _ _ X X _ _ X X _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ X X X X _ _ X X X X _ _ X X X X _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ X X _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ _ _ _ _ X X X X X X X X _ _ _ _ X X X X X X _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ X X X X _ _ X X X X _ _ _ _ X X _ _ _ _ X X X X _ _ X X X X X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ X X X X X X _ _ X X _ _ X X _ _ X X _ _ X X _ _ X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X X X X X X X X X X X X X _ _ _ _ _ _ _ _ _ _ X X X X X X _ _ X X X X _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ X X _ _ X X X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ X X X X X X _ _ X X _ _ X X X X X X X X X X X X _ _ _ _ X X _ _ X X X X X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ X X X X X X _ _ X X _ _ X X _ _ _ _ _ _ X X X X _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ X X X X X X _ _ X X _ _ _ _ X X X X _ _ X X X X _ _ _ _ X X X X _ _ X X X X _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ X X _ _ X X _ _ _ _ _ _ _ _ _ _ X X X X _ _ X X X X X X _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ X X X X X X X X X X X X X X _ _ X X X X X X X X X X X X _ _ _ _ X X _ _ _ _ X X _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ N
|
||||
, N
|
||||
};
|
||||
const char *err_txt[] = { NULL };
|
||||
// act
|
||||
int exit_code = system(XSTR(TARGET) "<" SNP_INPUT " 1>" OUTFILE " 2>" ERRFILE);
|
||||
// assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(exit_code), EXIT_SUCCESS);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_empty_input
|
||||
, test_black_and_white_input
|
||||
, test_snp_input
|
||||
);
|
||||
|
||||
}
|
Binary file not shown.
|
@ -1,8 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/boundinbox
|
||||
SOURCES := src/main.c
|
||||
TSTSOURCES := tests/tests.c
|
||||
LIBS := -lm
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P03 Calculate bounding box
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab to calculate the bounding box of some triangle and to compare the boxes
|
||||
*
|
||||
*/
|
|
@ -1,209 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab P03 weekday
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/// @brief point of two coordinate axes
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
/// @brief box with an origin point and a dimension w and h
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
/// @brief triangle given by three points a, b, and c
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
/**
|
||||
* @brief Compares two double values with a given hard coded tolerance.
|
||||
* @param [in] a the first value
|
||||
* @param [in] b the second value
|
||||
* @returns 0 if fabs(a-b) <= tolerance, -1 if a < b, 1 otherwise
|
||||
* @remark the tolerance is expected to be 0.05 (internally hard coded)
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares two box parameters for their area (w * h of the box).
|
||||
* @param [in] a the first box
|
||||
* @param [in] b the second box
|
||||
* @returns the return value from compare_double() when given the areas of both boxes as parameter to compare_double()
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares the area of the parameter against 0.
|
||||
* @param [in] box the box to check against area 0
|
||||
* @returns compare_double() == 0 with the boxes area and 0 as parameters
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief Calculates the bounding box of a triangle
|
||||
* @param [in] t the trinagle for which the baounding box is to be calculated
|
||||
* @returns the bounding box of the triangle
|
||||
* @remark calculates first the point with the minimum x and y of the triangle's points,
|
||||
* plus as second point the one with the max coordinates of all points
|
||||
* @remark the minial point is the origin of the bounding box, the width and hight is the x/y delta of the two points
|
||||
*
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// forward declaration of used functions in main()
|
||||
static box_t get_match(box_t board, triangle_t t);
|
||||
static triangle_t triangle_rotate(triangle_t t, double degree);
|
||||
static void write_data(box_t board, triangle_t t, int degree);
|
||||
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @param argc [in] number of entries in argv
|
||||
* @param argv [in] program name plus command line arguments
|
||||
* @returns returns success if valid date is given, failure otherwise
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int x1, x2, x3, y1, y2, y3;
|
||||
if (argc < 2 || sscanf(argv[1], "%d/%d-%d/%d-%d/%d", &x1, &y1, &x2, &y2, &x3, &y3) != 6) {
|
||||
fprintf(stderr, "Usage: %s x1/y1-x2/y2-x3/y3\ne.g. 0/0-100/0-50/50\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
|
||||
}
|
||||
|
||||
box_t board = { { 0, 0 }, 100, 200 };
|
||||
|
||||
// rotate the triangle in steps of 1 degree to find the "best position" of the triangle in the board
|
||||
triangle_t t = { { x1, y1 }, { x2, y2 }, { x3, y3 } };
|
||||
int degree_best = -1;
|
||||
box_t best;
|
||||
for(int degree = 0; degree < 360; degree++) {
|
||||
box_t match = get_match(board, triangle_rotate(t, degree));
|
||||
if (!is_zero_area(match)) {
|
||||
if (degree_best == -1 || compare_area(match, best) < 0) {
|
||||
degree_best = degree;
|
||||
best = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write as tabular file
|
||||
write_data(board, t, degree_best);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/****************** internal functions ********************/
|
||||
|
||||
// forward declarations
|
||||
static point_t point_rotate(point_t p, double degree);
|
||||
static point_t point_move(point_t p, double dx, double dy);
|
||||
static triangle_t triangle_move(triangle_t t, double dx, double dy);
|
||||
|
||||
|
||||
static box_t get_match(box_t board, triangle_t t)
|
||||
{
|
||||
box_t b = triangle_bounding_box(t);
|
||||
if (compare_double(board.w, b.w) < 0) return (box_t){ board.p, 0, 0 };
|
||||
if (compare_double(board.h, b.h) < 0) return (box_t){ board.p, 0, 0 };
|
||||
return (box_t){ board.p, b.w, b.h };
|
||||
}
|
||||
|
||||
static triangle_t triangle_rotate(triangle_t t, double degree)
|
||||
{
|
||||
return (triangle_t){ point_rotate(t.a, degree), point_rotate(t.b, degree), point_rotate(t.c, degree) };
|
||||
}
|
||||
|
||||
static triangle_t triangle_move(triangle_t t, double dx, double dy)
|
||||
{
|
||||
return (triangle_t){ point_move(t.a, dx, dy), point_move(t.b, dx, dy), point_move(t.c, dx, dy) };
|
||||
}
|
||||
|
||||
static point_t point_rotate(point_t p, double degree)
|
||||
{
|
||||
double rad = fmod(degree, 360.0) * acos(-1.0) / 180.0;
|
||||
double s = sin(rad);
|
||||
double c = cos(rad);
|
||||
|
||||
return (point_t){ c*p.x - s*p.y, s*p.x + c*p.y };
|
||||
}
|
||||
|
||||
static point_t point_move(point_t p, double dx, double dy)
|
||||
{
|
||||
return (point_t) { p.x+dx, p.y+dy };
|
||||
}
|
||||
|
||||
static void write_data(box_t board, triangle_t t, int degree)
|
||||
{
|
||||
double border = 10.0;
|
||||
double gap = 2*border;
|
||||
|
||||
// move board to origin
|
||||
board.p.x = 0.0;
|
||||
board.p.y = 0.0;
|
||||
|
||||
// move original triangle to above the board
|
||||
box_t tbb = triangle_bounding_box(t);
|
||||
t = triangle_move(t, -tbb.p.x, -tbb.p.y + board.h + gap);
|
||||
tbb.p.x = 0.0;
|
||||
tbb.p.y = board.h + gap;
|
||||
|
||||
// view box
|
||||
box_t view = { { -border, -border }, fmax(board.w, tbb.w) + 2 * border, board.h + gap + tbb.h + 2 * border };
|
||||
printf("viewbox:%.1f:%.1f:%.1f:%.1f\n", view.p.x, view.p.y, view.w, view.h);
|
||||
|
||||
printf("rect:%.1f:%.1f:%.1f:%.1f:%s\n", board.p.x, board.p.y, board.w, board.h, "gray");
|
||||
printf("polygon:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%s\n", t.a.x, t.a.y, t.b.x, t.b.y, t.c.x, t.c.y, "green");
|
||||
|
||||
// there was a match, show it
|
||||
if (degree >= 0) {
|
||||
triangle_t rotated = triangle_rotate(t, degree);
|
||||
box_t rbb = triangle_bounding_box(rotated);
|
||||
t = triangle_move(rotated, -rbb.p.x, -rbb.p.y); // move to origin
|
||||
printf("polygon:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%s\n", t.a.x, t.a.y, t.b.x, t.b.y, t.c.x, t.c.y, "yellow");
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# produces a crude HTML embedded SVG drawing from a tabular file (given on stdin) with columns separated by ":"
|
||||
# usage: tab2svg < inbut.txt > output.html
|
||||
|
||||
awk $* -- '
|
||||
BEGIN {
|
||||
FS=":" # field-separator: which character separats fields in a record (i.e. in a line)
|
||||
print "<!DOCTYPE html>"
|
||||
print "<html>"
|
||||
print " <head>"
|
||||
print " <title>SVG Data</title>"
|
||||
print " </head>"
|
||||
print " <body>"
|
||||
}
|
||||
/^viewbox/ {
|
||||
x = $2
|
||||
y = $3
|
||||
w = $4
|
||||
h = $5
|
||||
}
|
||||
/^rect/ {
|
||||
if (h > 0) {
|
||||
printf " <b>board = %dmm x %dmm</b>\n</p>\n", $4, $5
|
||||
printf " <svg width=\"%dmm\" viewbox=\"%.1f %.1f %.1f %.1f\" xmlns=\"http://www.w3.org/2000/svg\">\n", $4, x, y, w, h
|
||||
h = 0
|
||||
}
|
||||
printf " <rect fill=\"%s\" stroke=\"black\" x=\"%.1f\" y=\"%.1f\" width=\"%.1f\" height=\"%.1f\"/>\n", $6, $2, $3, $4, $5
|
||||
}
|
||||
/^polygon/ {
|
||||
printf " <polygon fill=\"%s\" stroke=\"black\" points=\"%.1f,%.1f %.1f,%.1f %.1f,%.1f\"/>\n", $8, $2, $3, $4, $5, $6, $7
|
||||
}
|
||||
END {
|
||||
print " </svg>"
|
||||
print " </body>"
|
||||
print "</html>"
|
||||
}
|
||||
'
|
|
@ -1,109 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief alias for EXIT_SUCCESS
|
||||
#define OK EXIT_SUCCESS
|
||||
/// @brief alias for EXIT_FAILURE
|
||||
#define FAIL EXIT_FAILURE
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// tests
|
||||
static void test_no_match(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] = {
|
||||
"viewbox:-10.0:-10.0:250.0:290.0\n",
|
||||
"rect:0.0:0.0:100.0:200.0:gray\n",
|
||||
"polygon:0.0:220.0:230.0:220.0:100.0:270.0:green\n",
|
||||
};
|
||||
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 0/0-230/0-100/50 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
}
|
||||
|
||||
static void test_initial_match(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] = {
|
||||
"viewbox:-10.0:-10.0:120.0:340.0\n",
|
||||
"rect:0.0:0.0:100.0:200.0:gray\n",
|
||||
"polygon:0.0:220.0:100.0:220.0:100.0:320.0:green\n",
|
||||
"polygon:0.0:0.0:100.0:0.0:100.0:100.0:yellow\n",
|
||||
};
|
||||
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 0/0-100/0-100/100 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
}
|
||||
|
||||
static void test_tight_match(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] = {
|
||||
"viewbox:-10.0:-10.0:225.0:290.0\n",
|
||||
"rect:0.0:0.0:100.0:200.0:gray\n",
|
||||
"polygon:0.0:220.0:205.0:220.0:205.0:270.0:green\n",
|
||||
"polygon:94.8:0.0:48.7:199.7:0.0:188.5:yellow\n",
|
||||
};
|
||||
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 0/0-205/0-205/50 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_no_match
|
||||
, test_initial_match
|
||||
, test_tight_match
|
||||
);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/weekday
|
||||
SOURCES := src/main.c
|
||||
TSTSOURCES := tests/tests.c
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P03 Calculate the week day
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab to calculate the week day from a given Gregorian date.
|
||||
*
|
||||
*/
|
|
@ -1,121 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab P03 weekday
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// *** TASK1: typedef enum types for month_t (Jan=1,...Dec} ***
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// *** TASK1: typedef struct for date_t ***
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// *** TASK2: typedef enum weekday_t (Sun=0, Mon, ...Sat) ***
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
/**
|
||||
* @brief TASK1: Checks if the given date is a leap year.
|
||||
* @returns 0 = is not leap year, 1 = is leap year
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief TASK1: Calculates the length of the month given by the data parameter
|
||||
* @returns 28, 29, 30, 31 if a valid month, else 0
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
/**
|
||||
* @brief TASK1: Checks if the given date is in the gregorian date range
|
||||
* @returns 0 = no, 1 = yes
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief TASK1: Checks if the given date is a valid date.
|
||||
* @returns 0 = is not valid date, 1 = is valid date
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief TASK2: calculated from a valid date the weekday
|
||||
* @returns returns a weekday in the range Sun...Sat
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief TASK2: print weekday as 3-letter abreviated English day name
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @param argc [in] number of entries in argv
|
||||
* @param argv [in] program name plus command line arguments
|
||||
* @returns returns success if valid date is given, failure otherwise
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
// TASK1: parse the mandatory argument into a date_t variable and check if the date is valid
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// TASK2: calculate the weekday and print it in this format: YYYY-MM-DD is a Ddd\n, e.g. 2021-03-08 is a Mon\n
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief alias for EXIT_SUCCESS
|
||||
#define OK EXIT_SUCCESS
|
||||
/// @brief alias for EXIT_FAILURE
|
||||
#define FAIL EXIT_FAILURE
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static struct tm now()
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
return *localtime(&t);
|
||||
}
|
||||
|
||||
static const char* weekday_name(int wday)
|
||||
{
|
||||
assert(0 <= wday && wday <= 6);
|
||||
static const char* days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
return days[wday];
|
||||
}
|
||||
|
||||
// tests
|
||||
static void test_task1_fail_no_arg(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
}
|
||||
|
||||
static void test_task1_fail_not_gregorian(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1291-08-01 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-14 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1583-10-14 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
}
|
||||
|
||||
static void test_task1_fail_month_out_of_range(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-13-13 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-00-13 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-12-13 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
}
|
||||
|
||||
static void test_task1_fail_day_out_of_range(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-29 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-28 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-28 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
}
|
||||
|
||||
static void test_task1_fail_leap_year(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1900-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1900-02-28 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2000-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2000-02-29 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2001-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2001-02-28 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2004-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2004-02-29 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
}
|
||||
|
||||
static void test_task1_valid_date(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-01 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-29 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-03-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-04-30 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-05-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-06-30 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-07-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-08-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-09-30 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-10-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-11-30 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-12-31 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-03-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-04-31 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-05-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-06-31 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-07-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-08-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-09-31 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-10-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-11-31 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-12-32 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
}
|
||||
|
||||
static void test_task2_start_gregorian(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1581-10-14 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1581-10-15 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-14 >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-15 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1583-10-14 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1583-10-15 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
|
||||
const char *out_txt[] = { "1582-10-15 is a Fri\n" };
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-15 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
}
|
||||
|
||||
static void test_task2_today(void)
|
||||
{
|
||||
// arrange
|
||||
const size_t SIZE = 1000;
|
||||
char command[SIZE];
|
||||
struct tm t = now();
|
||||
snprintf(command, SIZE, "%s %04d-%02d-%02d 2>%s | tail -1 >%s", XSTR(TARGET), t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, ERRFILE, OUTFILE);
|
||||
|
||||
char buffer[SIZE];
|
||||
snprintf(buffer, SIZE, "%04d-%02d-%02d is a %s\n", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, weekday_name(t.tm_wday));
|
||||
const char *out_txt[] = { buffer };
|
||||
const char *err_txt[] = { NULL };
|
||||
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(command)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_task1_fail_no_arg
|
||||
, test_task1_fail_not_gregorian
|
||||
, test_task1_fail_month_out_of_range
|
||||
, test_task1_fail_day_out_of_range
|
||||
, test_task1_fail_leap_year
|
||||
, test_task1_valid_date
|
||||
, test_task2_start_gregorian
|
||||
, test_task2_today
|
||||
);
|
||||
}
|
Binary file not shown.
|
@ -1,65 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/dep2dot
|
||||
# Add all additional c-files to the SOURCES variable
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
SOURCES := src/main.c
|
||||
# END-STUDENTS-TO-ADD-CODE
|
||||
TSTSOURCES := tests/tests.c
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
||||
|
||||
|
||||
# DEPFILES := ... define a list of png file names: %.c -> %.c.png
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define dep target as .PHONEY
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define dep target depending on FULLTARGET and DEPFILES above
|
||||
# action: echo some text telling that the target is done using $@ - the echo command shall not be echoed before execution
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define new suffix rule for %.png depending on %.dot
|
||||
# action: dot -Tpng $< >$@ || $(RM) $@
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define new suffix rule for %.dot depending on %.dep
|
||||
# action: call $(TARGET) $(@:.dot=) <$< >$@ || $(RM) $@
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# converts any .c file into a .c.dep file by means of GCC -H switch
|
||||
# note: it removes intermediate files which were created as side effect
|
||||
%.c.dep: %.c
|
||||
$(COMPILE.c) -H -o $@.x $< 2>$@ && $(RM) $@.x $@.d
|
||||
|
||||
|
||||
# cleanup all results, including the ones od creating the dependencies
|
||||
dep-clean: clean
|
||||
$(RM) $(DEPFILES) $(wildcard src/*.dep src/*.dot)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P04 Modularisation
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab for splitting functionality into multiple modules.
|
||||
*
|
||||
*/
|
|
@ -1,149 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Implementation of the dependency file access.
|
||||
*/
|
||||
#include "data.h"
|
||||
#include "error.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define MAX_PATH_LEN 512 ///< @brief Arbitrarily chosen maximum accepted path lenght.
|
||||
#define MAX_LINE_LEN 512 ///< @brief Arbitrarily chosen maximum accepted line length
|
||||
#define MAX_DIRS 64 ///< @brief Arbitrarily chosen maximum number of supported individual directories per dependency file.
|
||||
#define MAX_FILES 256 ///< @brief Arbitrarily chosen maximum number of supported individual denendency entries.
|
||||
|
||||
/**
|
||||
* @brief Declaration of POSIX (but not C99) function.
|
||||
* @param s [IN] The string to duplicate on the heap memory.
|
||||
* @return The duplicated string.
|
||||
* @remark Since the Makefile calls gcc with -std=c99, non-C99 POSIX and GNU extensions are excluded - the glibc, though, provides the function to the linker.
|
||||
*/
|
||||
char *strdup(const char *s); // not stdc99, but available in the glibc
|
||||
|
||||
/**
|
||||
* @brief Initialized the data structure before the data is to be read from th edependency file.
|
||||
* @param data [INOUT] The address of the instance to initialize.
|
||||
*/
|
||||
static void init(data_t *data)
|
||||
{
|
||||
assert(data);
|
||||
memset(data, 0, sizeof(data_t));
|
||||
data->dirs = malloc(MAX_DIRS * sizeof(dir_t));
|
||||
if (!data->dirs) FATAL("no memory left");
|
||||
data->files = malloc(MAX_FILES * sizeof(file_t));
|
||||
if (!data->files) FATAL("no memory left");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the directory list with the given data.
|
||||
* @param data [INOUT] The instance to update.
|
||||
* @param path [IN] The file path of a dependency entry as given by the dependency file.
|
||||
* @return The index of the directory entry (either an existing matching one or a newly added one).
|
||||
* @remark Extracts the directory part by means of dirname() from the given path and looks up an existing entry or adds a new one.
|
||||
*/
|
||||
static size_t get_or_add_dir(data_t *data, const char *path)
|
||||
{
|
||||
assert(data);
|
||||
assert(path);
|
||||
// The function dirname() gives no guarantee to not modify the parameter, therefore, need to produce a copy before calling dirname().
|
||||
// Likewise, the returned value may refer to the passed paremater, therefore, a copy is made from the return value.
|
||||
char *dup = strdup(path);
|
||||
if (!dup) FATAL("no memory left");
|
||||
char *name = strdup(dirname(dup));
|
||||
if (!name) FATAL("no memory left");
|
||||
free(dup);
|
||||
|
||||
// search for a matching entry...
|
||||
size_t i = 0;
|
||||
while(i < data->n_dirs && strcmp(data->dirs[i].name, name) != 0) {
|
||||
i++;
|
||||
}
|
||||
if (i >= MAX_DIRS) FATAL("too many directories");
|
||||
|
||||
if (i == data->n_dirs) { // no match found: add
|
||||
// handover the allocated name to the owning new directory entry
|
||||
dir_t dir = { .name = name };
|
||||
// append the new directory entry
|
||||
data->dirs[data->n_dirs] = dir;
|
||||
data->n_dirs++;
|
||||
} else {
|
||||
// release the name since match found, and therefore, no need to keep the allocated name anymore
|
||||
free(name);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add a file entry from the dependency file to the data structure.
|
||||
* @param data [INOUT] The data container instance.
|
||||
* @param path [IN] The path of one file entry from the dependency file.
|
||||
* @param level [IN] The dependency level of the file entry from the dependency file.
|
||||
* @remark The sequence of entries in the dependency file is relevant - it implies direct dependencies.
|
||||
*/
|
||||
static void add_file(data_t *data, const char *path, size_t level)
|
||||
{
|
||||
assert(data);
|
||||
assert(path);
|
||||
// The function basename() gives no guarantee to not modify the parameter, therefore, need to produce a copy before calling basename().
|
||||
// Likewise, the returned value may refer to the passed paremater, therefore, a copy is made from the return value.
|
||||
char *dup = strdup(path);
|
||||
if (!dup) FATAL("no memory left");
|
||||
char *name = strdup(basename(dup));
|
||||
if (!name) FATAL("no memory left");
|
||||
free(dup);
|
||||
|
||||
if (data->n_files >= MAX_FILES) FATAL("too many files");
|
||||
// produce a file entry
|
||||
file_t file = { .name = name, .dir = get_or_add_dir(data, path), .level = level };
|
||||
data->files[data->n_files] = file;
|
||||
data->n_files++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes one dependency line of the dependency file.
|
||||
* @param data [INOUT] The data container instance.
|
||||
* @param line [IN] The line to parse and store in data.
|
||||
*/
|
||||
static void process_line(data_t *data, const char line[])
|
||||
{
|
||||
assert(data);
|
||||
|
||||
size_t len = strlen(line);
|
||||
assert(len > 0);
|
||||
assert(line[0] == '.');
|
||||
|
||||
// read level
|
||||
size_t i = strspn(line, ".");
|
||||
size_t level = i;
|
||||
// skip spaces
|
||||
i += strspn(line+i, " \t");
|
||||
// take rest as path and add the file to the records
|
||||
add_file(data, line+i, level);
|
||||
}
|
||||
|
||||
/*
|
||||
* The public interface.
|
||||
*/
|
||||
const data_t data_read_all(const char *root)
|
||||
{
|
||||
data_t data;
|
||||
init(&data);
|
||||
// add as first file the root for the given dependencies
|
||||
add_file(&data, root, 0);
|
||||
|
||||
char line[MAX_LINE_LEN] = { 0 };
|
||||
|
||||
// read all stdin line and only process dependency lines (those starting on a '.')
|
||||
clearerr(stdin);
|
||||
while(fgets(line, MAX_LINE_LEN, stdin)) {
|
||||
size_t len = strlen(line);
|
||||
if (len > 0 && line[len-1] == '\n' && line[0] == '.') { // only dependency lines
|
||||
line[len-1] = '\0';
|
||||
process_line(&data, line);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Access to the GCC produced dependency data (via gcc -H command line option).
|
||||
*/
|
||||
|
||||
// begin of include guard
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// includes which are needed in this header file
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Directory container for file entries of the dependency file.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief File container for the file entries of the dependency file.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Overall container for all directories and all files from the dependency file.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entry function to read the deendency data from stdin.
|
||||
* @param root [IN] The name of the root file (the deoendency file does not mention the root file, so, it has to be passed from outside).
|
||||
* @return The container of the read data from stdin. See the documentation on gcc -H for details on the dependencies, etc.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// end of include guard
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Error handling convenience functions.
|
||||
*/
|
||||
#ifndef _ERROR_H_
|
||||
#define _ERROR_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief Prints the message to stderr and terminates with EXIT_FAILURE.
|
||||
* @param MSG [IN] The "..." *string literal* to emit as error - no format parameters nor variables supported.
|
||||
*/
|
||||
#define FATAL(MSG) do { fprintf(stderr, "ERROR: %s\n", MSG); exit(EXIT_FAILURE); } while(0)
|
||||
|
||||
#endif // _ERROR_H_
|
|
@ -1,36 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab P04 dep2dot
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "data.h"
|
||||
#include "output.h"
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @param argc [in] number of entries in argv
|
||||
* @param argv [in] program name plus command line arguments
|
||||
* @returns returns success if valid date is given, failure otherwise
|
||||
* @remark Prerequisit to convert the resulting DOT file on the shell: sodo apt install graphviz
|
||||
* @remark Convert: gcc -H ... file.c ... 2>file.dep ; dep2dot file.c <file.dep >file.dot && dot -Tpng file.dot >file.png
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc < 2) FATAL("missing arguments\nusage: dep2dot file.c <file.dep >file.dot # from gcc -H ... file.c ... 2>file.dep\n");
|
||||
|
||||
output_dot(data_read_all(argv[1]));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Provides output functions for various file formats.
|
||||
*/
|
||||
#include "output.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief Writes the node name of the given file.
|
||||
* @param file [IN] The file for which to write the node name.
|
||||
* @remark The dependency data contain duplicates of file entries - the node name must be unique for the path and the *basename* of the files.
|
||||
*/
|
||||
static void print_node(file_t file)
|
||||
{
|
||||
printf("\"%s (cluster_c%zd)\"", file.name, file.dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursively writes the individual direct dependencies for the file given by curr.
|
||||
* @param files [IN] The array of all files - the sequence is relevant.
|
||||
* @param len [IN] The lenght of the files array, i.e. the upper limit for curr values and the subsequent index values.
|
||||
* @param curr [IN] The index into files for the current root for dependencies: curr -> x, curr -> y, ...
|
||||
* @return Returns the index into files for the next file to process (i.e. curr value for the next call to this function).
|
||||
* @remark For a given *curr* file, all following files are with depth level + 1 are direct include files.
|
||||
* @remark All files with a higher level are *indirect* include files, thus *direct* includes from files processed by recursive calls.
|
||||
* @remark The list of direct includes to the *curr* file terminates with a level equal of less the the *curr* one (or when the list is exchausted).
|
||||
*/
|
||||
static size_t dependencies(file_t files[], size_t len, size_t curr)
|
||||
{
|
||||
assert(curr < len);
|
||||
size_t level = files[curr].level;
|
||||
size_t file = curr + 1;
|
||||
while(file < len && files[file].level > level) {
|
||||
if (files[file].level == level + 1) {
|
||||
// Write to stdout " file -> include;\n" where file and include are the DOT node names of the respective files
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
file = dependencies(files, len, file);
|
||||
} else {
|
||||
file++;
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public interface
|
||||
*/
|
||||
void output_dot(const data_t data)
|
||||
{
|
||||
printf("digraph dep {\n");
|
||||
// nodes
|
||||
printf(" node [shape=box]\n");
|
||||
for (size_t file = 0; file < data.n_files; file++) {
|
||||
// Write to stdout " file [label=\"name\"];\n" where file is the DOT node name and name is the file name
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
// directory clusters
|
||||
for (size_t dir = 0; dir < data.n_dirs; dir++) {
|
||||
printf(" subgraph cluster_c%zd {\n", dir);
|
||||
printf(" label=\"%s\"; %s\n", data.dirs[dir].name, strncmp(data.dirs[dir].name, "/usr/", 5) == 0 ? "style=filled; color=lightgrey;" : "color=black;");
|
||||
for (size_t file = 0; file < data.n_files; file++) {
|
||||
if (data.files[file].dir == dir) {
|
||||
// Write to stdout " file;\n" where file is the DOT node name
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
}
|
||||
printf(" }\n");
|
||||
}
|
||||
|
||||
// dependencies
|
||||
size_t curr = 0;
|
||||
do {
|
||||
curr = dependencies(data.files, data.n_files, curr);
|
||||
} while(curr < data.n_files);
|
||||
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Provides output functions for various file formats.
|
||||
*/
|
||||
// define proper header file here, with include gaurd, etc.
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
|
@ -1,7 +0,0 @@
|
|||
Test File
|
||||
. dir1/h1_1
|
||||
.. dir1/h1_1_2
|
||||
. dir1/h1_2
|
||||
. dir2/h2_1
|
||||
.. dir1/h1_1
|
||||
Done
|
|
@ -1,2 +0,0 @@
|
|||
Test File
|
||||
Done
|
|
@ -1,140 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief alias for EXIT_SUCCESS
|
||||
#define OK EXIT_SUCCESS
|
||||
/// @brief alias for EXIT_FAILURE
|
||||
#define FAIL EXIT_FAILURE
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
|
||||
/// @brief test data file
|
||||
#define IN_NO_DEP "no_dep.input"
|
||||
/// @brief test data file
|
||||
#define IN_DEP "dep.input"
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// tests
|
||||
static void test_fail_no_arg(void)
|
||||
{
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
}
|
||||
|
||||
static void test_no_dep(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] = {
|
||||
"digraph dep {\n",
|
||||
" node [shape=box]\n",
|
||||
" \"root (cluster_c0)\" [label=\"root\"];\n",
|
||||
" subgraph cluster_c0 {\n",
|
||||
" label=\".\"; color=black;\n",
|
||||
" \"root (cluster_c0)\";\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
};
|
||||
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " root <" IN_NO_DEP " >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
|
||||
// assert
|
||||
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
}
|
||||
|
||||
static void test_dep(void)
|
||||
{
|
||||
// arrange
|
||||
const char *out_txt[] = {
|
||||
"digraph dep {\n",
|
||||
" node [shape=box]\n",
|
||||
" \"root (cluster_c0)\" [label=\"root\"];\n",
|
||||
" \"h1_1 (cluster_c1)\" [label=\"h1_1\"];\n",
|
||||
" \"h1_1_2 (cluster_c1)\" [label=\"h1_1_2\"];\n",
|
||||
" \"h1_2 (cluster_c1)\" [label=\"h1_2\"];\n",
|
||||
" \"h2_1 (cluster_c2)\" [label=\"h2_1\"];\n",
|
||||
" \"h1_1 (cluster_c1)\" [label=\"h1_1\"];\n",
|
||||
" subgraph cluster_c0 {\n",
|
||||
" label=\".\"; color=black;\n",
|
||||
" \"root (cluster_c0)\";\n",
|
||||
" }\n",
|
||||
" subgraph cluster_c1 {\n",
|
||||
" label=\"dir1\"; color=black;\n",
|
||||
" \"h1_1 (cluster_c1)\";\n",
|
||||
" \"h1_1_2 (cluster_c1)\";\n",
|
||||
" \"h1_2 (cluster_c1)\";\n",
|
||||
" \"h1_1 (cluster_c1)\";\n",
|
||||
" }\n",
|
||||
" subgraph cluster_c2 {\n",
|
||||
" label=\"dir2\"; color=black;\n",
|
||||
" \"h2_1 (cluster_c2)\";\n",
|
||||
" }\n",
|
||||
" \"root (cluster_c0)\" -> \"h1_1 (cluster_c1)\";\n",
|
||||
" \"h1_1 (cluster_c1)\" -> \"h1_1_2 (cluster_c1)\";\n",
|
||||
" \"root (cluster_c0)\" -> \"h1_2 (cluster_c1)\";\n",
|
||||
" \"root (cluster_c0)\" -> \"h2_1 (cluster_c2)\";\n",
|
||||
" \"h2_1 (cluster_c2)\" -> \"h1_1 (cluster_c1)\";\n",
|
||||
"}\n",
|
||||
};
|
||||
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " root <" IN_DEP " >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
|
||||
// assert
|
||||
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_fail_no_arg
|
||||
, test_no_dep
|
||||
, test_dep
|
||||
);
|
||||
}
|
Binary file not shown.
|
@ -1,9 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/tic-tac-toe
|
||||
MODULES := src/model.c src/view.c src/control.c
|
||||
SOURCES := src/main.c $(MODULES)
|
||||
TSTSOURCES := tests/tests.c $(MODULES)
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P05 Tic Tac Toe Game
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab on usage of arrays.
|
||||
*
|
||||
*/
|
|
@ -1,154 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Implementation
|
||||
*/
|
||||
#include "control.h"
|
||||
#include "model.h"
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* @brief Conversion from control field number (1...9) to 0-based model position (row, col).
|
||||
* @param cell [IN] Field number (1...9).
|
||||
* @return Returns the position of the field.
|
||||
* @remark Asserts proper field range.
|
||||
*/
|
||||
static model_pos_t get_pos(size_t cell)
|
||||
{
|
||||
assert(1 <= cell && cell <= 9);
|
||||
model_pos_t pos = { (cell - 1) / 3, (cell - 1) % 3 };
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Conversion from control player to model state.
|
||||
* @param player [IN] Control player value to convert.
|
||||
* @return Returns the matching model state.
|
||||
* @remark No assertion is done - defaults to model_state_none.
|
||||
*/
|
||||
static model_state_t get_state(control_player_t player)
|
||||
{
|
||||
switch(player) {
|
||||
case control_player_a: return model_state_a;
|
||||
case control_player_b: return model_state_b;
|
||||
default: return model_state_none;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Conversion from 0-based model position (row, col) to control field number (1...9).
|
||||
* @param pos [IN] 0-based model position (row,col).
|
||||
* @return The control filed number (1...9)
|
||||
* @remark Asserts proper position range.
|
||||
*/
|
||||
static size_t get_cell(model_pos_t pos)
|
||||
{
|
||||
assert(pos.row < 3);
|
||||
assert(pos.col < 3);
|
||||
return 1 + pos.row * 3 + pos.col;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Conversion from model state to control player.
|
||||
* @param state [IN] Model state to convert
|
||||
* @return Returns the matching control player value.
|
||||
* @remark No assertion is done - defaults to control_no_player.
|
||||
*/
|
||||
static control_player_t get_player(model_state_t state)
|
||||
{
|
||||
switch(state) {
|
||||
case model_state_a: return control_player_a;
|
||||
case model_state_b: return control_player_b;
|
||||
default: return control_no_player;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queries if a move is possible.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @return Returns 0 if no move is possible any more, otherwise 1.
|
||||
*/
|
||||
static int control_can_move(control_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
return model_can_move(instance->model);
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
void control_init(control_t *instance, model_t *model)
|
||||
{
|
||||
assert(instance);
|
||||
assert(model);
|
||||
instance->player = control_player_a;
|
||||
instance->model = model;
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
void control_move(control_t *instance, size_t cell)
|
||||
{
|
||||
assert(instance);
|
||||
if (model_move(instance->model, get_pos(cell), get_state(instance->player))) {
|
||||
if (control_can_move(instance)) {
|
||||
switch(instance->player) {
|
||||
case control_player_a:
|
||||
instance->player = control_player_b;
|
||||
break;
|
||||
case control_player_b:
|
||||
instance->player = control_player_a;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
instance->player = control_no_player;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
control_player_t control_get_winner(control_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
return get_player(model_get_winner(instance->model));
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
control_player_t control_get_player(control_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
return instance->player;
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
control_player_t control_get_state(control_t *instance, size_t cell)
|
||||
{
|
||||
assert(instance);
|
||||
return get_player(model_get_state(instance->model, get_pos(cell)));
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
control_line_t control_get_win(control_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
if (control_get_winner(instance) == control_no_player) {
|
||||
control_line_t no_win = { 0 };
|
||||
return no_win;
|
||||
}
|
||||
|
||||
model_line_t line = model_get_win_line(instance->model);
|
||||
assert(line.dir != model_dir_none);
|
||||
size_t start_cell = get_cell(line.start);
|
||||
switch(line.dir) {
|
||||
case model_dir_h:
|
||||
return (control_line_t) { { start_cell, start_cell + 1, start_cell + 2 } };
|
||||
case model_dir_v:
|
||||
return (control_line_t) { { start_cell, start_cell + 3, start_cell + 6 } };
|
||||
case model_dir_d:
|
||||
if (start_cell == 1) {
|
||||
return (control_line_t) { { start_cell, start_cell + 4, start_cell + 8 } };
|
||||
} else {
|
||||
return (control_line_t) { { start_cell, start_cell + 2, start_cell + 6 } };
|
||||
}
|
||||
default:
|
||||
return (control_line_t) { { 1, 1, 1 } };
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief MVC - agent between model and view
|
||||
*/
|
||||
#ifndef _CONTROL_H_
|
||||
#define _CONTROL_H_
|
||||
|
||||
#include "model.h"
|
||||
|
||||
/**
|
||||
* @brief The selection of possible players.
|
||||
*/
|
||||
typedef enum {
|
||||
control_no_player, ///< none of the players
|
||||
control_player_a, ///< first player
|
||||
control_player_b, ///< second player
|
||||
} control_player_t;
|
||||
|
||||
/**
|
||||
* @brief Sequence of winning cell numbers in increasing cell numbers.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t line[3]; ///< the sequence of cells (1...9) or 0 in the first element if no win
|
||||
} control_line_t;
|
||||
|
||||
/**
|
||||
* @brief The instance type.
|
||||
*/
|
||||
typedef struct {
|
||||
control_player_t player; ///< the current player
|
||||
model_t *model; ///< the reference to the model
|
||||
} control_t;
|
||||
|
||||
/**
|
||||
* @brief Constructor: initialize the instance memory.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @param model [IN] Dependency Injection of the model instance.
|
||||
*/
|
||||
void control_init(control_t *instance, model_t *model);
|
||||
|
||||
/**
|
||||
* @brief Performs a move on the board.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @param cell [IN] The affected field (1...9)
|
||||
* @remark Silently ignores a move if it is not allowed (e.g. if already completed or the field is already played, etc.).
|
||||
*/
|
||||
void control_move(control_t *instance, size_t cell);
|
||||
|
||||
/**
|
||||
* @brief Queries the winning player.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @returns Returns the winning player (if any).
|
||||
*/
|
||||
control_player_t control_get_winner(control_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Queries the next player.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @returns Returns the next player (if any).
|
||||
* @remark This is updated by the control_move() function.
|
||||
*/
|
||||
control_player_t control_get_player(control_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Queries the state of a field.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @param cell [IN] The affected field of the board (1...9).
|
||||
* @returns Returns the player which played this field (if any).
|
||||
*/
|
||||
control_player_t control_get_state(control_t *instance, size_t cell);
|
||||
|
||||
/**
|
||||
* @brief Gets the winning fields (if any).
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @returns Returns the field numbers in increasing order (1...9) which win the game (if any).
|
||||
* @remark If there is no winner (yet), the first entry in the result is 0.
|
||||
*/
|
||||
control_line_t control_get_win(control_t *instance);
|
||||
|
||||
#endif // _CONTROL_H_
|
|
@ -1,39 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab P04 dep2dot
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "view.h"
|
||||
#include "model.h"
|
||||
#include "control.h"
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @param argc [in] number of entries in argv
|
||||
* @param argv [in] program name plus command line arguments
|
||||
* @returns returns success if valid date is given, failure otherwise
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
view_t view;
|
||||
control_t control;
|
||||
model_t model;
|
||||
|
||||
model_init(&model);
|
||||
control_init(&control, &model);
|
||||
view_init(&view, &control);
|
||||
view_run(&view);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Implementation
|
||||
*/
|
||||
#include "model.h"
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* @brief Asserts that the position is in range.
|
||||
* @param [IN] The position to check.
|
||||
*/
|
||||
static void assert_pos(model_pos_t pos)
|
||||
{
|
||||
assert(pos.row < MODEL_SIZE);
|
||||
assert(pos.col < MODEL_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the field on the board to the given state.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @param pos [IN] The affected field.
|
||||
* @param state [IN] The new state of the field.
|
||||
*/
|
||||
static void set_state(model_t *instance, model_pos_t pos, model_state_t state)
|
||||
{
|
||||
assert_pos(pos);
|
||||
|
||||
// Instructions to the students:
|
||||
// set the field of the board to the new state
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
model_pos_t model_pos(size_t row, size_t col)
|
||||
{
|
||||
return (model_pos_t){row, col};
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
void model_init(model_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
|
||||
// Instructions to the students:
|
||||
// set all fields of the board to model_state_none
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
model_state_t model_get_state(model_t *instance, model_pos_t pos)
|
||||
{
|
||||
assert(instance);
|
||||
assert_pos(pos);
|
||||
|
||||
// Instructions to the students:
|
||||
// replace the stub implementation my access to the field at the given position.
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
return model_state_none; // stub
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
model_line_t model_get_win_line(model_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
model_state_t anchor;
|
||||
|
||||
// horizontal
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
anchor = model_get_state(instance, model_pos(row, 0));
|
||||
if (anchor != model_state_none
|
||||
&& anchor == model_get_state(instance, model_pos(row, 1))
|
||||
&& anchor == model_get_state(instance, model_pos(row, 2))) {
|
||||
return (model_line_t) { model_dir_h, { row, 0 } };
|
||||
}
|
||||
}
|
||||
|
||||
// vertical
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
anchor = model_get_state(instance, model_pos(0, col));
|
||||
if (anchor != model_state_none
|
||||
&& anchor == model_get_state(instance, model_pos(1, col))
|
||||
&& anchor == model_get_state(instance, model_pos(2, col))) {
|
||||
return (model_line_t) { model_dir_v, { 0, col } };
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// diagonal
|
||||
anchor = model_get_state(instance, model_pos(1, 1));
|
||||
if (anchor != model_state_none) {
|
||||
if (anchor == model_get_state(instance, model_pos(0, 0)) && anchor == model_get_state(instance, model_pos(2, 2))) {
|
||||
return (model_line_t) { model_dir_d, { 0, 0 } };
|
||||
}
|
||||
if (anchor == model_get_state(instance, model_pos(2, 0)) && anchor == model_get_state(instance, model_pos(0, 2))) {
|
||||
return (model_line_t) { model_dir_d, { 0, 2 } };
|
||||
}
|
||||
}
|
||||
|
||||
// fallback
|
||||
return (model_line_t) { model_dir_none, { 0, 0 } };
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
model_state_t model_get_winner(model_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
model_line_t line = model_get_win_line(instance);
|
||||
return line.dir == model_dir_none
|
||||
? model_state_none
|
||||
: model_get_state(instance, model_pos(line.start.row, line.start.col))
|
||||
;
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
int model_can_move(model_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
if (model_get_winner(instance) == model_state_none) {
|
||||
// Instructions to the students:
|
||||
// scan all fields: return 1 with first field which equals model_state_none
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
int model_move(model_t *instance, model_pos_t pos, model_state_t state)
|
||||
{
|
||||
assert(instance);
|
||||
assert_pos(pos);
|
||||
if (model_get_state(instance, pos) == model_state_none && model_can_move(instance)) {
|
||||
set_state(instance, pos, state);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief MVC - Model instance
|
||||
*/
|
||||
#ifndef _MODEL_H_
|
||||
#define _MODEL_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MODEL_SIZE 3 ///< size of the game to avoid magic numbers in the code (not meant to modify)
|
||||
|
||||
/**
|
||||
* @brief The position on the board.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t row; ///< The row (0-based).
|
||||
size_t col; ///< The column (0-based).
|
||||
} model_pos_t;
|
||||
|
||||
/**
|
||||
* @brief Winner line direction - the winner line is given together with the start position.
|
||||
*/
|
||||
typedef enum {
|
||||
model_dir_none, ///< no winner line
|
||||
model_dir_h, ///< horizontal
|
||||
model_dir_v, ///< vertical
|
||||
model_dir_d, ///< diagonal
|
||||
} model_dir_t;
|
||||
|
||||
/**
|
||||
* @brief The Winner line (if any).
|
||||
*/
|
||||
typedef struct {
|
||||
model_dir_t dir; ///< the winner line direction (if any)
|
||||
model_pos_t start; ///< the start position of the winner line
|
||||
} model_line_t;
|
||||
|
||||
/**
|
||||
* @brief The state of a field.
|
||||
*/
|
||||
typedef enum {
|
||||
model_state_none, ///< field available to play
|
||||
model_state_a, ///< field already played
|
||||
model_state_b, ///< field already played
|
||||
} model_state_t;
|
||||
|
||||
/**
|
||||
* @brief The instance type.
|
||||
*/
|
||||
typedef struct {
|
||||
model_state_t board[MODEL_SIZE][MODEL_SIZE]; ///< the play board
|
||||
} model_t;
|
||||
|
||||
/**
|
||||
* @brief Convert to row and col to position.
|
||||
* @param row [IN] position parameter
|
||||
* @param col [IN] position parameter
|
||||
* @return Returns the position given be row and col parameters.
|
||||
*/
|
||||
model_pos_t model_pos(size_t row, size_t col);
|
||||
|
||||
/**
|
||||
* @brief Constructor: initialize the instance memory.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
*/
|
||||
void model_init(model_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Queries the state of the given field.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @param pos [IN] The affected field.
|
||||
* @return Returns the state of the field.
|
||||
*/
|
||||
model_state_t model_get_state(model_t *instance, model_pos_t pos);
|
||||
|
||||
/**
|
||||
* @brief Queries the winner (if any).
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @return Returns the wining player or model_state_none if no winner (yet).
|
||||
*/
|
||||
model_state_t model_get_winner(model_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Queries if a move is possible (i.e. not won yet and any field available?).
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @return Returns 0 if no move possible, 1 otherwise.
|
||||
*/
|
||||
int model_can_move(model_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Do a move if possible.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @param pos [IN] The field to play.
|
||||
* @param state [IN] The new state (only model_state_a and model_state_b allowed).
|
||||
* @return Returns if the attempt to move was successful.
|
||||
* @remark Does only succeed if not yet won and if the field is available.
|
||||
*/
|
||||
int model_move(model_t *instance, model_pos_t pos, model_state_t state);
|
||||
|
||||
/**
|
||||
* @brief Gets the winner line (if any).
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @returns The line which wins (if any).
|
||||
* @remark The start position is 0/0, 1/0, 2/0 for horizontal, 0/0, 0/1, 0/2 for vertical, 0/0, 0/2 for diagonal.
|
||||
*/
|
||||
model_line_t model_get_win_line(model_t *instance);
|
||||
|
||||
#endif // _MODEL_H_
|
|
@ -1,255 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Implementation
|
||||
*/
|
||||
#include "view.h"
|
||||
#include "control.h"
|
||||
|
||||
#include <assert.h> // assert()
|
||||
#include <stdio.h> // various i/o
|
||||
#include <ctype.h> // isdigit()
|
||||
#include <unistd.h> // STDIN_FILENO, isatty()
|
||||
#include <termios.h> // tcgetattr(), tcsetattr()
|
||||
|
||||
#define EXIT '0' ///< the UI exit request
|
||||
|
||||
#define CLS "\033[2J" ///< ANSI termial CSI sequence for clear screen
|
||||
#define AVAILABLE "\033[40m" ///< ANSI termial CSI sequence for available fields (black)
|
||||
#define PLAYER_A "\033[42m" ///< ANSI termial CSI sequence for one player (green)
|
||||
#define PLAYER_B "\033[41m" ///< ANSI termial CSI sequence for the other player (red)
|
||||
#define GAP "\033[47m" ///< ANSI termial CSI sequence for boarder (white)
|
||||
#define RESET "\033[0m" ///< ANSI termial CSI sequence to reset all settings
|
||||
|
||||
#define CELL_WIDTH 10 ///< rendering parameter: columns per cell
|
||||
#define CELL_HEIGHT 5 ///< rendering parameter: rows per cell
|
||||
#define GAP_WIDTH 4 ///< rendering parameter: columns per border
|
||||
#define GAP_HEIGHT 2 ///< rendering parameter: rows per boarder
|
||||
|
||||
#define SIZE 3 ///< size of the game to avoid magic numbers in the code (not meant to modify)
|
||||
#define CELLS (SIZE * SIZE) ///< size of the game to avoid magic numbers in the code (not meant to modify)
|
||||
|
||||
/**
|
||||
* @brief Position the cursor for further output.
|
||||
* @param row [IN] position parameter
|
||||
* @param col [IN] position parameter
|
||||
*/
|
||||
static void goto_pos(size_t row, size_t col)
|
||||
{
|
||||
printf("\033[%zd;%zdH", row, col);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Displays a sequence of spaces at the given position in the given background color.
|
||||
* @param row [IN] position parameter
|
||||
* @param col [IN] position parameter
|
||||
* @param width [IN] how many spaces to write
|
||||
* @param color [IN] the format string before writing the spaces (intent: background color)
|
||||
* @remark After writing the spaces, the format is reset.
|
||||
*/
|
||||
static size_t show_bar(size_t row, size_t col, size_t width, const char* color)
|
||||
{
|
||||
goto_pos(row, col);
|
||||
printf("%s", color);
|
||||
for(size_t col = 0; col < width; col++) {
|
||||
putchar(' ');
|
||||
}
|
||||
printf(RESET);
|
||||
return col + width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Displays a horizontal border over the whole board width.
|
||||
* @param row [IN] position parameter
|
||||
* @param col [IN] position parameter
|
||||
*/
|
||||
static size_t show_h_gap(size_t row, size_t col) {
|
||||
for(size_t i = 0; i < GAP_HEIGHT; i++) {
|
||||
show_bar(row+i, col, GAP_WIDTH + CELL_WIDTH + GAP_WIDTH, GAP);
|
||||
}
|
||||
return row + GAP_HEIGHT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes for the call at position y/x the given number with the given background color.
|
||||
* @param y [IN] position parameter: the upper left row of the cell
|
||||
* @param x [IN] position parameter: the upper left column of the cell
|
||||
* @param n [IN] the number to write as text
|
||||
* @param color [IN] the format string before writing the text (intent: background color)
|
||||
* @remark After writing the number, the format is reset.
|
||||
*/
|
||||
static void show_cell_nr(size_t y, size_t x, size_t n, const char *color)
|
||||
{
|
||||
size_t cy = (y + y + CELL_HEIGHT)/2;
|
||||
size_t cx = (x + x + CELL_WIDTH - 2)/2;
|
||||
|
||||
goto_pos(cy, cx);
|
||||
printf("%s", color);
|
||||
printf("%2zd", n);
|
||||
printf(RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Renders the given cell with the given background color, including the surrounding border.
|
||||
* @param n [IN] the cell number (0...CELLS-1)
|
||||
* @param color [IN] the format string for the cell content (intent: background color)
|
||||
* @remark After writing the number, the format is reset.
|
||||
*/
|
||||
static void show_cell(size_t n, const char *color)
|
||||
{
|
||||
// goto upper-left corner of a cell (the cell starts with an upper and left gap)
|
||||
size_t y = 1 + n / SIZE * (GAP_HEIGHT + CELL_HEIGHT);
|
||||
size_t x = 1 + n % SIZE * (GAP_WIDTH + CELL_WIDTH);
|
||||
|
||||
size_t row = show_h_gap(y, x);
|
||||
for(size_t i = 0; i < CELL_HEIGHT; i++) {
|
||||
size_t col = x;
|
||||
col = show_bar(row, col, GAP_WIDTH, GAP);
|
||||
col = show_bar(row, col, CELL_WIDTH, color);
|
||||
col = show_bar(row, col, GAP_WIDTH, GAP);
|
||||
row++;
|
||||
}
|
||||
row = show_h_gap(row, x);
|
||||
show_cell_nr(y + GAP_HEIGHT, x + GAP_WIDTH, n + 1, color);
|
||||
goto_pos(row, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Renders the given player's name in the given background color.
|
||||
* @param player [IN] the player to render (select the background color and the name of the player
|
||||
* @remark After writing the content, the format is reset.
|
||||
*/
|
||||
static void print_player(control_player_t player)
|
||||
{
|
||||
switch(player) {
|
||||
case control_player_a:
|
||||
printf(PLAYER_A);
|
||||
printf("Player A");
|
||||
printf(RESET);
|
||||
break;
|
||||
case control_player_b:
|
||||
printf(PLAYER_B);
|
||||
printf("Player B");
|
||||
printf(RESET);
|
||||
break;
|
||||
default:
|
||||
printf(RESET);
|
||||
printf("none");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Displays a label followed by the given player.
|
||||
* @param row [IN] position parameter
|
||||
* @param col [IN] position parameter
|
||||
* @param label [IN] the profixing label
|
||||
* @param player [IN] the player to display
|
||||
*/
|
||||
static void show_player(size_t row, size_t col, const char *label, control_player_t player)
|
||||
{
|
||||
goto_pos(row, col);
|
||||
printf(RESET);
|
||||
col += printf("%s", label);
|
||||
goto_pos(row, col);
|
||||
print_player(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Renders the winner and the next player.
|
||||
* @param winner [IN] the winning player (if any)
|
||||
* @param next [IN] the next player (if any)
|
||||
*/
|
||||
static void show_status(control_player_t winner, control_player_t next)
|
||||
{
|
||||
size_t y = GAP_HEIGHT;
|
||||
size_t x = SIZE * (GAP_WIDTH + CELL_WIDTH) + GAP_WIDTH + GAP_WIDTH;
|
||||
size_t row = y;
|
||||
size_t col = x;
|
||||
|
||||
show_player(row, col, "Winner is: ", winner);
|
||||
row += 2;
|
||||
show_player(row, col, "Next player is: ", next);
|
||||
row += 2;
|
||||
row += 2;
|
||||
goto_pos(row, col);
|
||||
printf("0: exit");
|
||||
row += 2;
|
||||
goto_pos(row, col);
|
||||
printf("1..9: play field");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Renders the board from the status given by the control instance.
|
||||
* @param instance [IN] the instance which holds the control instance
|
||||
*/
|
||||
static void show(view_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
assert(instance->control);
|
||||
puts(CLS);
|
||||
show_status(control_get_winner(instance->control), control_get_player(instance->control));
|
||||
|
||||
for(size_t i = 0; i < CELLS; i++) {
|
||||
const char *color = AVAILABLE;
|
||||
switch(control_get_state(instance->control, i+1)) {
|
||||
case control_player_a:
|
||||
color = PLAYER_A;
|
||||
break;
|
||||
case control_player_b:
|
||||
color = PLAYER_B;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
show_cell(i, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes the input and dsiplays the result.
|
||||
* @param the instance which holds the control instance
|
||||
*/
|
||||
static void notifier_loop(view_t *instance)
|
||||
{
|
||||
show(instance);
|
||||
int c = getchar();
|
||||
while(c != EOF && c != EXIT) {
|
||||
if (isdigit(c)) {
|
||||
control_move(instance->control, c-'0');
|
||||
}
|
||||
show(instance);
|
||||
c = getchar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
void view_init(view_t *instance, control_t *control)
|
||||
{
|
||||
assert(instance);
|
||||
assert(control);
|
||||
instance->control = control;
|
||||
}
|
||||
|
||||
// public API function which is documented in the header file.
|
||||
void view_run(view_t *instance)
|
||||
{
|
||||
if (isatty(STDIN_FILENO)) { // in case of an interactive terminal, the exhoing and buffering is disabled
|
||||
// declare non POSIX function, which is available in glibc, but not in strinct C99 mode
|
||||
void cfmakeraw(struct termios *termios_p);
|
||||
|
||||
// replace original tty IO state...
|
||||
struct termios orig;
|
||||
struct termios raw;
|
||||
cfmakeraw(&raw);
|
||||
tcgetattr(STDIN_FILENO, &orig);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
|
||||
// ...do the work...
|
||||
notifier_loop(instance);
|
||||
// ...and finalle restore original tty IO state
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &orig);
|
||||
} else { // if not an interactive terminal, no tweaking with IO is done
|
||||
notifier_loop(instance);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief MVC - View instance
|
||||
*/
|
||||
#ifndef _VIEW_H_
|
||||
#define _VIEW_H_
|
||||
|
||||
#include "control.h"
|
||||
|
||||
/**
|
||||
* @brief The instance type.
|
||||
*/
|
||||
typedef struct {
|
||||
control_t *control; ///< the instance knows of the control instance
|
||||
} view_t;
|
||||
|
||||
/**
|
||||
* @brief Constructor: initialize the instance memory.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @param control [IN] Dependency Injection of the control instance.
|
||||
*/
|
||||
void view_init(view_t *instance, control_t *control);
|
||||
|
||||
/**
|
||||
* @brief Starts the notifyer loop: accepts input and displays the results.
|
||||
* @param instance [INOUT] The instance which holds the state.
|
||||
* @remark Does only return when termination is requested through the UI.
|
||||
*/
|
||||
void view_run(view_t *instance);
|
||||
|
||||
#endif // _VIEW_H_
|
|
@ -1,445 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
#include "model.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief alias for EXIT_SUCCESS
|
||||
#define OK EXIT_SUCCESS
|
||||
/// @brief alias for EXIT_FAILURE
|
||||
#define FAIL EXIT_FAILURE
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
|
||||
#define TRACE_INDENT "\n " ///< allow for better stdout formatting in case of error
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// test utils
|
||||
static void init_model(model_t *instance, int act)
|
||||
{
|
||||
if (act) printf(TRACE_INDENT "init_model:... ");
|
||||
model_init(instance);
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
if (act) printf("%zd/%zd ", row, col);
|
||||
CU_ASSERT_EQUAL_FATAL(instance->board[row][col], model_state_none);
|
||||
}
|
||||
}
|
||||
if (act) printf(TRACE_INDENT);
|
||||
}
|
||||
|
||||
static void print_board(model_state_t board[MODEL_SIZE][MODEL_SIZE])
|
||||
{
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
printf("{ ");
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
printf("%d ", board[row][col]);
|
||||
}
|
||||
printf("} ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// tests
|
||||
static void test_model_init(void)
|
||||
{
|
||||
// check void model_init(model_t *instance);
|
||||
|
||||
// arrange
|
||||
model_t model;
|
||||
// act & assert
|
||||
init_model(&model, 1);
|
||||
}
|
||||
|
||||
static void test_model_get_state(void)
|
||||
{
|
||||
// check: model_state_t model_get_state(model_t *instance, model_pos_t pos);
|
||||
|
||||
{
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "initial state:... ");
|
||||
print_board(model.board);
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
printf("%zd/%zd ", row, col);
|
||||
CU_ASSERT_EQUAL_FATAL(model_get_state(&model, model_pos(row, col)), model_state_none);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_none, model_state_a, model_state_b },
|
||||
{ model_state_a, model_state_b, model_state_none },
|
||||
{ model_state_b, model_state_none, model_state_a },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "modified state:... ");
|
||||
print_board(model.board);
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
printf("%zd/%zd ", row, col);
|
||||
CU_ASSERT_EQUAL_FATAL(model_get_state(&model, model_pos(row, col)), board[row][col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf(TRACE_INDENT);
|
||||
}
|
||||
|
||||
static void test_model_get_winner(void)
|
||||
{
|
||||
// check: model_state_t model_get_winner(model_t *instance);
|
||||
|
||||
{
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "initial no winner:... ");
|
||||
print_board(model.board);
|
||||
CU_ASSERT_EQUAL_FATAL(model_get_winner(&model), model_state_none);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_none, model_state_a, model_state_b },
|
||||
{ model_state_a, model_state_b, model_state_none },
|
||||
{ model_state_b, model_state_none, model_state_a },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "winner:... ");
|
||||
print_board(model.board);
|
||||
CU_ASSERT_EQUAL_FATAL(model_get_winner(&model), model_state_b);
|
||||
}
|
||||
printf(TRACE_INDENT);
|
||||
}
|
||||
|
||||
static void test_model_can_move(void)
|
||||
{
|
||||
// check: int model_can_move(model_t *instance);
|
||||
|
||||
{
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "initial can move:... ");
|
||||
print_board(model.board);
|
||||
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 1);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_none, model_state_a, model_state_a },
|
||||
{ model_state_a, model_state_b, model_state_none },
|
||||
{ model_state_b, model_state_none, model_state_b },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "can move while not yet done nor win:... ");
|
||||
print_board(model.board);
|
||||
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 1);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_none, model_state_a, model_state_b },
|
||||
{ model_state_a, model_state_b, model_state_none },
|
||||
{ model_state_b, model_state_none, model_state_a },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "cannot move after win:... ");
|
||||
print_board(model.board);
|
||||
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 0);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_b, model_state_a, model_state_a },
|
||||
{ model_state_a, model_state_b, model_state_b },
|
||||
{ model_state_b, model_state_a, model_state_a },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "cannot move when all done:... ");
|
||||
print_board(model.board);
|
||||
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 0);
|
||||
}
|
||||
printf(TRACE_INDENT);
|
||||
}
|
||||
|
||||
static void test_model_move(void)
|
||||
{
|
||||
// check: int model_move(model_t *instance, model_pos_t pos, model_state_t state);
|
||||
|
||||
{
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "initial move:... ");
|
||||
print_board(model.board);
|
||||
model_pos_t pos_a = model_pos(0, 0);
|
||||
printf("%zd/%zd ", pos_a.row, pos_a.col);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_a, model_state_a), 1);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_a, model_state_a), 0);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_a, model_state_b), 0);
|
||||
model_pos_t pos_b = model_pos(2, 2);
|
||||
printf("%zd/%zd ", pos_b.row, pos_b.col);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_b, model_state_b), 1);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_b, model_state_b), 0);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_b, model_state_a), 0);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_none, model_state_a, model_state_a },
|
||||
{ model_state_a, model_state_b, model_state_none },
|
||||
{ model_state_b, model_state_none, model_state_b },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "can move while not yet done nor win:... ");
|
||||
print_board(model.board);
|
||||
model_pos_t pos = model_pos(2, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 1);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 0);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_b), 0);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_none, model_state_a, model_state_b },
|
||||
{ model_state_a, model_state_b, model_state_none },
|
||||
{ model_state_b, model_state_none, model_state_a },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "cannot move after win:... ");
|
||||
print_board(model.board);
|
||||
model_pos_t pos = model_pos(2, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 0);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_b), 0);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_b, model_state_a, model_state_a },
|
||||
{ model_state_a, model_state_b, model_state_b },
|
||||
{ model_state_b, model_state_a, model_state_a },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "cannot move when all done:... ");
|
||||
print_board(model.board);
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
model_pos_t pos = model_pos(row, col);
|
||||
printf("%zd/%zd ", row, col);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 0);
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_b), 0);
|
||||
}
|
||||
}
|
||||
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 0);
|
||||
}
|
||||
printf(TRACE_INDENT);
|
||||
}
|
||||
|
||||
static void test_model_get_win_line(void)
|
||||
{
|
||||
// check: model_line_t model_get_win_line(model_t *instance);
|
||||
|
||||
{
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "initial no winner:... ");
|
||||
print_board(model.board);
|
||||
model_line_t no_win = model_get_win_line(&model);
|
||||
CU_ASSERT_EQUAL_FATAL(no_win.dir, model_dir_none);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_none, model_state_a, model_state_a },
|
||||
{ model_state_a, model_state_b, model_state_none },
|
||||
{ model_state_b, model_state_none, model_state_b },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "no winner while not yet done nor win:... ");
|
||||
print_board(model.board);
|
||||
model_line_t no_win = model_get_win_line(&model);
|
||||
CU_ASSERT_EQUAL_FATAL(no_win.dir, model_dir_none);
|
||||
}
|
||||
{
|
||||
// arrange
|
||||
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||||
{ model_state_b, model_state_a, model_state_a },
|
||||
{ model_state_a, model_state_b, model_state_b },
|
||||
{ model_state_b, model_state_a, model_state_a },
|
||||
};
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
memcpy(model.board, board, sizeof(board));
|
||||
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "no winner when all done:... ");
|
||||
print_board(model.board);
|
||||
model_line_t no_win = model_get_win_line(&model);
|
||||
CU_ASSERT_EQUAL_FATAL(no_win.dir, model_dir_none);
|
||||
}
|
||||
{
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(row, col), model_state_a), 1);
|
||||
}
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "row winner:... ");
|
||||
print_board(model.board);
|
||||
model_line_t win = model_get_win_line(&model);
|
||||
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_h);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.row, row);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.col, 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(row, col), model_state_a), 1);
|
||||
}
|
||||
// act & assert
|
||||
printf(TRACE_INDENT "column winner:... ");
|
||||
print_board(model.board);
|
||||
model_line_t win = model_get_win_line(&model);
|
||||
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_v);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.row, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.col, col);
|
||||
}
|
||||
}
|
||||
{
|
||||
printf(TRACE_INDENT "diagonal left-right winner:... ");
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
for(size_t i = 0; i < MODEL_SIZE; i++) {
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(i, i), model_state_a), 1);
|
||||
}
|
||||
// act & assert
|
||||
print_board(model.board);
|
||||
model_line_t win = model_get_win_line(&model);
|
||||
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_d);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.row, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.col, 0);
|
||||
}
|
||||
{
|
||||
printf(TRACE_INDENT "diagonal right-left winner:... ");
|
||||
// arrange
|
||||
model_t model;
|
||||
init_model(&model, 0);
|
||||
for(size_t i = 0; i < MODEL_SIZE; i++) {
|
||||
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(MODEL_SIZE - 1 - i, i), model_state_a), 1);
|
||||
}
|
||||
// act & assert
|
||||
print_board(model.board);
|
||||
model_line_t win = model_get_win_line(&model);
|
||||
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_d);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.row, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(win.start.col, MODEL_SIZE - 1);
|
||||
}
|
||||
printf(TRACE_INDENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_model_init
|
||||
, test_model_get_state
|
||||
, test_model_get_winner
|
||||
, test_model_can_move
|
||||
, test_model_move
|
||||
, test_model_get_win_line
|
||||
);
|
||||
}
|
Binary file not shown.
|
@ -1,9 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/integer-rechner
|
||||
MODULES := src/calc.c src/scan.c src/stack.c src/eval.c src/error.c
|
||||
SOURCES := src/main.c $(MODULES)
|
||||
TSTSOURCES := tests/tests.c $(MODULES)
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P06 Integer Rechner
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab on usage of arrays.
|
||||
*
|
||||
*/
|
|
@ -1,168 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "calc.h"
|
||||
#include "eval.h"
|
||||
#include "error.h"
|
||||
|
||||
/**
|
||||
* @brief The details of the otherwise opaque type.
|
||||
*/
|
||||
struct calc {
|
||||
scan_t *scan; ///< DI: the scanner (this instance does not take over ownership)
|
||||
eval_t *eval; ///< DI: the evaluator (this instance does not take over ownership)
|
||||
};
|
||||
|
||||
static void parse_expression(calc_t *instance);
|
||||
|
||||
static eval_op_t unary_tk2op(int tk) {
|
||||
switch(tk) {
|
||||
case '~': return OP_INV;
|
||||
case '+': return OP_NOP;
|
||||
case '-': return OP_CHS;
|
||||
default:
|
||||
error_fatal("not supported unary op");
|
||||
return OP_NOP;
|
||||
}
|
||||
}
|
||||
|
||||
static eval_op_t binary_tk2op(int tk) {
|
||||
switch(tk) {
|
||||
case '|': return OP_BIT_OR;
|
||||
case '^': return OP_BIT_XOR;
|
||||
case '&': return OP_BIT_AND;
|
||||
case TK_LSHIFT: return OP_BIT_LEFT;
|
||||
case TK_RSHIFT: return OP_BIT_RIGHT;
|
||||
case '+': return OP_ADD;
|
||||
case '-': return OP_SUB;
|
||||
case '*': return OP_MUL;
|
||||
case '/': return OP_DIV;
|
||||
case '%': return OP_MOD;
|
||||
default:
|
||||
error_fatal("not supported binary op");
|
||||
return OP_NOP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int parse_optional_op(calc_t *instance, const int ops[])
|
||||
{
|
||||
assert(instance);
|
||||
assert(ops);
|
||||
const int *op = ops;
|
||||
while(*op && *op != scan_curr_token(instance->scan)) op++;
|
||||
if (*op) scan_next_token(instance->scan);
|
||||
return *op;
|
||||
}
|
||||
|
||||
static void parse_unary_op(calc_t *instance, void (*parse)(calc_t *), const int ops[])
|
||||
{
|
||||
assert(instance);
|
||||
int op = parse_optional_op(instance, ops);
|
||||
if (op) {
|
||||
parse_unary_op(instance, parse, ops);
|
||||
eval_op(instance->eval, unary_tk2op(op));
|
||||
}
|
||||
else {
|
||||
(*parse)(instance);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_binary_op(calc_t *instance, void (*parse)(calc_t *), const int ops[])
|
||||
{
|
||||
assert(instance);
|
||||
(*parse)(instance);
|
||||
int op = parse_optional_op(instance, ops);
|
||||
while (op) {
|
||||
(*parse)(instance);
|
||||
eval_op(instance->eval, binary_tk2op(op));
|
||||
op = parse_optional_op(instance, ops);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_nested_expression(calc_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
// printf("parse_nested\n");
|
||||
if ('(' != scan_curr_token(instance->scan)) error_fatal("number or '(' ... ')' expected");
|
||||
if (scan_next_token(instance->scan) == TK_EOT) error_fatal("expression expected");
|
||||
parse_expression(instance);
|
||||
if (scan_curr_token(instance->scan) != ')') error_fatal("closing ')' expected");
|
||||
scan_next_token(instance->scan);
|
||||
}
|
||||
|
||||
static void parse_number(calc_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
// printf("parse_number\n");
|
||||
if (scan_curr_token(instance->scan) != TK_NUM) error_fatal("number expected");
|
||||
eval_number(instance->eval, scan_curr_value(instance->scan));
|
||||
scan_next_token(instance->scan);
|
||||
}
|
||||
|
||||
static void parse_primary(calc_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
// printf("parse_primary(%d)\n", scan_curr_token(instance->scan));
|
||||
int t = scan_curr_token(instance->scan);
|
||||
if (t == TK_NUM) parse_number(instance);
|
||||
else if (t == '(') parse_nested_expression(instance);
|
||||
else error_fatal("number or '(' ... ')' expected");
|
||||
}
|
||||
|
||||
static void parse_unary(calc_t *instance) { parse_unary_op(instance, parse_primary, (const int[]){ '+', '-', '~', 0 }); }
|
||||
|
||||
static void parse_mul(calc_t *instance) { parse_binary_op(instance, parse_unary, (const int[]){ '*', '/', '%', 0 }); }
|
||||
|
||||
static void parse_sum(calc_t *instance) { parse_binary_op(instance, parse_mul, (const int[]){ '+', '-', 0 }); }
|
||||
|
||||
static void parse_bit_shift(calc_t *instance) { parse_binary_op(instance, parse_sum, (const int[]){ TK_LSHIFT, TK_RSHIFT, 0 }); }
|
||||
|
||||
static void parse_bit_and(calc_t *instance) { parse_binary_op(instance, parse_bit_shift, (const int[]){ '&', 0 }); }
|
||||
|
||||
static void parse_bit_xor(calc_t *instance) { parse_binary_op(instance, parse_bit_and, (const int[]){ '^', 0 }); }
|
||||
|
||||
static void parse_bit_or(calc_t *instance) { parse_binary_op(instance, parse_bit_xor, (const int[]){ '|', 0 }); }
|
||||
|
||||
static void parse_expression(calc_t *instance) { parse_bit_or(instance); }
|
||||
|
||||
|
||||
calc_t *calc_new(scan_t *scan, eval_t *eval)
|
||||
{
|
||||
assert(scan);
|
||||
assert(eval);
|
||||
calc_t *instance = malloc(sizeof(calc_t));
|
||||
if (!instance) error_fatal_errno("calc_new: instance");
|
||||
instance->scan = scan;
|
||||
instance->eval = eval;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void calc_destroy(calc_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void calc_execute(calc_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
if (scan_next_token(instance->scan) == TK_EOT) error_fatal("missing expression text");
|
||||
parse_expression(instance);
|
||||
// printf("excess = %d\n", scan_curr_token(instance->scan));
|
||||
if (scan_curr_token(instance->scan) != TK_EOT) error_fatal("excess expression text found");
|
||||
|
||||
eval_result(instance->eval);
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Infix calculator
|
||||
*/
|
||||
|
||||
#ifndef _CALC_H_
|
||||
#define _CALC_H_
|
||||
|
||||
#include "scan.h"
|
||||
#include "eval.h"
|
||||
|
||||
/**
|
||||
* @brief Opaque type - detailed in the implementation only.
|
||||
*/
|
||||
typedef struct calc calc_t;
|
||||
|
||||
/**
|
||||
* @brief Construcor.
|
||||
* @param scan [IN] Dependency Injection: the serving scanner.
|
||||
* @param eval [IN] Dependency Injection: the serving evaluator.
|
||||
* @return The newly created and initialized instance
|
||||
* @remark In case of error, the program terminates with EXIT_FAILURE and an appropriate error message.
|
||||
* @remark Does not take over ownership of the injected dependencies.
|
||||
*/
|
||||
calc_t *calc_new(scan_t *scan, eval_t *eval);
|
||||
|
||||
/**
|
||||
* @brief Frees the instances memory and the data it owns.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void calc_destroy(calc_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Entry point for processing the expression from stdin.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void calc_execute(calc_t *instance);
|
||||
|
||||
#endif // _CALC_H_
|
|
@ -1,36 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Errors
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "error.h"
|
||||
|
||||
static size_t context = 0;
|
||||
void error_set_pos(size_t pos)
|
||||
{
|
||||
context = pos;
|
||||
}
|
||||
|
||||
void error_fatal(const char message[])
|
||||
{
|
||||
fprintf(stderr, "ERROR: at or near position %zd: %s\n", context, message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void error_fatal_errno(const char message[])
|
||||
{
|
||||
fprintf(stderr, "ERROR: at or near position %zd: ", context);
|
||||
perror(message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Error handling
|
||||
*/
|
||||
|
||||
#ifndef _ERROR_H_
|
||||
#define _ERROR_H_
|
||||
|
||||
/**
|
||||
* @brief Sets the context of the current token for potential error reports.
|
||||
* @param pos [IN] The current input start position of the token which is currently processed.
|
||||
*/
|
||||
void error_set_pos(size_t pos);
|
||||
|
||||
/**
|
||||
* @brief Issues on stderr an error message and terminates the program with EXIT_FAILURE.
|
||||
* @param message [IN] Context information.
|
||||
*/
|
||||
void error_fatal(const char message[]);
|
||||
|
||||
/**
|
||||
* @brief Issues on stderr an error message (includeing the errno text) and terminates the program with EXIT_FAILURE.
|
||||
* @param message [IN] Context information.
|
||||
*/
|
||||
void error_fatal_errno(const char message[]);
|
||||
|
||||
#endif // _ERROR_H_
|
|
@ -1,244 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief RPN Evaluator
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "eval.h"
|
||||
#include "error.h"
|
||||
|
||||
/**
|
||||
* @brief The details of the otherwise opaque type.
|
||||
*/
|
||||
struct eval {
|
||||
stack_t *stack; ///< DI: the stack (this instance does not take over ownership)
|
||||
int verbose; ///< verbosity control (0 = silent, 1 = verbose)
|
||||
};
|
||||
|
||||
static void write_op(FILE *fd, eval_op_t op)
|
||||
{
|
||||
switch(op) {
|
||||
case OP_NOP: fprintf(fd, "OP_NOP\n"); break;
|
||||
case OP_PRINT_HEX: fprintf(fd, "OP_PRINT_HEX\n"); break;
|
||||
case OP_PRINT_DEC: fprintf(fd, "OP_PRINT_DEC\n"); break;
|
||||
case OP_PRINT_OCT: fprintf(fd, "OP_PRINT_OCT\n"); break;
|
||||
case OP_PRINT_BIN: fprintf(fd, "OP_PRINT_BIN\n"); break;
|
||||
case OP_BIT_OR: fprintf(fd, "OP_BIT_OR\n"); break;
|
||||
case OP_BIT_XOR: fprintf(fd, "OP_BIT_XOR\n"); break;
|
||||
case OP_BIT_AND: fprintf(fd, "OP_BIT_AND\n"); break;
|
||||
case OP_BIT_LEFT: fprintf(fd, "OP_BIT_LEFT\n"); break;
|
||||
case OP_BIT_RIGHT: fprintf(fd, "OP_BIT_RIGHT\n"); break;
|
||||
case OP_ADD: fprintf(fd, "OP_ADD\n"); break;
|
||||
case OP_SUB: fprintf(fd, "OP_SUB\n"); break;
|
||||
case OP_MUL: fprintf(fd, "OP_MUL\n"); break;
|
||||
case OP_DIV: fprintf(fd, "OP_DIV\n"); break;
|
||||
case OP_MOD: fprintf(fd, "OP_MOD\n"); break;
|
||||
case OP_CHS: fprintf(fd, "OP_CHS\n"); break;
|
||||
case OP_INV: fprintf(fd, "OP_INV\n"); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_value(FILE *fd, eval_op_t op, unsigned int value)
|
||||
{
|
||||
const unsigned int top_bit = 1 << (sizeof(unsigned int) * 8 - 1);
|
||||
switch(op) {
|
||||
case OP_PRINT_HEX:
|
||||
fprintf(fd, "hex=0x%0*x\n", (int)(sizeof(unsigned int)*2), value);
|
||||
break;
|
||||
case OP_PRINT_DEC:
|
||||
fprintf(fd, "dec=%d\n", value);
|
||||
break;
|
||||
case OP_PRINT_OCT:
|
||||
fprintf(fd, "oct=0%0*o\n", (int)((sizeof(unsigned int)*8+2)/3), value);
|
||||
break;
|
||||
case OP_PRINT_BIN:
|
||||
fprintf(fd, "bin=0b");
|
||||
for(size_t i = 0; i < sizeof(unsigned int)*8; i++) {
|
||||
fputc((value & top_bit) ? '1' : '0', fd);
|
||||
value <<= 1;
|
||||
}
|
||||
fputc('\n', fd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int eval_top(eval_t *instance, eval_op_t op)
|
||||
{
|
||||
assert(instance);
|
||||
assert(instance->stack);
|
||||
|
||||
switch(op) {
|
||||
case OP_NOP:
|
||||
return 1;
|
||||
case OP_PRINT_HEX:
|
||||
case OP_PRINT_DEC:
|
||||
case OP_PRINT_OCT:
|
||||
case OP_PRINT_BIN:
|
||||
write_value(stdout, op, stack_top(instance->stack));
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eval_unary(eval_t *instance, eval_op_t op)
|
||||
{
|
||||
assert(instance);
|
||||
assert(instance->stack);
|
||||
|
||||
unsigned int v;
|
||||
switch(op) {
|
||||
case OP_CHS:
|
||||
v = stack_pop(instance->stack);
|
||||
stack_push(instance->stack, -v);
|
||||
return 1;
|
||||
case OP_INV:
|
||||
// 1. implement the ~ operator analogous to the - sign operator above
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eval_binary(eval_t *instance, eval_op_t op)
|
||||
{
|
||||
assert(instance);
|
||||
assert(instance->stack);
|
||||
|
||||
unsigned int a;
|
||||
unsigned int b;
|
||||
|
||||
switch(op) {
|
||||
case OP_ADD:
|
||||
b = stack_pop(instance->stack);
|
||||
a = stack_pop(instance->stack);
|
||||
stack_push(instance->stack, a + b);
|
||||
return 1;
|
||||
case OP_SUB:
|
||||
b = stack_pop(instance->stack);
|
||||
a = stack_pop(instance->stack);
|
||||
stack_push(instance->stack, a - b);
|
||||
return 1;
|
||||
case OP_MUL:
|
||||
b = stack_pop(instance->stack);
|
||||
a = stack_pop(instance->stack);
|
||||
stack_push(instance->stack, a * b);
|
||||
return 1;
|
||||
case OP_DIV:
|
||||
b = stack_pop(instance->stack);
|
||||
a = stack_pop(instance->stack);
|
||||
stack_push(instance->stack, a / b);
|
||||
return 1;
|
||||
case OP_MOD:
|
||||
b = stack_pop(instance->stack);
|
||||
a = stack_pop(instance->stack);
|
||||
stack_push(instance->stack, a % b);
|
||||
return 1;
|
||||
case OP_BIT_OR:
|
||||
// 1. implement the | operator analogous to the * operator above
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
case OP_BIT_XOR:
|
||||
// 1. implement the ^ operator analogous to the * operator above
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
case OP_BIT_AND:
|
||||
// 1. implement the & operator analogous to the * operator above
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
case OP_BIT_LEFT:
|
||||
// 1. implement the << operator analogous to the * operator above
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
case OP_BIT_RIGHT:
|
||||
// 1. implement the >> operator analogous to the * operator above
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
eval_t *eval_new(stack_t *stack, int verbose)
|
||||
{
|
||||
assert(stack);
|
||||
eval_t *instance = malloc(sizeof(eval_t));
|
||||
if (!instance) error_fatal_errno("eval_new: instance");
|
||||
instance->stack = stack;
|
||||
instance->verbose = verbose;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void eval_destroy(eval_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void eval_number(eval_t *instance, unsigned int value)
|
||||
{
|
||||
assert(instance);
|
||||
stack_push(instance->stack, value);
|
||||
if (instance->verbose) write_value(stderr, OP_PRINT_HEX, value);
|
||||
}
|
||||
|
||||
void eval_op(eval_t *instance, eval_op_t op)
|
||||
{
|
||||
if (eval_top(instance, op) || eval_unary(instance, op) || eval_binary(instance, op)) {
|
||||
// successfully evaluated
|
||||
if (instance->verbose) write_op(stderr, op);
|
||||
} else {
|
||||
error_fatal("eval_op: unknown op");
|
||||
}
|
||||
}
|
||||
|
||||
void eval_result(eval_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
unsigned int v = stack_top(instance->stack);
|
||||
printf("--- RESULT ---\n");
|
||||
write_value(stdout, OP_PRINT_DEC, v);
|
||||
write_value(stdout, OP_PRINT_HEX, v);
|
||||
write_value(stdout, OP_PRINT_OCT, v);
|
||||
write_value(stdout, OP_PRINT_BIN, v);
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief RPN Evaluator
|
||||
*/
|
||||
#ifndef _EVAL_H_
|
||||
#define _EVAL_H_
|
||||
|
||||
#include "stack.h"
|
||||
|
||||
/**
|
||||
* @brief All RPN Operators.
|
||||
*/
|
||||
typedef enum {
|
||||
OP_NOP, ///< no operation
|
||||
OP_PRINT_HEX, ///< print as hex
|
||||
OP_PRINT_DEC, ///< print as dec
|
||||
OP_PRINT_OCT, ///< print as oct
|
||||
OP_PRINT_BIN, ///< print as bin
|
||||
OP_BIT_OR, ///< unsigned integer bit or
|
||||
OP_BIT_XOR, ///< unsigned integer bit xor
|
||||
OP_BIT_AND, ///< unsigned integer bit and
|
||||
OP_BIT_LEFT, ///< unsigned integer shift-left
|
||||
OP_BIT_RIGHT, ///< unsigned integer shift-right
|
||||
OP_ADD, ///< unsigned integer addition
|
||||
OP_SUB, ///< unsigned integer subtraction
|
||||
OP_MUL, ///< unsigned integer multiplication
|
||||
OP_DIV, ///< unsigned integer division
|
||||
OP_MOD, ///< unsigned integer modulo
|
||||
OP_CHS, ///< unsigned integer twos-complement
|
||||
OP_INV, ///< unsigned integer ones-complement
|
||||
} eval_op_t;
|
||||
|
||||
/**
|
||||
* @brief Opaque type - detailed in the implementation only.
|
||||
*/
|
||||
typedef struct eval eval_t;
|
||||
|
||||
/**
|
||||
* @brief Construcor.
|
||||
* @param stack [IN] Dependency Injection: the serving stack.
|
||||
* @param verbose [IN] Cointrol debug output (stderr): 0 = no output, 1 = additional output.
|
||||
* @return The newly created and initialized instance
|
||||
* @remark In case of error, the program terminates with EXIT_FAILURE and an appropriate error message.
|
||||
* @remark Does not take over ownership of the injected dependencies.
|
||||
*/
|
||||
eval_t *eval_new(stack_t *stack, int verbose);
|
||||
|
||||
/**
|
||||
* @brief Frees the instances memory and the data it owns.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void eval_destroy(eval_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Feeds the value in RPN sequence to the evaluator.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @param value [IN] The value to stack on the RPN calculator.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void eval_number(eval_t *instance, unsigned int value);
|
||||
|
||||
/**
|
||||
* @brief Feeds the operation in RPN sequence to the evaluator.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @param op [IN] The operator to evaluate.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void eval_op(eval_t *instance, eval_op_t op);
|
||||
|
||||
/**
|
||||
* @brief Prints the top entry of the stack.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void eval_result(eval_t *instance);
|
||||
|
||||
#endif // _EVAL_H_
|
|
@ -1,42 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "calc.h"
|
||||
|
||||
/**
|
||||
* @brief Main entry point.
|
||||
* @param[in] argc The size of the argv array.
|
||||
* @param[in] argv The command line arguments...
|
||||
* @returns Returns EXIT_SUCCESS (=0) on success, EXIT_FAILURE (=1) there is an expression syntax error.
|
||||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int verbose = argc > 1 && strtol(argv[1], NULL, 10);
|
||||
|
||||
const size_t stack_size = 10;
|
||||
stack_t *stack = stack_new(stack_size);
|
||||
eval_t *eval = eval_new(stack, verbose);
|
||||
scan_t *scan = scan_new();
|
||||
calc_t *calc = calc_new(scan, eval);
|
||||
|
||||
calc_execute(calc);
|
||||
|
||||
calc_destroy(calc);
|
||||
scan_destroy(scan);
|
||||
eval_destroy(eval);
|
||||
stack_destroy(stack);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Infix calculator tokenizer
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "scan.h"
|
||||
#include "error.h"
|
||||
|
||||
/**
|
||||
* @brief The details of the otherwise opaque type.
|
||||
*/
|
||||
struct scan {
|
||||
size_t count; ///< counts the read characters (used for error reporting)
|
||||
int la; ///< look-ahead-1 character
|
||||
int token; ///< the currently recognized token
|
||||
unsigned int value; ///< the current TK_NUM value
|
||||
};
|
||||
|
||||
|
||||
static int next_char(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
instance->la = getc(stdin);
|
||||
if (instance->la != EOF) instance->count++;
|
||||
return instance->la;
|
||||
}
|
||||
|
||||
static int curr_char(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
return instance->la;
|
||||
}
|
||||
|
||||
static int skip_chars(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
while(instance->la != EOF && isspace(instance->la)) next_char(instance);
|
||||
return instance->la;
|
||||
}
|
||||
|
||||
static int eof(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
// printf("eof?\n");
|
||||
if (curr_char(instance) == EOF) {
|
||||
instance->token = TK_EOT;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int op1(scan_t *instance, const char ops[])
|
||||
{
|
||||
assert(instance);
|
||||
// printf("op1?\n");
|
||||
assert(ops);
|
||||
if (strchr(ops, curr_char(instance))) {
|
||||
instance->token = curr_char(instance);
|
||||
next_char(instance);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int op2(scan_t *instance, const char *op, int t)
|
||||
{
|
||||
assert(instance);
|
||||
// printf("op2?\n");
|
||||
assert(op);
|
||||
assert(strlen(op) == 2);
|
||||
if (curr_char(instance) == op[0] && next_char(instance) == op[1]) {
|
||||
instance->token = t;
|
||||
next_char(instance);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int number(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
// printf("number\n");
|
||||
int c = curr_char(instance);
|
||||
if (c == '0') {
|
||||
instance->value = 0;
|
||||
instance->token = TK_NUM;
|
||||
c = next_char(instance);
|
||||
if (strchr("xX", c)) {
|
||||
instance->token = TK_ERROR;
|
||||
c = next_char(instance);
|
||||
while(isxdigit(c) || c == '_') {
|
||||
if (c != '_') {
|
||||
instance->value *= 16;
|
||||
instance->token = TK_NUM;
|
||||
if (isdigit(c)) {
|
||||
instance->value += c - '0';
|
||||
} else {
|
||||
instance->value += 10 + c - (isupper(c) ? 'A' : 'a');
|
||||
}
|
||||
}
|
||||
c = next_char(instance);
|
||||
}
|
||||
} else if (strchr("bB", c)) {
|
||||
instance->token = TK_ERROR;
|
||||
c = next_char(instance);
|
||||
while(strchr("01_", c)) {
|
||||
if (c != '_') {
|
||||
instance->value *= 2;
|
||||
instance->value += c - '0';
|
||||
instance->token = TK_NUM;
|
||||
}
|
||||
c = next_char(instance);
|
||||
}
|
||||
} else if (strchr("01234567_", c)) {
|
||||
while(strchr("01234567_", c)) {
|
||||
if (c != '_') {
|
||||
instance->value *= 8;
|
||||
instance->value += c - '0';
|
||||
}
|
||||
c = next_char(instance);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
} else if (isdigit(c)) {
|
||||
instance->value = 0;
|
||||
while(isdigit(c) || c == '_') {
|
||||
if (c != '_') {
|
||||
instance->value *= 10;
|
||||
instance->value += c - '0';
|
||||
c = next_char(instance);
|
||||
}
|
||||
}
|
||||
instance->token = TK_NUM;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
scan_t *scan_new()
|
||||
{
|
||||
scan_t *instance = malloc(sizeof(scan_t));
|
||||
if (!instance) error_fatal_errno("scan_new: instance");
|
||||
instance->count = 0;
|
||||
instance->la = EOF;
|
||||
instance->token = TK_EOT;
|
||||
instance->value = 0;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void scan_destroy(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
int scan_next_token(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
// printf("next...\n");
|
||||
int c = curr_char(instance);
|
||||
if (c == EOF) c = next_char(instance); // initial (or final) situation
|
||||
c = skip_chars(instance);
|
||||
error_set_pos(instance->count);
|
||||
|
||||
instance->token = TK_ERROR;
|
||||
instance->value = 0;
|
||||
|
||||
if (eof(instance) || op1(instance, "+-*%/|^&~()") || op2(instance, "<<", TK_LSHIFT) || op2(instance, ">>", TK_RSHIFT) || number(instance)) {
|
||||
// one of the above was found
|
||||
skip_chars(instance);
|
||||
}
|
||||
|
||||
// printf("next = %d\n", token);
|
||||
return instance->token;
|
||||
}
|
||||
|
||||
int scan_curr_token(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
return instance->token;
|
||||
}
|
||||
|
||||
unsigned int scan_curr_value(scan_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
if (scan_curr_token(instance) != TK_NUM) error_fatal_errno("scan_curr_value: wrong token");
|
||||
return instance->value;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Infix calculator tokenizer
|
||||
*/
|
||||
|
||||
#ifndef _SCAN_H_
|
||||
#define _SCAN_H_
|
||||
|
||||
/**
|
||||
* @brief Opaque type - detailed in the implementation only.
|
||||
*/
|
||||
typedef struct scan scan_t;
|
||||
|
||||
/**
|
||||
* @brief Specific token enum values beside the ones provided as plain characters.
|
||||
* @remark The last enum value must be below printable ascii code
|
||||
*/
|
||||
typedef enum {
|
||||
TK_ERROR = 0, ///< error or end mark for arrays of tokens (must be 0)
|
||||
TK_EOT, ///< end of text, i.e. when EOF is recognized
|
||||
TK_LSHIFT, ///< left-shift operator (2-char token)
|
||||
TK_RSHIFT, ///< right-shift operator (2-char token)
|
||||
TK_NUM, ///< number token (e.g. 3, 0x1F, etc.)
|
||||
} scan_tk_t;
|
||||
|
||||
/**
|
||||
* @brief Construcor.
|
||||
* @return The newly created and initialized instance
|
||||
* @remark In case of error, the program terminates with EXIT_FAILURE and an appropriate error message.
|
||||
*/
|
||||
scan_t *scan_new();
|
||||
|
||||
/**
|
||||
* @brief Frees the instances memory and the data it owns.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void scan_destroy(scan_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Moves to the next token.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @return Returns the next recognized token (single character token or scan_tk_t enum value).
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
* @remark If the token is a TK_NUM, the scan_curr_value() function returns the associated value.
|
||||
*/
|
||||
int scan_next_token(scan_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Gets the token which mas found with the last scan_next_token() call.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @return Returns the currently recognized token (single character token or scan_tk_t enum value).
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
int scan_curr_token(scan_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Gets the value associated with the TK_NUM token.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @return Returns the value associated with the current TK_NUM.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
* @remark This only gives valid values if the scan_curr_token() equals TK_NUM.
|
||||
*/
|
||||
unsigned int scan_curr_value(scan_t *instance);
|
||||
|
||||
#endif // _SCAN_H_
|
|
@ -1,132 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Stack
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "stack.h"
|
||||
#include "error.h"
|
||||
|
||||
/**
|
||||
* @brief The details of the otherwise opaque type.
|
||||
*/
|
||||
struct stack {
|
||||
stack_value_t *stack; ///< the data container (the instance owns this)
|
||||
stack_value_t *top; ///< the pointer into the container where the current top data resides (has to point initially to stack-1)
|
||||
stack_value_t *full; ///< the pointer to the last entry of the conatainer
|
||||
};
|
||||
|
||||
stack_t *stack_new(size_t max_elements)
|
||||
{
|
||||
stack_t *instance = NULL;
|
||||
// 1. allocate a stack_t instance on the heap and set the instance variable to it
|
||||
// 2. call error_fatal_errno("stack_new: instance"); if failed to allocate the memory on the heap
|
||||
// 3. allocate an array of max_elements value_t's on the heap and store its address in the stack member of the stack_t instance
|
||||
// 4. call error_fatal_errno("stack_new: stack"); if failed to allocate the memory on the heap
|
||||
// 5. set the top member of the stack_t instance to the address of the "element" before the first stack array element
|
||||
// 6. set the full member of the stack_t instance to the address of the last element of the stack array
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return instance;
|
||||
}
|
||||
|
||||
void stack_destroy(stack_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
// 1. free the stack array
|
||||
// 2. free the stack_t instance
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
void stack_push(stack_t *instance, stack_value_t value)
|
||||
{
|
||||
assert(instance);
|
||||
if (stack_is_full(instance)) error_fatal("stack_push: full");
|
||||
// 1. increment by one element the address stored in the top member of the stack_t instance
|
||||
// 2. store the received value at the new top location
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
stack_value_t stack_pop(stack_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
if (stack_is_empty(instance)) error_fatal("stack_pop: empty");
|
||||
stack_value_t value = 0;
|
||||
// 1. set the variable value to the value from the address the top member points to
|
||||
// 2. decrement by one element the address stored in the top member of the stack_t instance
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return value;
|
||||
}
|
||||
|
||||
stack_value_t stack_top(stack_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
if (stack_is_empty(instance)) error_fatal("stack_top: empty");
|
||||
stack_value_t value = 0;
|
||||
// 1. set the variable value to the value from the address the top member points to
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return value;
|
||||
}
|
||||
|
||||
int stack_is_empty(stack_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
int is_empty = 1;
|
||||
// 1. set is_empty to 1 if the top equals the initial condition as done in stack_new(), otherwise to 0
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return is_empty;
|
||||
}
|
||||
|
||||
int stack_is_full(stack_t *instance)
|
||||
{
|
||||
assert(instance);
|
||||
int is_full = 1;
|
||||
// 1. set is_full to 1 if the top equals the full pointer as set in the stack_new() function, otherwise 0
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return is_full;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Stack
|
||||
*/
|
||||
|
||||
#ifndef _STACK_H_
|
||||
#define _STACK_H_
|
||||
|
||||
/**
|
||||
* @brief Convenience alias.
|
||||
*/
|
||||
typedef unsigned int stack_value_t;
|
||||
|
||||
/**
|
||||
* @brief Opaque type - detailed in the implementation only.
|
||||
*/
|
||||
typedef struct stack stack_t;
|
||||
|
||||
/**
|
||||
* @brief Construcor.
|
||||
* @param max_elements [IN] Gives the size of the stack.
|
||||
* @return The newly created and initialized instance
|
||||
* @remark In case of error, the program terminates with EXIT_FAILURE and an appropriate error message.
|
||||
*/
|
||||
stack_t *stack_new(size_t max_elements);
|
||||
|
||||
/**
|
||||
* @brief Frees the instances memory and the data it owns (i.e. the stack container).
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void stack_destroy(stack_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Pushes the value to the stack.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @param value [IN] The value to pus.
|
||||
* @remark In case of error, the program terminates with EXIT_FAILURE and an appropriate error message.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
void stack_push(stack_t *instance, stack_value_t value);
|
||||
|
||||
/**
|
||||
* @brief Removes the top stack entry and returns it.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @return Returns the top most entry.
|
||||
* @remark In case of error, the program terminates with EXIT_FAILURE and an appropriate error message.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
stack_value_t stack_pop(stack_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Gets the top stack entry.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @return Returns the top most entry.
|
||||
* @remark In case of error, the program terminates with EXIT_FAILURE and an appropriate error message.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
stack_value_t stack_top(stack_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Queries if the stack is empty - i.e. if a pop operation is possible.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @return Returns 1 if empry, 0 otherwise.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
int stack_is_empty(stack_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Queries if the stack is full - i.e. if a push operation is possible.
|
||||
* @param instance [INOUT] The affected instance.
|
||||
* @return Returns 1 if full, 0 otherwise.
|
||||
* @remark assert(instance) is performed, i.e. it is considered a programming error if instance is NULL.
|
||||
*/
|
||||
int stack_is_full(stack_t *instance);
|
||||
|
||||
#endif // _STACK_H_
|
|
@ -1,263 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
#include "stack.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief alias for EXIT_SUCCESS
|
||||
#define OK EXIT_SUCCESS
|
||||
/// @brief alias for EXIT_FAILURE
|
||||
#define FAIL EXIT_FAILURE
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
|
||||
#define TRACE_INDENT "\n " ///< allow for better stdout formatting in case of error
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// tests
|
||||
static void test_stack_new(void)
|
||||
{
|
||||
// arrange
|
||||
const size_t size = 2;
|
||||
// act
|
||||
stack_t *instance = stack_new(size);
|
||||
// assert
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(instance);
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 1);
|
||||
// cleanup
|
||||
stack_destroy(instance);
|
||||
}
|
||||
|
||||
static void test_stack_push(void)
|
||||
{
|
||||
// arrange
|
||||
const size_t size = 2;
|
||||
stack_t *instance = stack_new(size);
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(instance);
|
||||
// act & assert
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
stack_push(instance, i);
|
||||
CU_ASSERT_EQUAL(stack_top(instance), i);
|
||||
}
|
||||
// cleanup
|
||||
stack_destroy(instance);
|
||||
}
|
||||
|
||||
static void test_stack_top(void)
|
||||
{
|
||||
// arrange
|
||||
const size_t size = 2;
|
||||
stack_t *instance = stack_new(size);
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(instance);
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 1);
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 0);
|
||||
stack_push(instance, i);
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 0);
|
||||
CU_ASSERT_EQUAL(stack_top(instance), i);
|
||||
}
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 1);
|
||||
// cleanup
|
||||
stack_destroy(instance);
|
||||
}
|
||||
|
||||
static void test_stack_pop(void)
|
||||
{
|
||||
// arrange
|
||||
const size_t size = 2;
|
||||
stack_t *instance = stack_new(size);
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(instance);
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
stack_push(instance, i);
|
||||
}
|
||||
// act & assert
|
||||
for(size_t i = size; i > 0; i--) {
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 0);
|
||||
CU_ASSERT_EQUAL(stack_pop(instance), i-1);
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 0);
|
||||
}
|
||||
// cleanup
|
||||
stack_destroy(instance);
|
||||
}
|
||||
|
||||
static void test_stack_is_empty(void)
|
||||
{
|
||||
// arrange
|
||||
const size_t size = 2;
|
||||
stack_t *instance = stack_new(size);
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(instance);
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 1);
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
stack_push(instance, i);
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 0);
|
||||
}
|
||||
for(size_t i = size; i > 0; i--) {
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 0);
|
||||
stack_pop(instance);
|
||||
}
|
||||
CU_ASSERT_EQUAL(stack_is_empty(instance), 1);
|
||||
// cleanup
|
||||
stack_destroy(instance);
|
||||
}
|
||||
|
||||
static void test_stack_is_full(void)
|
||||
{
|
||||
// arrange
|
||||
const size_t size = 2;
|
||||
stack_t *instance = stack_new(size);
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(instance);
|
||||
// act & assert
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 0);
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 0);
|
||||
stack_push(instance, i);
|
||||
}
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 1);
|
||||
for(size_t i = size; i > 0; i--) {
|
||||
stack_pop(instance);
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 0);
|
||||
}
|
||||
CU_ASSERT_EQUAL(stack_is_full(instance), 0);
|
||||
// cleanup
|
||||
stack_destroy(instance);
|
||||
}
|
||||
|
||||
static void test_silent(void)
|
||||
{
|
||||
const char *out_txt[] = {
|
||||
"--- RESULT ---\n",
|
||||
"dec=3\n",
|
||||
"hex=0x00000003\n",
|
||||
"oct=000000000003\n",
|
||||
"bin=0b00000000000000000000000000000011\n",
|
||||
};
|
||||
const char *err_txt[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL_FATAL(WEXITSTATUS(system("echo '1 + 2' | " XSTR(TARGET) " 0 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL_FATAL(WEXITSTATUS(system("echo '1 + 2' | " XSTR(TARGET) " >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
static void test_verbose(void)
|
||||
{
|
||||
const char *out_txt[] = {
|
||||
"--- RESULT ---\n",
|
||||
"dec=3\n",
|
||||
"hex=0x00000003\n",
|
||||
"oct=000000000003\n",
|
||||
"bin=0b00000000000000000000000000000011\n",
|
||||
};
|
||||
const char *err_txt[] = {
|
||||
"hex=0x00000001\n",
|
||||
"hex=0x00000002\n",
|
||||
"OP_ADD\n",
|
||||
};
|
||||
|
||||
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL_FATAL(WEXITSTATUS(system("echo '1 + 2' | " XSTR(TARGET) " 1 >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
static void test_all(void)
|
||||
{
|
||||
const char *out_txt[] = {
|
||||
"--- RESULT ---\n",
|
||||
"dec=8\n",
|
||||
"hex=0x00000008\n",
|
||||
"oct=000000000010\n",
|
||||
"bin=0b00000000000000000000000000001000\n",
|
||||
};
|
||||
const char *err_txt[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL_FATAL(WEXITSTATUS(system("echo '(8 | 7 ^ 5) & 4 << 3 + 2 * (~1+(1>>0))' | " XSTR(TARGET) " >" OUTFILE " 2>" ERRFILE)), OK);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
static void test_error(void)
|
||||
{
|
||||
const char *out_txt[] = {
|
||||
NULL,
|
||||
};
|
||||
const char *err_txt[] = {
|
||||
"ERROR: at or near position 5: number or '(' ... ')' expected\n",
|
||||
};
|
||||
|
||||
// arrange & act & assert
|
||||
CU_ASSERT_EQUAL_FATAL(WEXITSTATUS(system("echo '1 + ' | " XSTR(TARGET) " >" OUTFILE " 2>" ERRFILE)), FAIL);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_stack_new
|
||||
, test_stack_push
|
||||
, test_stack_top
|
||||
, test_stack_pop
|
||||
, test_stack_is_empty
|
||||
, test_stack_is_full
|
||||
, test_silent
|
||||
, test_verbose
|
||||
, test_all
|
||||
, test_error
|
||||
);
|
||||
}
|
Binary file not shown.
|
@ -1,13 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/personen-verwaltung
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
MODULES :=
|
||||
# END-STUDENTS-TO-ADD-CODE
|
||||
SOURCES := src/main.c $(MODULES)
|
||||
TSTSOURCES := tests/tests.c $(MODULES)
|
||||
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
||||
|
||||
# CFLAGS += -Werror
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P07 Linked List
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab on usage of arrays.
|
||||
*
|
||||
*/
|
|
@ -1,29 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* @brief Main entry point.
|
||||
* @param[in] argc The size of the argv array.
|
||||
* @param[in] argv The command line arguments...
|
||||
* @returns Returns EXIT_SUCCESS (=0) on success, EXIT_FAILURE (=1) there is an expression syntax error.
|
||||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief alias for EXIT_SUCCESS
|
||||
#define OK EXIT_SUCCESS
|
||||
/// @brief alias for EXIT_FAILURE
|
||||
#define FAIL EXIT_FAILURE
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
|
||||
#define TRACE_INDENT "\n " ///< allow for better stdout formatting in case of error
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// tests
|
||||
static void test_person_compare(void)
|
||||
{
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
// arrange
|
||||
|
||||
// act
|
||||
CU_FAIL("missing test");
|
||||
|
||||
// assert
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
static void test_list_insert(void)
|
||||
{
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
// arrange
|
||||
|
||||
// act
|
||||
CU_FAIL("missing test");
|
||||
|
||||
// assert
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
static void test_list_remove(void)
|
||||
{
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
// arrange
|
||||
|
||||
// act
|
||||
CU_FAIL("missing test");
|
||||
|
||||
// assert
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
static void test_list_clear(void)
|
||||
{
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
// arrange
|
||||
|
||||
// act
|
||||
CU_FAIL("missing test");
|
||||
|
||||
// assert
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_person_compare
|
||||
, test_list_insert
|
||||
, test_list_remove
|
||||
, test_list_clear
|
||||
);
|
||||
}
|
Binary file not shown.
|
@ -1,11 +0,0 @@
|
|||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/c-get-exec-list
|
||||
MODULES :=
|
||||
SOURCES := src/main.c $(MODULES)
|
||||
TSTSOURCES := tests/tests.c $(MODULES)
|
||||
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
||||
|
||||
# CFLAGS += -Werror
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @mainpage SNP - P08: C implementation of P01-Bash get_exec_list_arg.sh
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab on POSIX file and directory attribute access.
|
||||
*
|
||||
*/
|
|
@ -1,123 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
|
||||
#include <stdlib.h> // getenv, malloc, free, EXIT_SUCCESS, NULL
|
||||
#include <string.h> // strchr
|
||||
#include <stdio.h> // printf, sprintf
|
||||
#include <sys/stat.h> // struct stat, S_ISDIR, S_ISREG
|
||||
#include <unistd.h> // stat, access
|
||||
#include <dirent.h> // opendir, closedir, readdir, DIR, struct dirent
|
||||
|
||||
/**
|
||||
* @brief Creates a copy of the string on the heap.
|
||||
* @param s [IN] The original string.
|
||||
* @return Returns the allocated copy or NULL if s is NULL or if malloc failed.
|
||||
* @remark Suggestion: Use the functions malloc(), strcpy().
|
||||
*/
|
||||
static char *malloc_copy(const char *s)
|
||||
{
|
||||
char *p = NULL;
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces inplace in the buffer all occurances of sep by '\0'.
|
||||
* @param buffer [INOUT] The string which gets searched and modified.
|
||||
* @param sep [IN] The separator for which all instances in buffer get replaced by '\0'.
|
||||
* @return Returns the number of fields which are separated by sep, or 0 if buffer is NULL.
|
||||
* @remark Empty fields are allowed and to be supported, i.e. given by ":..." or by "...::..." or by "...:".
|
||||
* @remark Suggestion: Use the function strchr() to search for the separator.
|
||||
*/
|
||||
static size_t split_buffer_inplace(char buffer[], char sep)
|
||||
{
|
||||
size_t n = 0;
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If path is an executable directory, list all executable files located directly in that directory - each such file as i:path:file.
|
||||
* @param i [IN] The number of the path to report.
|
||||
* @param path [IN] The directory path to search for executables.
|
||||
* @remark Suggestion: Use the function is_accessible_dir(), is_executable_file(), opendir(), readdir(), closedir().
|
||||
*/
|
||||
static void list_executables(size_t i, const char *path)
|
||||
{
|
||||
// bash:
|
||||
// [ -n "$p" ] || p="."
|
||||
// if [ -d "$p" ] && [ -x "$p" ]
|
||||
// then
|
||||
// find -L "$p" -maxdepth 1 -type f -executable -printf "$i:%h:%f\n"
|
||||
// fi
|
||||
const char *p = path && strlen(path) ? path : "."; // replace an empty path by "." as current directory to allow for appending /name
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
|
||||
// # from lab P01_Bash
|
||||
// paths="$1"
|
||||
// [ -n "$paths" ] || paths="$PATH"
|
||||
//
|
||||
// # input-field-separator: tells the shell to split in the 'for' loop the $var by ":"
|
||||
// IFS=":"
|
||||
//
|
||||
// for p in $paths
|
||||
// do
|
||||
// i=$((i+1))
|
||||
// [ -n "$p" ] || p="."
|
||||
// if [ -d "$p" ] && [ -x "$p" ]
|
||||
// then
|
||||
// find -L "$p" -maxdepth 1 -type f -executable -printf "$i:%h:%f\n" 2>/dev/null
|
||||
// fi
|
||||
// done
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
char *paths = malloc_copy(argc > 1 && argv[1][0] ? argv[1] : getenv("PATH"));
|
||||
size_t n = split_buffer_inplace(paths, ':'); // replaces all ':' by '\0' and returns the number of the resulting fields
|
||||
char *p = paths;
|
||||
for(size_t i = 1; i <= n; i++) { // 1...n
|
||||
list_executables(i, p);
|
||||
p += strlen(p) + 1; // readover the field and the trailing '\0' to get to the next field
|
||||
}
|
||||
free(paths);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Test suite for the given package.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <CUnit/Basic.h>
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifndef TARGET // must be given by the make file --> see test target
|
||||
#error missing TARGET define
|
||||
#endif
|
||||
|
||||
/// @brief alias for EXIT_SUCCESS
|
||||
#define OK EXIT_SUCCESS
|
||||
/// @brief alias for EXIT_FAILURE
|
||||
#define FAIL EXIT_FAILURE
|
||||
|
||||
/// @brief The name of the STDOUT text file.
|
||||
#define OUTFILE "stdout.txt"
|
||||
/// @brief The name of the STDERR text file.
|
||||
#define ERRFILE "stderr.txt"
|
||||
|
||||
#define TRACE_INDENT "\n " ///< allow for better stdout formatting in case of error
|
||||
|
||||
#define PATH_SIZE 256
|
||||
|
||||
// setup & cleanup
|
||||
static int setup(void)
|
||||
{
|
||||
remove_file_if_exists(OUTFILE);
|
||||
remove_file_if_exists(ERRFILE);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static int teardown(void)
|
||||
{
|
||||
// Do nothing.
|
||||
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// tests
|
||||
static void test_paths(void)
|
||||
{
|
||||
// arrange
|
||||
const char *name = strrchr(XSTR(TARGET), '/');
|
||||
name = name ? name+1 : XSTR(TARGET);
|
||||
|
||||
char buf[PATH_SIZE] = { 0 };
|
||||
snprintf(buf, PATH_SIZE, "4:../bin:%s\n", name);
|
||||
|
||||
const char *out_txt[] =
|
||||
{ "1:.:runtest\n",
|
||||
"2::runtest\n",
|
||||
buf
|
||||
};
|
||||
const char *err_txt[] = { NULL };
|
||||
// act
|
||||
int exit_code = system(XSTR(TARGET) " .::..:../bin 1>" OUTFILE " 2>" ERRFILE);
|
||||
// assert
|
||||
CU_ASSERT_EQUAL(WEXITSTATUS(exit_code), EXIT_SUCCESS);
|
||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers and runs the tests.
|
||||
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
// setup, run, teardown
|
||||
TestMainBasic("lab test", setup, teardown
|
||||
, test_paths
|
||||
);
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/******************************************************************************
|
||||
* File: Daemonizer.c
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: Einen Daemon-Prozess erzeugen
|
||||
******************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
//*****************************************************************************
|
||||
|
||||
// Macro to write out all the PIDs...
|
||||
|
||||
#define OutPutPIDs() /*printf("\nPID %d, PPID %d, GRP-ID %d\n", \
|
||||
getpid(), getppid(), getpgrp())*/
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// Function: Locks file with file descriptor fd
|
||||
// Returns: 0 on success, -1 of file is already locked
|
||||
// Exits: on fatal errors
|
||||
//*****************************************************************************
|
||||
|
||||
int lock(int fd) {
|
||||
int retval, len;
|
||||
struct flock lock; // data structure for file lock
|
||||
char buffer[16];
|
||||
|
||||
// prepare lockfile
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_start = 0;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_len = 0;
|
||||
|
||||
retval = fcntl(fd, F_SETLK, &lock); // set file lock
|
||||
if (retval < 0) {
|
||||
if ((errno == EACCES) || (errno == EAGAIN)) {
|
||||
return(-1); // Daemon already runs
|
||||
}
|
||||
else {
|
||||
perror("fatal error when locking file");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// empty the lockfile
|
||||
|
||||
retval = ftruncate(fd, 0);
|
||||
if (retval < 0) {
|
||||
perror("fatal error when emptying lockfile");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// write process ID to lockfile
|
||||
|
||||
sprintf(buffer, "%d\n", getpid());
|
||||
len = strlen(buffer);
|
||||
retval = write(fd, buffer, len) < len;
|
||||
if (retval < 0) {
|
||||
perror("fatal error when writing pid to lockfile");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// set lockfile to close on exec
|
||||
|
||||
retval = fcntl(fd, F_GETFD, 0);
|
||||
if (retval < 0) {
|
||||
perror("fatal error when reading lockfile flags");
|
||||
exit(-1);
|
||||
}
|
||||
retval = retval | FD_CLOEXEC;
|
||||
retval = fcntl(fd, F_SETFD, retval);
|
||||
if (retval < 0) {
|
||||
perror("fatal error when setting lockfile flags");
|
||||
exit(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Function: Makes a deamon process and runs a daemon function
|
||||
// Parameter: Daemon function
|
||||
// data pointer to data to be passed to Daemonfunction
|
||||
// LogFile, path of logfile, if NULL, no logfile is created
|
||||
// LivDir, path, where daemon will live
|
||||
// Returns: should not return
|
||||
// Exits: if daemon is already runnung or on fatal errors
|
||||
//*****************************************************************************
|
||||
|
||||
int Daemonizer(void Daemon(void *), void *data,
|
||||
const char *LockFile, const char *LogFile, const char *LivDir) {
|
||||
|
||||
pid_t PID;
|
||||
int fd, dummyfd, retval;
|
||||
|
||||
// create a prozess and terminate parents -> parent is init
|
||||
|
||||
OutPutPIDs();
|
||||
|
||||
PID = fork();
|
||||
if (PID < 0) {
|
||||
perror("could not fork()");
|
||||
exit(-1);
|
||||
}
|
||||
else if (PID > 0) {
|
||||
exit(0); // I have done my work an can exit
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// now I am a process detached from the parent
|
||||
// an make the process -> a daemon process
|
||||
|
||||
signal(SIGINT, SIG_IGN); // ignore CTRL-C
|
||||
signal(SIGQUIT, SIG_IGN); // ignore quit
|
||||
signal(SIGHUP, SIG_IGN); // ignore hangup of terminal
|
||||
|
||||
OutPutPIDs();
|
||||
|
||||
setsid(); // make process session leader
|
||||
// and processgroup leader
|
||||
// no control terminal with pocess
|
||||
OutPutPIDs();
|
||||
|
||||
chdir(LivDir); // change to secure directory
|
||||
umask(0); // allow all access rights for files
|
||||
|
||||
// set up lockfile, if required
|
||||
|
||||
if (LockFile != NULL) {
|
||||
fd = open(LockFile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
|
||||
S_IRGRP | S_IROTH);
|
||||
if (fd < 0) {
|
||||
perror("fatal error when opening lockfile");
|
||||
exit(-1);
|
||||
}
|
||||
retval = lock(fd);
|
||||
if (retval < 0) {
|
||||
printf("\n*** daemon is already running ***\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// last message from daemon
|
||||
|
||||
printf("\n*** daemon starts with process id: %d ***\n",getpid());
|
||||
|
||||
// close "communication" to outer world and set up logging, if required
|
||||
|
||||
close(1); // close stdout
|
||||
close(2); // close stderr
|
||||
if (LogFile != NULL) { // open log file on stdout
|
||||
enum {UserWrite=0644};
|
||||
dummyfd = open(LogFile, O_CREAT | O_APPEND | O_WRONLY,UserWrite);
|
||||
if (dummyfd < 0) {
|
||||
perror("could not open log file");
|
||||
exit(-1);
|
||||
}
|
||||
dup(1); // connect stderr to logfile
|
||||
}
|
||||
close(0); // now close stdin
|
||||
|
||||
// now start the daemon funktion
|
||||
Daemon(data);
|
||||
|
||||
// should not come here
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
|
@ -1,15 +0,0 @@
|
|||
/*********************************************************************
|
||||
* File: Daemonizer.h
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: einen Daemon-Prozess erzeugen
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef DAEMONIZER_H
|
||||
#define DAEMONIZER_H
|
||||
|
||||
int Daemonizer(void Daemon(void *), void *data,
|
||||
const char *LockFile, const char *LogFile, const char *LivDir);
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
|
@ -1,188 +0,0 @@
|
|||
//*****************************************************************************
|
||||
// ipCom.c IP Socket Functions
|
||||
// Original Author: M. Thaler, M. Pellaton (Modul BSY)
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
// system includes
|
||||
//*****************************************************************************
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
//*****************************************************************************
|
||||
// local definitions
|
||||
//*****************************************************************************
|
||||
|
||||
#include "IPsockCom.h"
|
||||
|
||||
//*****************************************************************************
|
||||
// Function: send data buffer to host "host" with port "port"
|
||||
// Parameter: hostname or IP address in dot format
|
||||
// port number
|
||||
// buffer
|
||||
// size of buffer
|
||||
// Returns: number of characters read on success, -1 if connection failed
|
||||
// buffer: time data
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
int getTimeFromServer(char *host, int port, char *buffer, int bufferLen) {
|
||||
|
||||
int sfd, sysRet, timeOut, retval;
|
||||
char stringPort[8];
|
||||
struct addrinfo hints, *aiList, *aiPtr = NULL;
|
||||
|
||||
if (strcmp(host, "") == 0) {
|
||||
printf("Need hostname or IP address\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
sprintf(stringPort, "%d", port);
|
||||
|
||||
memset(&hints, '\0', sizeof(hints));
|
||||
//hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
sysRet = getaddrinfo(host, stringPort, &hints, &aiList);
|
||||
if (sysRet != 0) {
|
||||
printf("error getting network address for %s (%s)\n",
|
||||
host, gai_strerror(sysRet));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
aiPtr = aiList; // search through list
|
||||
while (aiPtr != 0) {
|
||||
sfd = socket(aiPtr->ai_family, aiPtr->ai_socktype, aiPtr->ai_protocol);
|
||||
if (sfd >= 0) {
|
||||
timeOut = 100;
|
||||
sysRet = 1;
|
||||
while ((timeOut != 0) && (sysRet != 0)) {
|
||||
sysRet = connect(sfd, aiPtr->ai_addr, aiPtr->ai_addrlen);
|
||||
usleep(1000);
|
||||
timeOut--;
|
||||
}
|
||||
if (sysRet == 0)
|
||||
break; // connect successful
|
||||
else
|
||||
close(sfd);
|
||||
}
|
||||
aiPtr = aiPtr->ai_next;
|
||||
}
|
||||
freeaddrinfo(aiList);
|
||||
if (aiPtr == NULL) {
|
||||
printf("could not connect to %s\n", host);
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
retval = 0;
|
||||
|
||||
if (retval == 0) {
|
||||
if (write(sfd, buffer, bufferLen) < 0) {
|
||||
printf("error sending request to timer serveer\n");
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
retval = read(sfd, buffer, COM_BUF_SIZE);
|
||||
}
|
||||
close(sfd);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Function: starts "time" socket server
|
||||
// Parameter: port number to listen to
|
||||
// Returns: socket file descriptor if ok, -1 if error
|
||||
// Exits:
|
||||
//*****************************************************************************
|
||||
|
||||
int StartTimeServer(int portNumber) {
|
||||
|
||||
int sfd, sysRet, j;
|
||||
char stringPort[8];
|
||||
struct addrinfo hints, *aiList, *aiPtr = NULL;
|
||||
|
||||
sprintf(stringPort, "%d", portNumber); // portnumber to string
|
||||
memset(&hints, '\0', sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = 0;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
sysRet = getaddrinfo(NULL, stringPort, &hints, &aiList);
|
||||
if (sysRet != 0) {
|
||||
printf("error getting network address (%s)\n", gai_strerror(sysRet));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
aiPtr = aiList; // search through list
|
||||
while (aiPtr != 0) {
|
||||
sfd = socket(aiPtr->ai_family, aiPtr->ai_socktype, aiPtr->ai_protocol);
|
||||
if (sfd >= 0) {
|
||||
j = 1;
|
||||
sysRet = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j));
|
||||
if (sysRet < 0)
|
||||
perror("cannot set socket options");
|
||||
|
||||
if (bind(sfd, aiPtr->ai_addr, aiPtr->ai_addrlen) < 0) {
|
||||
perror("bind failed ");
|
||||
close(sfd);
|
||||
exit(-1);
|
||||
}
|
||||
if (listen(sfd, 5) < 0) {
|
||||
close(sfd);
|
||||
perror("listen failed ");
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
aiPtr = aiPtr->ai_next;
|
||||
}
|
||||
freeaddrinfo(aiList);
|
||||
if (aiPtr == NULL) {
|
||||
printf("could not set up a socket server\n");
|
||||
exit(-1);
|
||||
}
|
||||
return(sfd);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Function: Reads data from client
|
||||
// Parameter: socket file descriptor
|
||||
// buffer to place data
|
||||
// Returns: current socket descriptor on success, < 0 on failure
|
||||
// Exits: none
|
||||
//*****************************************************************************
|
||||
|
||||
|
||||
int WaitForClient(int sfd, char *buffer) {
|
||||
|
||||
int cfd, retval, addrlen;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
cfd = accept(sfd,(struct sockaddr *)&addr,(socklen_t *)&addrlen);
|
||||
if (cfd >= 0) {
|
||||
retval = read(cfd, buffer, COM_BUF_SIZE);
|
||||
retval = cfd;
|
||||
}
|
||||
else
|
||||
retval = cfd;
|
||||
return(retval);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
|
@ -1,20 +0,0 @@
|
|||
//*****************************************************************************
|
||||
// ipCom.c IP Socket Functions
|
||||
// Original Autor: M. Thaler, M. Pellaton (Modul BSY)
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef IP_COM_SOCKETS
|
||||
#define IP_COM_SOCKETS
|
||||
|
||||
#define COM_BUF_SIZE 512
|
||||
|
||||
#define PIDperror()\
|
||||
fprintf(stderr,"fatal error, daemon with PID %d: ",getpid());
|
||||
|
||||
int getTimeFromServer(char *host, int port, char *buffer, int bufferLen);
|
||||
int StartTimeServer(int PortNumber);
|
||||
int WaitForClient(int sfd, char *buffer);
|
||||
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
|
@ -1,44 +0,0 @@
|
|||
/*********************************************************************
|
||||
* File: MrTimeDaemon.c
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: einen Daemon-Prozess erzeugen
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Daemonizer.h"
|
||||
#include "TimeDaemon.h"
|
||||
|
||||
#define STRING_LENGTH 128
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
int main(void) {
|
||||
pid_t pid;
|
||||
int status;
|
||||
const char *lockfilePath = "/tmp/timeDaemon.lock";
|
||||
//const char *lockfilePath = NULL;
|
||||
const char *logfilePath = "/tmp/timeDaemon.log";
|
||||
const char *livingPath = "/tmp";
|
||||
const char *myName = "I am Mr. Time Daemon on \n";
|
||||
|
||||
|
||||
if ((pid = fork()) == 0)
|
||||
Daemonizer(TimeDaemon, (void *)myName,
|
||||
lockfilePath, logfilePath, livingPath);
|
||||
else {
|
||||
assert(pid > 0);
|
||||
wait(&status); // wait for Daemonizer to exit
|
||||
// after having forked the "Daemon"
|
||||
if (WEXITSTATUS(status) != 0)
|
||||
printf("*** Daemonizer failed ***\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
|
@ -1,21 +0,0 @@
|
|||
/*********************************************************************
|
||||
* File: PlapperMaul.c
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: plappern
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
int main(void) {
|
||||
|
||||
while (1) {
|
||||
printf("Hallo, ich bins.... Pidi %d\n", getpid());
|
||||
usleep(500000);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
|
@ -1,75 +0,0 @@
|
|||
/******************************************************************************
|
||||
* File: TimeDaemon.c
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: the daemon code
|
||||
******************************************************************************/
|
||||
|
||||
//*****************************************************************************
|
||||
// system includes
|
||||
//*****************************************************************************
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/un.h>
|
||||
#include <netdb.h>
|
||||
#include <time.h>
|
||||
|
||||
//*****************************************************************************
|
||||
// local includes
|
||||
//*****************************************************************************
|
||||
|
||||
#include "TimeDaemon.h"
|
||||
#include "TimeDaemonDefs.h"
|
||||
#include "IPsockCom.h"
|
||||
|
||||
//*****************************************************************************
|
||||
// Function: TimeDeamon
|
||||
// Parameter: data: expects here pointer to string
|
||||
//*****************************************************************************
|
||||
|
||||
void TimeDaemon(void *data) {
|
||||
|
||||
TimeData tData;
|
||||
char buffer[COM_BUF_SIZE];
|
||||
struct tm MyTime;
|
||||
time_t ActualTime;
|
||||
int sfd, cfd;
|
||||
|
||||
|
||||
printf("%s\n", (char *)data);
|
||||
|
||||
// start server
|
||||
sfd = StartTimeServer(TIME_PORT);
|
||||
if (sfd < 0) {
|
||||
perror("could not start socket server");
|
||||
exit(-1);
|
||||
}
|
||||
while (1) {
|
||||
|
||||
cfd = WaitForClient(sfd, buffer);
|
||||
if ((strcmp(buffer, REQUEST_STRING) == 0) && (cfd >= 0)) {
|
||||
|
||||
time(&ActualTime);
|
||||
MyTime = *localtime(&ActualTime);
|
||||
|
||||
tData.hours = MyTime.tm_hour;
|
||||
tData.minutes = MyTime.tm_min;
|
||||
tData.seconds = MyTime.tm_sec;
|
||||
tData.day = MyTime.tm_mday;
|
||||
tData.month = MyTime.tm_mon + 1;
|
||||
tData.year = MyTime.tm_year + 1900;
|
||||
gethostname(tData.servername, HOST_NAM_LEN);
|
||||
write(cfd, (char *)(&tData), sizeof(tData));
|
||||
}
|
||||
}
|
||||
// if we should somehow come here (how ?)
|
||||
close(sfd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
|
@ -1,14 +0,0 @@
|
|||
/******************************************************************************
|
||||
* File: TimeDaemon.h
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: function prototype of time daemon
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef TIME_DAEMON
|
||||
#define TIME_DAEMON
|
||||
|
||||
void TimeDaemon(void *);
|
||||
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
|
@ -1,30 +0,0 @@
|
|||
/******************************************************************************
|
||||
* File: TimeDaemonDefs.h
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: Data Definitions for TimeDaemon
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef TIME_DAEMON_DEFS
|
||||
#define TIME_DAEMON_DEFS
|
||||
|
||||
#define HOST_NAM_LEN 32
|
||||
|
||||
#define TIME_PORT 65534
|
||||
|
||||
#define REQUEST_STRING "requestTimeFromServer"
|
||||
|
||||
// data structure receiving from time daemon
|
||||
|
||||
typedef struct {
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int day;
|
||||
int month;
|
||||
int year;
|
||||
char servername[HOST_NAM_LEN];
|
||||
} TimeData, *TimeDataPtr;
|
||||
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
|
@ -1,66 +0,0 @@
|
|||
/******************************************************************************
|
||||
* File: WhatsTheTimeMr.c
|
||||
* Original Autor: M. Thaler (Modul BSY)
|
||||
* Aufgabe: Ask MrTimeDaemon for the time
|
||||
******************************************************************************/
|
||||
|
||||
//*****************************************************************************
|
||||
// system includes
|
||||
//*****************************************************************************
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/un.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h> // required by inet_aton
|
||||
|
||||
//*****************************************************************************
|
||||
// local includes
|
||||
//*****************************************************************************
|
||||
|
||||
#include "TimeDaemon.h"
|
||||
#include "TimeDaemonDefs.h"
|
||||
#include "IPsockCom.h"
|
||||
|
||||
//*****************************************************************************
|
||||
// Function: main()
|
||||
// Parameter: hostname or IP address in dot format
|
||||
//*****************************************************************************
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
char buffer[COM_BUF_SIZE];
|
||||
char hostname[64];
|
||||
TimeDataPtr tDataPtr;
|
||||
int j;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("*** no hostname or IP-address -> using localhost ***\n");
|
||||
strcpy(hostname, "localhost");
|
||||
} else {
|
||||
strcpy(hostname, argv[1]);
|
||||
}
|
||||
|
||||
strcpy(buffer,REQUEST_STRING);
|
||||
j = getTimeFromServer(hostname, TIME_PORT, buffer, sizeof(buffer));
|
||||
if (j < 0)
|
||||
printf("no response from %s\n", argv[1]);
|
||||
else {
|
||||
tDataPtr = (TimeDataPtr)(buffer);
|
||||
printf("\nIt's ");
|
||||
printf("%02d:%02d:%02d",
|
||||
tDataPtr->hours, tDataPtr->minutes,tDataPtr->seconds);
|
||||
printf(" the %d.%d.%d on \"%s\"\n\n",
|
||||
tDataPtr->day, tDataPtr->month,
|
||||
tDataPtr->year, tDataPtr->servername);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
# *************************************************************
|
||||
# Original Autor: M. Thaler (Modul BSY)
|
||||
# *************************************************************
|
||||
|
||||
CMP= gcc
|
||||
CMPFLAGS= -Wall -g -std=gnu99
|
||||
EXENAMES= MrTimeDaemon.e
|
||||
EXENAMEC= WhatsTheTimeMr.e
|
||||
EXENAMEP= PlapperMaul.e
|
||||
LIBNAME=
|
||||
|
||||
compile: $(EXENAMES) $(EXENAMEC) $(EXENAMEP)
|
||||
|
||||
$(EXENAMES): MrTimeDaemon.o IPsockCom.o Daemonizer.o TimeDaemon.o
|
||||
$(CMP) $(CMPFLAGS) MrTimeDaemon.o IPsockCom.o Daemonizer.o TimeDaemon.o $(LIBNAME) -o $(EXENAMES)
|
||||
|
||||
$(EXENAMEC): WhatsTheTimeMr.o IPsockCom.o
|
||||
$(CMP) $(CMPFLAGS) WhatsTheTimeMr.o IPsockCom.o $(LIBNAME) -o $(EXENAMEC)
|
||||
|
||||
$(EXENAMEP): PlapperMaul.o
|
||||
$(CMP) $(CMPFLAGS) PlapperMaul.o $(LIBNAME) -o $(EXENAMEP)
|
||||
|
||||
.c.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
.cc.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f $(EXENAMEC) $(EXENAMES) $(EXENAMEP)
|
||||
rm -f *.o
|
||||
|
||||
all:
|
||||
@make clean
|
||||
@make
|
Binary file not shown.
Binary file not shown.
|
@ -1,53 +0,0 @@
|
|||
//***************************************************************************
|
||||
// File: ProcA1.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//***************************************************************************
|
||||
|
||||
//***************************************************************************
|
||||
// system includes
|
||||
//***************************************************************************
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//***************************************************************************
|
||||
// Function: main(), parameter: none
|
||||
//***************************************************************************
|
||||
|
||||
int main(void) {
|
||||
|
||||
pid_t pid;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
i = 5;
|
||||
|
||||
printf("\n\ni vor fork: %d\n\n", i);
|
||||
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
perror("Could not fork");
|
||||
break;
|
||||
case 0:
|
||||
i++;
|
||||
printf("\n... ich bin das Kind %d mit i=%d, ", getpid(),i);
|
||||
printf("meine Eltern sind %d \n", getppid());
|
||||
break;
|
||||
default:
|
||||
i--;
|
||||
printf("\n... wir sind die Eltern %d mit i=%d ", getpid(), i);
|
||||
printf("und Kind %d,\n unsere Eltern sind %d\n", pid, getppid());
|
||||
wait(&status);
|
||||
break;
|
||||
}
|
||||
printf("\n. . . . . und wer bin ich ?\n\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# *************************************************************
|
||||
# Original Autor: M. Thaler (Modul BSY)
|
||||
# *************************************************************
|
||||
|
||||
CMP= gcc
|
||||
CMPFLAGS= -Wall
|
||||
LDFLAGS=
|
||||
EXENAM1= ProcA1.e
|
||||
FNAM1= ProcA1
|
||||
LIBNAME=
|
||||
|
||||
$(EXENAM1): $(FNAM1).o
|
||||
$(CMP) $(FNAM1).o $(LIBNAME) $(LDFLAGS) -o $@
|
||||
|
||||
.c.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
.cc.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f *.o $(EXENAM1)
|
||||
|
||||
all:
|
||||
@make clean
|
||||
@make
|
|
@ -1,38 +0,0 @@
|
|||
//***************************************************************************
|
||||
// File: ChildProcA3.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//***************************************************************************
|
||||
|
||||
//***************************************************************************
|
||||
// system includes
|
||||
//***************************************************************************
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//***************************************************************************
|
||||
// Function: main(), parameter: arg[0]: Programmname, arg[1]: i
|
||||
//***************************************************************************
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
int i;
|
||||
|
||||
if (argv[1] == NULL) {
|
||||
printf("argument missing\n");
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
i = atoi(argv[1]); // convert string argv[1] to integer i
|
||||
// argv[1] is a number passed to child
|
||||
|
||||
printf("\n... ich bin das Kind %d mit i=%d, ", getpid(),i);
|
||||
printf("meine Eltern sind %d \n", getppid());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
|
@ -1,54 +0,0 @@
|
|||
//***************************************************************************
|
||||
// File: ProcA3.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//***************************************************************************
|
||||
|
||||
//***************************************************************************
|
||||
// system includes
|
||||
//***************************************************************************
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//***************************************************************************
|
||||
// Function: main(), parameter: none
|
||||
//***************************************************************************
|
||||
|
||||
int main(void) {
|
||||
|
||||
pid_t pid;
|
||||
int status;
|
||||
int i, retval;
|
||||
char str[8];
|
||||
|
||||
i = 5;
|
||||
|
||||
printf("\n\ni vor fork: %d\n\n", i);
|
||||
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
perror("Could not fork");
|
||||
break;
|
||||
case 0:
|
||||
i++;
|
||||
sprintf(str, "%d",i); // convert integer i to string str
|
||||
retval = execl("./ChildProcA2.e", "ChildProcA2.e", str, NULL);
|
||||
if (retval < 0) perror("\nexecl not successful");
|
||||
break;
|
||||
default:
|
||||
i--;
|
||||
printf("\n... wir sind die Eltern %d mit i=%d ", getpid(), i);
|
||||
printf("und Kind %d,\n unsere Eltern sind %d\n", pid, getppid());
|
||||
wait(&status);
|
||||
break;
|
||||
}
|
||||
printf("\n. . . . . und wer bin ich ?\n\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
|
@ -1,34 +0,0 @@
|
|||
# *************************************************************
|
||||
# Original Autor: M. Thaler (Modul BSY)
|
||||
# *************************************************************
|
||||
|
||||
CMP= gcc
|
||||
CMPFLAGS= -Wall
|
||||
LDFLAGS=
|
||||
EXENAME= ProcA2.e
|
||||
FNAME= ProcA2
|
||||
EXENAMC= ChildProcA2.e
|
||||
FNAMC= ChildProcA2
|
||||
LIBNAME=
|
||||
LIBNAME=
|
||||
|
||||
compile: $(EXENAME) $(EXENAMC)
|
||||
|
||||
$(EXENAME): $(FNAME).o
|
||||
$(CMP) $(FNAME).o $(LIBNAME) $(LDFLAGS) -o $@
|
||||
|
||||
$(EXENAMC): $(FNAMC).o
|
||||
$(CMP) $(FNAMC).o $(LIBNAME) $(LDFLAGS) -o $@
|
||||
|
||||
.c.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
.cc.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f *.o $(EXENAME) $(EXENAMC)
|
||||
|
||||
all:
|
||||
@make clean
|
||||
@make
|
|
@ -1,31 +0,0 @@
|
|||
//***************************************************************************
|
||||
// File: ProcA4.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//***************************************************************************
|
||||
|
||||
//***************************************************************************
|
||||
// system includes
|
||||
//***************************************************************************
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//***************************************************************************
|
||||
// Function: main(), parameter: none
|
||||
//***************************************************************************
|
||||
|
||||
int main(void) {
|
||||
fork();
|
||||
fork();
|
||||
fork();
|
||||
fork();
|
||||
printf("PID: %d\t PPID: %d\n", getpid(), getppid());
|
||||
sleep(10); // keep processes in system to display their "stammbaum"
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
|
@ -1,27 +0,0 @@
|
|||
# *************************************************************
|
||||
# Original Autor: M. Thaler (Modul BSY)
|
||||
# *************************************************************
|
||||
|
||||
CMP= gcc
|
||||
CMPFLAGS= -Wall
|
||||
LDFLAGS=
|
||||
EXENAMES= ProcA3.e
|
||||
FNAME= ProcA3
|
||||
LIBNAME=
|
||||
|
||||
$(EXENAMES): $(FNAME).o
|
||||
$(CMP) $(FNAME).o $(LIBNAME) $(LDFLAGS) -o $@
|
||||
|
||||
.c.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
.cc.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f *.o $(EXENAMES)
|
||||
|
||||
all:
|
||||
@make clean
|
||||
@make
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
//***************************************************************************
|
||||
// File: ProcA5.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//***************************************************************************
|
||||
|
||||
//***************************************************************************
|
||||
// system includes
|
||||
//***************************************************************************
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "workerUtils.h"
|
||||
#include "selectCPU.h"
|
||||
|
||||
#define ITERATIONS 20
|
||||
#define WORK_HARD 2000000
|
||||
|
||||
//***************************************************************************
|
||||
// Function: main(), parameter: none
|
||||
//***************************************************************************
|
||||
|
||||
int main(void) {
|
||||
|
||||
pid_t pid;
|
||||
int i;
|
||||
|
||||
|
||||
pid = fork();
|
||||
selectCPU(0); // select CPU 0
|
||||
switch (pid) {
|
||||
case -1:
|
||||
perror("Could not fork");
|
||||
break;
|
||||
case 0:
|
||||
for (i = 0; i < ITERATIONS; i++) {
|
||||
justWork(WORK_HARD);
|
||||
printf("%d \t\tChild\n", i);
|
||||
fflush(stdout); // force output
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (i = 0; i < ITERATIONS; i++) {;
|
||||
justWork(WORK_HARD);
|
||||
printf("%d \tMother\n", i);
|
||||
fflush(stdout); // force output
|
||||
}
|
||||
}
|
||||
printf("I go it ...\n");
|
||||
|
||||
if (pid > 0) // wait for child to terminate
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
//***************************************************************************
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
setCPU() does not work on OSX
|
|
@ -1,27 +0,0 @@
|
|||
# *************************************************************
|
||||
# Original Autor: M. Thaler (Modul BSY)
|
||||
# *************************************************************
|
||||
|
||||
CMP= gcc
|
||||
CMPFLAGS= -Wall
|
||||
LDFLAGS=
|
||||
EXENAM1= ProcA4.e
|
||||
FNAM1= ProcA4.o workerUtils.o selectCPU.o
|
||||
LIBNAME=
|
||||
|
||||
$(EXENAM1): $(FNAM1)
|
||||
$(CMP) $(FNAM1) $(LIBNAME) $(LDFLAGS) -o $@
|
||||
|
||||
.c.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
.cc.o:
|
||||
$(CMP) -c $(CMPFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f *.o $(EXENAM1)
|
||||
|
||||
all:
|
||||
@make clean
|
||||
@make
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
//***************************************************************************
|
||||
// File: setCPU.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//***************************************************************************
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __linux
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
//******************************************************************************
|
||||
|
||||
#ifdef __linux
|
||||
|
||||
void selectCPU(unsigned int n) {
|
||||
cpu_set_t cpuset;
|
||||
if (n >= sysconf(_SC_NPROCESSORS_ONLN)) {
|
||||
printf("CPU %d not availble\n", n);
|
||||
exit(0);
|
||||
}
|
||||
sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(n, &cpuset);
|
||||
sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
void selectCPU(unsigned int n) {
|
||||
printf("Cannot set single CPU on OSX\n ... continue anyway");
|
||||
}
|
||||
#endif
|
||||
|
||||
//******************************************************************************
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
//*******************************************************************
|
||||
// File: selectCPU.h
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//*******************************************************************
|
||||
|
||||
#ifndef SET_CPUS_HEADER_FILE
|
||||
#define SET_CPUS_HEADER_FILE
|
||||
|
||||
//*******************************************************************
|
||||
|
||||
void selectCPU(unsigned int n);
|
||||
|
||||
//*******************************************************************
|
||||
|
||||
#endif
|
|
@ -1,90 +0,0 @@
|
|||
//*******************************************************************
|
||||
// File: workerUtils.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
// Purpose: helper applications to consume cpu time
|
||||
//*******************************************************************
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "workerUtils.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#define MAX_CPUS 16
|
||||
//------------------------------------------------------------------------------
|
||||
pid_t worker[MAX_CPUS];
|
||||
int nCPUS;
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void launchWorkLoad() {
|
||||
int i;
|
||||
nCPUS = sysconf(_SC_NPROCESSORS_ONLN); // get number of available CPUs
|
||||
nCPUS = (nCPUS > MAX_CPUS) ? MAX_CPUS : nCPUS;
|
||||
for (i = 0; i < nCPUS; i++) // start workers -> random load
|
||||
worker[i] = startWorker();
|
||||
}
|
||||
|
||||
void stopWorkLoad() {
|
||||
int i;
|
||||
for (i = 0; i < nCPUS; i++) // stop worker
|
||||
stopWorker(worker[i]);
|
||||
}
|
||||
|
||||
|
||||
void setRandom(void) {
|
||||
srandom((unsigned int)time(NULL)); // new random sequence
|
||||
}
|
||||
|
||||
void justWork(unsigned int load) {
|
||||
unsigned int j;
|
||||
for (j = 0; j < load; j++) {}; // just work
|
||||
}
|
||||
|
||||
void workHard(unsigned int low, unsigned int high) {
|
||||
double rv;
|
||||
unsigned int us, j;
|
||||
high = high - low;
|
||||
rv = ((double)random())/RAND_MAX; // make random value (0..1)
|
||||
us = low + (unsigned int)(rv * high); // between lower & higher limit
|
||||
for (j = 0; j < us; j++) {}; // just work
|
||||
setRandom(); // reseed random generator
|
||||
}
|
||||
|
||||
void randomSleep(unsigned int low, unsigned int high) {
|
||||
double rv;
|
||||
unsigned int us;
|
||||
high = high - low;
|
||||
rv = ((double)random())/RAND_MAX; // make random value (0..1)
|
||||
us = low + (unsigned int)(rv * high); // between lower & higher limit
|
||||
usleep(us*1000);
|
||||
}
|
||||
|
||||
|
||||
pid_t startWorker(void) { // make a hard working process
|
||||
struct timeval tv; // limit run time to 60 secs
|
||||
time_t st;
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) { // child: pid = 0 -> ifinite loop
|
||||
gettimeofday(&tv, NULL); // take start time
|
||||
st = tv.tv_sec;
|
||||
while ((tv.tv_sec-st) < 60) {
|
||||
workHard(50, 800); // work hard (random interval
|
||||
gettimeofday(&tv, NULL); // between 50us and 800us)
|
||||
}
|
||||
|
||||
}
|
||||
if (pid < 0) { // exit fork failed
|
||||
printf("forking worker failed\n");
|
||||
exit(0);
|
||||
}
|
||||
return pid; // return pid if parent
|
||||
}
|
||||
|
||||
void stopWorker(pid_t worker) {
|
||||
kill(worker, SIGKILL); // terminate worker process
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
//*******************************************************************
|
||||
// File: workerUtils.h
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
// Purpose: helper applications to consume cpu time
|
||||
//*******************************************************************
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#define MAX_CPUS 16
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void launchWorkLoad();
|
||||
|
||||
void stopWorkLoad();
|
||||
|
||||
void setRandom(void);
|
||||
|
||||
void justWork(unsigned int load);
|
||||
|
||||
void workHard(unsigned int low, unsigned int high);
|
||||
|
||||
void randomSleep(unsigned int low, unsigned int high);
|
||||
|
||||
pid_t startWorker(void);
|
||||
|
||||
void stopWorker(pid_t worker);
|
|
@ -1,51 +0,0 @@
|
|||
//***************************************************************************
|
||||
// File: ProcA6.c
|
||||
// Original Author: M. Thaler (Modul BSY)
|
||||
//***************************************************************************
|
||||
|
||||
//***************************************************************************
|
||||
// system includes
|
||||
//***************************************************************************
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//***************************************************************************
|
||||
// Function: main(), parameter: none
|
||||
//***************************************************************************
|
||||
|
||||
int main(void) {
|
||||
|
||||
pid_t pid, id;
|
||||
char buf[64];
|
||||
int i;
|
||||
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
perror("Could not fork");
|
||||
break;
|
||||
case 0:
|
||||
printf("\n... ich bin das Kind %d\n", getpid());
|
||||
for (i = 0; i < 10; i++) {
|
||||
usleep(500000); // slow down a bit
|
||||
printf("Mein Elternprozess ist %d\n", id = getppid());
|
||||
}
|
||||
printf("... so das wars\n");
|
||||
break;
|
||||
default:
|
||||
sleep(2); // terminate
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
printf("\n\n*** and here my new parent ****\n\n");
|
||||
sprintf(buf, "ps -p %d", id);
|
||||
system(buf);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
|
@ -1,3 +0,0 @@
|
|||
Reparenting -> new parent instead init (1):
|
||||
|
||||
command prctl(PR_SET_CHILD_SUBREAPER, 1)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue