remove stuff till HS21, backup at other branch

This commit is contained in:
stsh 2022-02-17 10:51:20 +01:00
parent accc615d03
commit 0765adb9ed
166 changed files with 0 additions and 9781 deletions

52
.gitignore vendored
View File

@ -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
View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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>"
}
'

View File

@ -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>"
}
'

View File

@ -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)

View File

@ -1,8 +0,0 @@
/**
* @mainpage SNP - P02 QR Code
*
* @section Purpose
*
* This is a lab to display a QR code on the color terminal.
*
*/

View File

@ -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;
}

View File

@ -1,29 +0,0 @@
############## ######## ##############
## ## ## ## ##
## ###### ## #### ## ###### ##
## ###### ## ###### ## ###### ##
## ###### ## ## ## ## ###### ##
## ## #### ## ##
############## ## ## ## ##############
######
#### #### ## ######## ## ##
## ## ## ## ## ##
## #### #### #### ## ## ##
## ######## ######
## #### #### ## #### ######
###### ## ## ## ## ##
############## ###### ####
## ## ## ## ####
## ###### ## ############ ## ######
## ###### ## ## #### ##
## ###### ## #### #### #### ####
## ## ## #### ######
############## ############ ## ##

View File

@ -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.

View File

@ -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)

View File

@ -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
*
*/

View File

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

View File

@ -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>"
}
'

View File

@ -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
);
}

View File

@ -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)

View File

@ -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.
*
*/

View File

@ -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;
}

View File

@ -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
);
}

View File

@ -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)

View File

@ -1,8 +0,0 @@
/**
* @mainpage SNP - P04 Modularisation
*
* @section Purpose
*
* This is a lab for splitting functionality into multiple modules.
*
*/

View File

@ -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;
}

View File

@ -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

View File

@ -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_

View File

@ -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;
}

View File

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

View File

@ -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

View File

@ -1,7 +0,0 @@
Test File
. dir1/h1_1
.. dir1/h1_1_2
. dir1/h1_2
. dir2/h2_1
.. dir1/h1_1
Done

View File

@ -1,2 +0,0 @@
Test File
Done

View File

@ -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.

View File

@ -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)

View File

@ -1,8 +0,0 @@
/**
* @mainpage SNP - P05 Tic Tac Toe Game
*
* @section Purpose
*
* This is a lab on usage of arrays.
*
*/

View File

@ -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 } };
}
}

View File

@ -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_

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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_

View File

@ -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);
}
}

View File

@ -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_

View File

@ -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
);
}

View File

@ -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)

View File

@ -1,8 +0,0 @@
/**
* @mainpage SNP - P06 Integer Rechner
*
* @section Purpose
*
* This is a lab on usage of arrays.
*
*/

View File

@ -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);
}

View File

@ -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_

View File

@ -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);
}

View File

@ -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_

View File

@ -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);
}

View File

@ -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_

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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_

View File

@ -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;
}

View File

@ -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_

View File

@ -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
);
}

View File

@ -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

View File

@ -1,8 +0,0 @@
/**
* @mainpage SNP - P07 Linked List
*
* @section Purpose
*
* This is a lab on usage of arrays.
*
*/

View File

@ -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;
}

View File

@ -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
);
}

View File

@ -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

View File

@ -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.
*
*/

View File

@ -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;
}

View File

@ -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
);
}

View File

@ -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);
}
//*****************************************************************************

View File

@ -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
//------------------------------------------------------------------------

View File

@ -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);
}
//*****************************************************************************

View File

@ -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
//***************************************************************************

View File

@ -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");
}
}
//--------------------------------------------------------------------

View File

@ -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);
}
}
//--------------------------------------------------------------------

View File

@ -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);
}
//*****************************************************************************

View File

@ -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
//*****************************************************************************

View File

@ -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
//*****************************************************************************

View File

@ -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);
}
//*****************************************************************************

View File

@ -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

View File

@ -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);
}
//***************************************************************************

View File

@ -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

View File

@ -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);
}
//***************************************************************************

View File

@ -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);
}
//***************************************************************************

View File

@ -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

View File

@ -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);
}
//***************************************************************************

View File

@ -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

View File

@ -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);
}
//***************************************************************************

View File

@ -1,2 +0,0 @@
setCPU() does not work on OSX

View File

@ -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

View File

@ -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
//******************************************************************************

View File

@ -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

View File

@ -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
}

View File

@ -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);

View File

@ -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);
}
//***************************************************************************

View File

@ -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