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