rm sol
This commit is contained in:
parent
36c8653382
commit
32ac505a9c
|
@ -1,39 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* -- _____ ______ _____ -
|
|
||||||
* -- |_ _| | ____|/ ____| -
|
|
||||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
|
||||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
|
||||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
|
||||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Lab implementation
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define ROW_COUNT 8
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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) if there is an input error.
|
|
||||||
*/
|
|
||||||
int main(char argc, char* argv){
|
|
||||||
uint16_t i;
|
|
||||||
double rate;
|
|
||||||
|
|
||||||
printf("Umwandlungskurs eingeben (1.00 BTC -> CHF): ");
|
|
||||||
if (1!= scanf("%lf", &rate)){
|
|
||||||
printf("Ungültige Eingabe! Geben Sie eine Fliesskommazahl ein.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 1; i <= ROW_COUNT; i++) {
|
|
||||||
printf("%5d CHF\t<-->\t %5.5lf BTC\n", i*200, (double)i*200/rate);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* -- _____ ______ _____ -
|
|
||||||
* -- |_ _| | ____|/ ____| -
|
|
||||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
|
||||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
|
||||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
|
||||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Lab implementation
|
|
||||||
*/
|
|
||||||
#include <stdio.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.
|
|
||||||
*/
|
|
||||||
int main(char argc, char* argv[]) {
|
|
||||||
printf("hello world.\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* -- _____ ______ _____ -
|
|
||||||
* -- |_ _| | ____|/ ____| -
|
|
||||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
|
||||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
|
||||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
|
||||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Lab implementation
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.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(char argc, char* argv[]) {
|
|
||||||
uint16_t char_count = 0, word_count = 0;
|
|
||||||
char c;
|
|
||||||
uint8_t is_word = 0;
|
|
||||||
|
|
||||||
printf("Eingabe: ");
|
|
||||||
c=getchar();
|
|
||||||
while('\n' != c){
|
|
||||||
char_count++;
|
|
||||||
if(c != ' ' && c !='\t'){
|
|
||||||
if(! is_word){
|
|
||||||
is_word = 1;
|
|
||||||
word_count++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
is_word = 0;
|
|
||||||
}
|
|
||||||
c = getchar();
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%d Zeichen, %d W\u00F6rter\n", char_count, word_count);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
|
|
||||||
# Lösungsskizzen
|
|
||||||
## Aufgabe 1
|
|
||||||
```
|
|
||||||
/**
|
|
||||||
* Tage Pro Monat
|
|
||||||
*
|
|
||||||
* Das Programm liest einen Monat (1-12) und ein Jahr (1600-2400) ein und
|
|
||||||
* gibt die Anzahl der Tage dieses Monats aus.
|
|
||||||
*
|
|
||||||
* @author Gerrit Burkert, Adaptation bazz
|
|
||||||
* @version 15-FEB-2013, 16-OCT-2017, 17-OCT-2019, 16-FEB-2022
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define ERROR_IN_MONTH 1
|
|
||||||
#define ERROR_IN_YEAR 2
|
|
||||||
|
|
||||||
///// Student Code
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Konstante Werte fuer die Monate
|
|
||||||
// ===============================
|
|
||||||
|
|
||||||
enum { JAN=1, FEB, MAR, APR, MAI, JUN, JUL, AUG, SEP, OKT, NOV, DEZ };
|
|
||||||
|
|
||||||
|
|
||||||
// Eingabe pruefen (0 ist vom atoi als Fehelcode verwendet und darf nicht verwendet werden)
|
|
||||||
// ===============
|
|
||||||
|
|
||||||
int gibIntWert(char *name, int von, int bis) {
|
|
||||||
|
|
||||||
int wert;
|
|
||||||
char wertS[20]; //
|
|
||||||
|
|
||||||
do {
|
|
||||||
printf("%s: ", name);
|
|
||||||
fgets(wertS, 20, stdin);
|
|
||||||
wert = atoi(wertS);
|
|
||||||
if (wert < von || wert > bis) {
|
|
||||||
printf("Der Wert muss zwischen %d und %d sein.\n", von, bis);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while(1);
|
|
||||||
return wert;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Schaltjahr bestimmen
|
|
||||||
// ====================
|
|
||||||
|
|
||||||
int istSchaltjahr(int jahr){
|
|
||||||
|
|
||||||
if ( (jahr % 400 == 0) || ( (jahr %100 != 0) && (jahr % 4 ==0) ) )
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Berechnung Anzahl Tage pro Monat
|
|
||||||
// ================================
|
|
||||||
|
|
||||||
int tageProMonat(int jahr, int monat) {
|
|
||||||
|
|
||||||
int anzTage;
|
|
||||||
|
|
||||||
// Tage pro Monat bestimmen
|
|
||||||
switch (monat) {
|
|
||||||
|
|
||||||
// Monate mit 31 Tagen
|
|
||||||
case JAN: case MAR: case MAI: case JUL: case AUG: case OKT: case DEZ:
|
|
||||||
anzTage = 31;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Monate mit 30 Tagen
|
|
||||||
case APR: case JUN: case SEP: case NOV:
|
|
||||||
anzTage = 30;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Februar: 28 oder 29 Tage
|
|
||||||
case FEB:
|
|
||||||
|
|
||||||
if (istSchaltjahr(jahr)) {
|
|
||||||
anzTage = 29;
|
|
||||||
} else {
|
|
||||||
anzTage = 28;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return anzTage;
|
|
||||||
}
|
|
||||||
|
|
||||||
///// END Student Code
|
|
||||||
|
|
||||||
|
|
||||||
int main (int argc, char *argv[]) {
|
|
||||||
|
|
||||||
int monat, jahr;
|
|
||||||
|
|
||||||
// Monat einlesen und Bereich ueberpruefen
|
|
||||||
monat = gibIntWert("Monat", 1, 12);
|
|
||||||
jahr = gibIntWert("Jahr", 1600, 9999);
|
|
||||||
|
|
||||||
// Ausgabe zum Test
|
|
||||||
printf("Monat: %d, Jahr: %d \n", monat, jahr);
|
|
||||||
|
|
||||||
// Ausgabe zum Test (hier mit dem ternaeren Operator "?:")
|
|
||||||
printf("%d ist %s Schaltjahr\n", jahr, istSchaltjahr(jahr) ? "ein" : "kein");
|
|
||||||
|
|
||||||
// Ausgabe
|
|
||||||
printf("Der Monat %02d-%d hat %d Tage.\n", monat, jahr, tageProMonat(jahr, monat));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
## Aufgabe 2
|
|
||||||
Alter bestehender Boilerplate Code
|
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
/*****************************************************************************
|
|
||||||
M. Thaler, Jan. 2000
|
|
||||||
Datei read.java
|
|
||||||
Funktion: Unsigned int Zahl via Bytestream von stdin einlesen.
|
|
||||||
Es wird zuerst eine Zeile eingelesen und dann konvertiert.
|
|
||||||
Die eingelesene Zeile darf nur eine Zahl enthalten
|
|
||||||
(mit optionalen Leerzeichen vor/nach der Zahl).
|
|
||||||
Returns: Die konvertierte Zahl
|
|
||||||
oder -1 (PARSE_ERROR) wenn keine Zahl oder zu gross
|
|
||||||
oder -2 (READ_ERROR) wenn Fehler beim einlesen.
|
|
||||||
Korrekturen: - Maerz 2002: M. Thaler, H. Fierz, Mar. 2002
|
|
||||||
liest bis EOL oder EOF, korrekter Rueckgabewert
|
|
||||||
- Sept 2016: A. Gieriet
|
|
||||||
Refactored (sprechende Variablen-Namen,
|
|
||||||
MS Windows Support, 0 Wert erlaubt,
|
|
||||||
Leerzeichen Support,
|
|
||||||
"magic" Numbers durch Symbole ersetzt,
|
|
||||||
maxResult Parameter, etc.)
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
public class read {
|
|
||||||
public int getInt(int maxResult)
|
|
||||||
throws java.io.IOException
|
|
||||||
{
|
|
||||||
// end of input
|
|
||||||
int EOF = -1; // end of file
|
|
||||||
int EOL = 10; // end of line
|
|
||||||
// abnormal return values
|
|
||||||
int PARSE_ERROR = -1;
|
|
||||||
int READ_ERROR = -2;
|
|
||||||
// ASCII Codes
|
|
||||||
int ASCII_SPACE = 32; // ' '
|
|
||||||
int ASCII_DIGIT_0 = 48; // '0'
|
|
||||||
int ASCII_DIGIT_9 = 57; // '9'
|
|
||||||
|
|
||||||
// conversion buffer
|
|
||||||
int NO_POS = -1;
|
|
||||||
int BUFFERSIZE = 10;
|
|
||||||
byte[] buffer = new byte[BUFFERSIZE];
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
// read line: up to EOL or EOF (i.e. error while reading)
|
|
||||||
int bytes = 0;
|
|
||||||
int input = System.in.read();
|
|
||||||
while ((input != EOL) && (input != EOF)) { // read whole line
|
|
||||||
if (bytes < BUFFERSIZE) { // only buffer first n characters
|
|
||||||
buffer[bytes] = (byte)input;
|
|
||||||
bytes++;
|
|
||||||
} else {
|
|
||||||
result = PARSE_ERROR; // exceed buffer size, continue read line
|
|
||||||
}
|
|
||||||
input = System.in.read();
|
|
||||||
}
|
|
||||||
if (input == EOF) {
|
|
||||||
result = READ_ERROR;
|
|
||||||
}
|
|
||||||
// check for numbers: skip leading and trailing spaces
|
|
||||||
// (i.e. this includes all control chars below the space ASCII code)
|
|
||||||
int pos = 0;
|
|
||||||
while((pos < bytes) && (buffer[pos] <= ASCII_SPACE)) pos++; // skip SP
|
|
||||||
int posOfFirstDigit = pos;
|
|
||||||
int posOfLastDigit = NO_POS;
|
|
||||||
while ((pos < bytes)
|
|
||||||
&& (buffer[pos] >= ASCII_DIGIT_0)
|
|
||||||
&& (buffer[pos] <= ASCII_DIGIT_9))
|
|
||||||
{
|
|
||||||
posOfLastDigit = pos;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
while((pos < bytes) && (buffer[pos] <= ASCII_SPACE)) pos++; // skip SP
|
|
||||||
// produce return value
|
|
||||||
if (result != 0) {
|
|
||||||
// previously detected read or parse error given
|
|
||||||
} else if ((pos != bytes) || (posOfLastDigit == NO_POS)) {
|
|
||||||
result = PARSE_ERROR;
|
|
||||||
} else { // convert number
|
|
||||||
for(int i = posOfFirstDigit; i <= posOfLastDigit; i++) {
|
|
||||||
result = result * 10 + (buffer[i] - ASCII_DIGIT_0);
|
|
||||||
if (result > maxResult) {
|
|
||||||
result = PARSE_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*****************************************************************************
|
|
||||||
M. Thaler, Jan. 2000
|
|
||||||
Datei: rectang.java
|
|
||||||
Funktion: Bestimmt, ob Dreieck rechtwinklig ist.
|
|
||||||
Returns: true wenn rechtwinklig, sonst false.
|
|
||||||
Korrekturen: - Sept 2016, A. Gieriet
|
|
||||||
Refactored (sprechende Variablen Namen, etc.)
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
public class rectang {
|
|
||||||
|
|
||||||
public boolean Rectangular(int a, int b, int c) {
|
|
||||||
|
|
||||||
int aS = a*a;
|
|
||||||
int bS = b*b;
|
|
||||||
int cS = c*c;
|
|
||||||
|
|
||||||
boolean isRightAngled;
|
|
||||||
if ((a == 0) && (b == 0) && (c == 0))
|
|
||||||
isRightAngled = false;
|
|
||||||
else if ((aS + bS) == cS)
|
|
||||||
isRightAngled = true;
|
|
||||||
else if ((aS + cS) == bS)
|
|
||||||
isRightAngled = true;
|
|
||||||
else if ((bS + cS) == aS)
|
|
||||||
isRightAngled = true;
|
|
||||||
else
|
|
||||||
isRightAngled = false;
|
|
||||||
|
|
||||||
return isRightAngled;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*****************************************************************************
|
|
||||||
M. Thaler, Jan. 2000
|
|
||||||
Datei: triangle.java
|
|
||||||
Funktion: Die drei Seiten eines Dreiecks einlesen und bestimmen ob
|
|
||||||
das Dreieck rechtwinklig ist.
|
|
||||||
Returns: Nichts.
|
|
||||||
Korrekturen: - Maerz 2002, M. Thaler, H. Fierz
|
|
||||||
Abfrage bei unkorrekter Eingabe wiederholen
|
|
||||||
- Sept 2016, A. Gieriet
|
|
||||||
Refactored (sprechende Variablen-Namen,
|
|
||||||
"magic" Numbers durch Symbole ersetzt, etc.)
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
class triangle {
|
|
||||||
|
|
||||||
public static void main(String[] args)
|
|
||||||
throws java.io.IOException
|
|
||||||
{
|
|
||||||
int READ_ERROR = -2;
|
|
||||||
int MAX_NUMBER = 1000;
|
|
||||||
|
|
||||||
read ReadInt = new read();
|
|
||||||
rectang Rect = new rectang();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
System.out.println("\nDreiecksbestimmung (CTRL-C: Abbruch)\n");
|
|
||||||
|
|
||||||
int word = 0;
|
|
||||||
int a = 0;
|
|
||||||
int b = 0;
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
System.out.print("Seite a: ");
|
|
||||||
word = ReadInt.getInt(MAX_NUMBER);
|
|
||||||
}
|
|
||||||
while ((word < 0) && (word != READ_ERROR));
|
|
||||||
if (word >= 0)
|
|
||||||
a = word;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
do {
|
|
||||||
System.out.print("Seite b: ");
|
|
||||||
word = ReadInt.getInt(MAX_NUMBER);
|
|
||||||
}
|
|
||||||
while ((word < 0) && (word != READ_ERROR));
|
|
||||||
if (word >= 0)
|
|
||||||
b = word;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
do {
|
|
||||||
System.out.print("Seite c: ");
|
|
||||||
word = ReadInt.getInt(MAX_NUMBER);
|
|
||||||
}
|
|
||||||
while ((word < 0) && (word != READ_ERROR));
|
|
||||||
if (word >= 0)
|
|
||||||
c = word;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (Rect.Rectangular(a, b, c) == true)
|
|
||||||
System.out.println("-> Dreieck " + a + "-" + b + "-" + c
|
|
||||||
+ " ist rechtwinklig");
|
|
||||||
else
|
|
||||||
System.out.println("-> Dreieck " + a + "-" + b + "-" + c
|
|
||||||
+ " ist nicht rechtwinklig");
|
|
||||||
System.out.println("\n");
|
|
||||||
}
|
|
||||||
System.out.println("\n\nbye bye\n");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +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 "read.h"
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
//#define EOF (-1) // end of file
|
|
||||||
|
|
||||||
/// end-of-line
|
|
||||||
#define EOL 10 // end of line
|
|
||||||
|
|
||||||
// abnormal return values
|
|
||||||
/// parse-error
|
|
||||||
#define PARSE_ERROR (-1)
|
|
||||||
|
|
||||||
// ASCII Codes
|
|
||||||
/// ascii code for space
|
|
||||||
#define ASCII_SPACE ' '
|
|
||||||
/// ascii code for 0
|
|
||||||
#define ASCII_DIGIT_0 '0'
|
|
||||||
/// ascii code for 9
|
|
||||||
#define ASCII_DIGIT_9 '9'
|
|
||||||
|
|
||||||
// conversion buffer
|
|
||||||
/// no buffer position sentry
|
|
||||||
#define NO_POS (-1)
|
|
||||||
/// buffer size
|
|
||||||
#define BUFFERSIZE (10)
|
|
||||||
|
|
||||||
int getInt(int maxResult)
|
|
||||||
{
|
|
||||||
TRACE("getInt(%d)", maxResult);
|
|
||||||
|
|
||||||
char buffer[BUFFERSIZE] = { 0 };
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
// read line: up to EOL or EOF (i.e. error while reading)
|
|
||||||
int bytes = 0;
|
|
||||||
int input = getchar();
|
|
||||||
while ((input != EOL) && (input != EOF)) { // read whole line
|
|
||||||
if (bytes < BUFFERSIZE) { // only buffer first n characters
|
|
||||||
buffer[bytes] = (char)input;
|
|
||||||
bytes++;
|
|
||||||
} else {
|
|
||||||
result = PARSE_ERROR; // exceed buffer size, continue read line
|
|
||||||
}
|
|
||||||
input = getchar();
|
|
||||||
}
|
|
||||||
if (input == EOF) {
|
|
||||||
result = READ_ERROR;
|
|
||||||
}
|
|
||||||
// check for numbers: skip leading and trailing spaces
|
|
||||||
// (i.e. this includes all control chars below the space ASCII code)
|
|
||||||
int pos = 0;
|
|
||||||
while((pos < bytes) && (buffer[pos] <= ASCII_SPACE)) pos++; // skip SP
|
|
||||||
int posOfFirstDigit = pos;
|
|
||||||
int posOfLastDigit = NO_POS;
|
|
||||||
while ((pos < bytes)
|
|
||||||
&& (buffer[pos] >= ASCII_DIGIT_0)
|
|
||||||
&& (buffer[pos] <= ASCII_DIGIT_9))
|
|
||||||
{
|
|
||||||
posOfLastDigit = pos;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
while((pos < bytes) && (buffer[pos] <= ASCII_SPACE)) pos++; // skip SP
|
|
||||||
// produce return value
|
|
||||||
if (result != 0) {
|
|
||||||
// previously detected read or parse error given
|
|
||||||
} else if ((pos != bytes) || (posOfLastDigit == NO_POS)) {
|
|
||||||
result = PARSE_ERROR;
|
|
||||||
} else { // convert number
|
|
||||||
for(int i = posOfFirstDigit; i <= posOfLastDigit; i++) {
|
|
||||||
result = result * 10 + (buffer[i] - ASCII_DIGIT_0);
|
|
||||||
if (result > maxResult) {
|
|
||||||
result = PARSE_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* -- _____ ______ _____ -
|
|
||||||
* -- |_ _| | ____|/ ____| -
|
|
||||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
|
||||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
|
||||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
|
||||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Lab implementation
|
|
||||||
*/
|
|
||||||
#ifndef READ_H
|
|
||||||
#define READ_H
|
|
||||||
|
|
||||||
/// I/O error which leads to aborting.
|
|
||||||
#define READ_ERROR (-2)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reads a line from stdin and tries to parse it as number (with optional leading and trailing spaces).
|
|
||||||
* @param[in] maxResult gives the limit for the number to be read.
|
|
||||||
* @returns the succesfully read and parsed number or a negative value if in error (READ_ERROR in case of I/O error).
|
|
||||||
*/
|
|
||||||
int getInt(int maxResult);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,38 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* -- _____ ______ _____ -
|
|
||||||
* -- |_ _| | ____|/ ____| -
|
|
||||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
|
||||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
|
||||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
|
||||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Lab implementation
|
|
||||||
*/
|
|
||||||
#include "rectang.h"
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
int rectangular(int a, int b, int c)
|
|
||||||
{
|
|
||||||
TRACE("rectangular(%d, %d, %d)", a, b, c);
|
|
||||||
|
|
||||||
int aS = a*a;
|
|
||||||
int bS = b*b;
|
|
||||||
int cS = c*c;
|
|
||||||
|
|
||||||
int isRightAngled;
|
|
||||||
if ((a == 0) && (b == 0) && (c == 0))
|
|
||||||
isRightAngled = 0;
|
|
||||||
else if ((aS + bS) == cS)
|
|
||||||
isRightAngled = 1;
|
|
||||||
else if ((aS + cS) == bS)
|
|
||||||
isRightAngled = 1;
|
|
||||||
else if ((bS + cS) == aS)
|
|
||||||
isRightAngled = 1;
|
|
||||||
else
|
|
||||||
isRightAngled = 0;
|
|
||||||
|
|
||||||
return isRightAngled;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* -- _____ ______ _____ -
|
|
||||||
* -- |_ _| | ____|/ ____| -
|
|
||||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
|
||||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
|
||||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
|
||||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Lab implementation
|
|
||||||
*/
|
|
||||||
#ifndef RECTANG_H
|
|
||||||
#define RECTANG_H
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief checks if the three lengths give a right-angled triangle.
|
|
||||||
* @param[in] a 1st side
|
|
||||||
* @param[in] b 2nd side
|
|
||||||
* @param[in] c 3rd side
|
|
||||||
* @returns 1 if right-angled, 0 otherwise
|
|
||||||
*/
|
|
||||||
int rectangular(int a, int b, int c);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,26 +0,0 @@
|
||||||
/* ----------------------------------------------------------------------------
|
|
||||||
* -- _____ ______ _____ -
|
|
||||||
* -- |_ _| | ____|/ ____| -
|
|
||||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
|
||||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
|
||||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
|
||||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Lab implementation
|
|
||||||
*/
|
|
||||||
#ifndef TRACE_H
|
|
||||||
#define TRACE_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief TRACE macro.
|
|
||||||
* @param[in] MSG "..." format string literal.
|
|
||||||
* @param[in] ... optional arguments to the format string.
|
|
||||||
*/
|
|
||||||
#define TRACE(MSG, ...) do { (void)fprintf(stderr, "TRACE: " MSG "\n", ##__VA_ARGS__); } while(0)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,78 +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 "read.h"
|
|
||||||
#include "rectang.h"
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
/// max side length
|
|
||||||
#define MAX_NUMBER 1000
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Main entry point.
|
|
||||||
* @returns Returns EXIT_SUCCESS (=0) on success, EXIT_FAILURE (=1) on failure.
|
|
||||||
*/
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
TRACE("main()");
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
(void)printf("\nDreiecksbestimmung (CTRL-C: Abbruch)\n\n");
|
|
||||||
|
|
||||||
int word = 0;
|
|
||||||
int a = 0;
|
|
||||||
int b = 0;
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
(void)printf("Seite a: ");
|
|
||||||
word = getInt(MAX_NUMBER);
|
|
||||||
}
|
|
||||||
while ((word < 0) && (word != READ_ERROR));
|
|
||||||
if (word >= 0)
|
|
||||||
a = word;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
do {
|
|
||||||
(void)printf("Seite b: ");
|
|
||||||
word = getInt(MAX_NUMBER);
|
|
||||||
}
|
|
||||||
while ((word < 0) && (word != READ_ERROR));
|
|
||||||
if (word >= 0)
|
|
||||||
b = word;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
do {
|
|
||||||
(void)printf("Seite c: ");
|
|
||||||
word = getInt(MAX_NUMBER);
|
|
||||||
}
|
|
||||||
while ((word < 0) && (word != READ_ERROR));
|
|
||||||
if (word >= 0)
|
|
||||||
c = word;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (rectangular(a, b, c))
|
|
||||||
(void)printf("-> Dreieck %d-%d-%d ist rechtwinklig\n", a, b, c);
|
|
||||||
else
|
|
||||||
(void)printf("-> Dreieck %d-%d-%d ist nicht rechtwinklig\n", a, b, c);
|
|
||||||
(void)printf("\n\n");
|
|
||||||
}
|
|
||||||
(void)printf("\n\nbye bye\n\n");
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
a
|
|
||||||
a
|
|
||||||
a
|
|
||||||
3
|
|
||||||
4444
|
|
||||||
4444
|
|
||||||
44444444444444
|
|
||||||
4
|
|
||||||
4
|
|
||||||
5
|
|
||||||
5
|
|
|
@ -1,12 +0,0 @@
|
||||||
3
|
|
||||||
4
|
|
||||||
6
|
|
||||||
5
|
|
||||||
4
|
|
||||||
4
|
|
||||||
3
|
|
||||||
5
|
|
||||||
5
|
|
||||||
33
|
|
||||||
43
|
|
||||||
55
|
|
|
@ -1,12 +0,0 @@
|
||||||
3
|
|
||||||
4
|
|
||||||
5
|
|
||||||
5
|
|
||||||
4
|
|
||||||
3
|
|
||||||
3
|
|
||||||
5
|
|
||||||
4
|
|
||||||
33
|
|
||||||
44
|
|
||||||
55
|
|
|
@ -1,205 +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 "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 stimulus for the right-angled triangles
|
|
||||||
#define INFILE_RIGHT_ANGLED "stim-right-angled.input"
|
|
||||||
/// @brief The stimulus for the not right-angled triangles
|
|
||||||
#define INFILE_NOT_RIGHT_ANGLED "stim-not-right-angled.input"
|
|
||||||
/// @brief The stimulus for input errors
|
|
||||||
#define INFILE_ERROR "stim-error.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_right_angled(void)
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
const char *out_txt[] = {
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 3-4-5 ist rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 5-4-3 ist rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 3-5-4 ist rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 33-44-55 ist rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: \n",
|
|
||||||
"\n",
|
|
||||||
"bye bye\n",
|
|
||||||
"\n",
|
|
||||||
};
|
|
||||||
// act
|
|
||||||
int exit_code = system(XSTR(TARGET) " 1>" OUTFILE " 2>" ERRFILE " <" INFILE_RIGHT_ANGLED);
|
|
||||||
// assert
|
|
||||||
CU_ASSERT_EQUAL(exit_code, 0);
|
|
||||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_not_right_angled(void)
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
const char *out_txt[] = {
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 3-4-6 ist nicht rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 5-4-4 ist nicht rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 3-5-5 ist nicht rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite b: Seite c: -> Dreieck 33-43-55 ist nicht rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: \n",
|
|
||||||
"\n",
|
|
||||||
"bye bye\n",
|
|
||||||
"\n",
|
|
||||||
};
|
|
||||||
// act
|
|
||||||
int exit_code = system(XSTR(TARGET) " 1>" OUTFILE " 2>" ERRFILE " <" INFILE_NOT_RIGHT_ANGLED);
|
|
||||||
// assert
|
|
||||||
CU_ASSERT_EQUAL(exit_code, 0);
|
|
||||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_trace(void)
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
const char *err_txt[] = {
|
|
||||||
"TRACE: main()\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: rectangular(3, 4, 6)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: rectangular(5, 4, 4)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: rectangular(3, 5, 5)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
"TRACE: rectangular(33, 43, 55)\n",
|
|
||||||
"TRACE: getInt(1000)\n",
|
|
||||||
};
|
|
||||||
// act
|
|
||||||
int exit_code = system(XSTR(TARGET) " 1>" OUTFILE " 2>" ERRFILE " <" INFILE_NOT_RIGHT_ANGLED);
|
|
||||||
// assert
|
|
||||||
CU_ASSERT_EQUAL(exit_code, 0);
|
|
||||||
assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_error(void)
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
const char *out_txt[] = {
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: Seite a: Seite a: Seite a: Seite a: Seite b: Seite b: Seite b: Seite b: Seite b: Seite c: Seite c: -> Dreieck 3-4-5 ist rechtwinklig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Dreiecksbestimmung (CTRL-C: Abbruch)\n",
|
|
||||||
"\n",
|
|
||||||
"Seite a: \n",
|
|
||||||
"\n",
|
|
||||||
"bye bye\n",
|
|
||||||
"\n",
|
|
||||||
};
|
|
||||||
// act
|
|
||||||
int exit_code = system(XSTR(TARGET) " 1>" OUTFILE " 2>" ERRFILE " <" INFILE_ERROR);
|
|
||||||
// assert
|
|
||||||
CU_ASSERT_EQUAL(exit_code, 0);
|
|
||||||
assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Registers and runs the tests.
|
|
||||||
*/
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
// setup, run, teardown
|
|
||||||
TestMainBasic("Triangle", setup, teardown
|
|
||||||
, test_right_angled
|
|
||||||
, test_not_right_angled
|
|
||||||
, test_trace
|
|
||||||
, test_error
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
|
||||||
|
|
||||||
TARGET := bin/dep2dot
|
|
||||||
SOURCES := src/main.c src/data.c src/output.c
|
|
||||||
TSTSOURCES := tests/tests.c
|
|
||||||
|
|
||||||
include $(SNP_SHARED_MAKEFILE)
|
|
||||||
|
|
||||||
|
|
||||||
# DEPFILES := ... define a list of png file names: %.c -> %.c.png
|
|
||||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
DEPFILES := $(SOURCES:%.c=%.c.png)
|
|
||||||
# END-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
# define dep target as .PHONEY
|
|
||||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
.PHONY: dep
|
|
||||||
# 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
|
|
||||||
dep: $(FULLTARGET) $(DEPFILES)
|
|
||||||
@echo "### $@ done ###"
|
|
||||||
|
|
||||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
# define new suffix rule for %.png depending on %.dot
|
|
||||||
# action: dot -Tpng $< >$@ || $(RM) $@
|
|
||||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
%.png: %.dot
|
|
||||||
dot -Tpng $< >$@ || $(RM) $@
|
|
||||||
|
|
||||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
# define new suffix rule for %.dot depending on %.dep
|
|
||||||
# action: call $(TARGET) $(@:.dot=) <$< >$@ || $(RM) $@
|
|
||||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
%.dot: %.dep
|
|
||||||
$(TARGET) $(@:.dot=) <$< >$@ || $(RM) $@
|
|
||||||
|
|
||||||
# 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,72 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief Access to the GCC produced dependency data (via -H command line option).
|
|
||||||
*/
|
|
||||||
|
|
||||||
// begin of include guard
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
#ifndef _DATA_H_
|
|
||||||
#define _DATA_H_
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
// includes which are needed in this header file
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
#include <stddef.h>
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Directory container for file entries of the dependency file.
|
|
||||||
*/
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
typedef struct {
|
|
||||||
const char *name; ///< @brief the path name of the directory as given by the GCC produced dependency file.
|
|
||||||
} dir_t;
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief File container for the file entries of the dependency file.
|
|
||||||
*/
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
typedef struct {
|
|
||||||
const char *name; ///< @brief The base name of the file from the GGC produced dependency file (i.e. the plain name, without any directory path).
|
|
||||||
size_t dir; ///< @brief The index of the directory entry which represents the path as given by the dependency file.
|
|
||||||
size_t level; ///< @brief The level as read out from the dependecy file.
|
|
||||||
} file_t;
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Overall container for all directories and all files from the dependency file.
|
|
||||||
*/
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
typedef struct {
|
|
||||||
size_t n_dirs; ///< @brief The number of valid entries in the dirs list.
|
|
||||||
dir_t *dirs; ///< @brief The list of directories.
|
|
||||||
size_t n_files; ///< @brief The number of valid entries in the files list.
|
|
||||||
file_t *files; ///< @brief The list of files from the dependency file (the sequence is relevant to determine the dependencies).
|
|
||||||
} data_t;
|
|
||||||
// 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
|
|
||||||
const data_t data_read_all(const char *root);
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// end of include guard
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
#endif // _DATA_H_
|
|
||||||
// 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,95 +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
|
|
||||||
printf(" ");
|
|
||||||
print_node(files[curr]);
|
|
||||||
printf(" -> ");
|
|
||||||
print_node(files[file]);
|
|
||||||
printf(";\n");
|
|
||||||
// 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
|
|
||||||
printf(" ");
|
|
||||||
print_node(data.files[file]);
|
|
||||||
printf(" [label=\"%s\"];\n", data.files[file].name);
|
|
||||||
// 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
|
|
||||||
printf(" ");
|
|
||||||
print_node(data.files[file]);
|
|
||||||
printf(";\n");
|
|
||||||
// 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,20 +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
|
|
||||||
#ifndef _OUTPUT_H_
|
|
||||||
#define _OUTPUT_H_
|
|
||||||
|
|
||||||
#include "data.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Produces DOT output of the dependencies given in data.
|
|
||||||
* @param data [IN] Container of the dependenciy data.
|
|
||||||
*/
|
|
||||||
void output_dot(const data_t data);
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _OUTPUT_H_
|
|
||||||
// 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
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -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,154 +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
|
|
||||||
instance->board[pos.row][pos.col] = state;
|
|
||||||
// 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
|
|
||||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
|
||||||
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
|
||||||
instance->board[row][col] = model_state_none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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 instance->board[pos.row][pos.col]; // stub return model_state_none;
|
|
||||||
// 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
|
|
||||||
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
|
||||||
for (size_t col = 0; col < MODEL_SIZE; col++) {
|
|
||||||
if (instance->board[row][col] == model_state_none) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -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 := src/person.c src/list.c
|
|
||||||
# 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,103 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "list.h"
|
|
||||||
|
|
||||||
static node_t anchor;
|
|
||||||
|
|
||||||
static int is_anchor(const node_t *node)
|
|
||||||
{
|
|
||||||
return node == &anchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_next(node_t *at)
|
|
||||||
{
|
|
||||||
assert(at);
|
|
||||||
assert(at->next);
|
|
||||||
if (!is_anchor(at->next)) {
|
|
||||||
node_t *next = at->next->next;
|
|
||||||
free(at->next);
|
|
||||||
at->next = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static node_t *find_insert(const person_t *p)
|
|
||||||
{
|
|
||||||
assert(p);
|
|
||||||
node_t *last = &anchor;
|
|
||||||
for(node_t *n = anchor.next; !is_anchor(n); last = n, n = n->next) {
|
|
||||||
int res = person_compare(&(n->content), p);
|
|
||||||
if (res == 0) {
|
|
||||||
return NULL; // *** EARLY RETURN ***// // already part of the list
|
|
||||||
} else if (res > 0) {
|
|
||||||
break; // the predecessor is the insert point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
|
|
||||||
static node_t *find_remove(const person_t *p)
|
|
||||||
{
|
|
||||||
assert(p);
|
|
||||||
node_t *last = &anchor;
|
|
||||||
for(node_t *n = anchor.next; !is_anchor(n); last = n, n = n->next) {
|
|
||||||
int res = person_compare(&(n->content), p);
|
|
||||||
if (res == 0) {
|
|
||||||
break; // the predecessor is the remove point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return is_anchor(last->next) ? NULL : last;
|
|
||||||
}
|
|
||||||
|
|
||||||
const node_t *list_anchor(void)
|
|
||||||
{
|
|
||||||
return &anchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const node_t *list_init()
|
|
||||||
{
|
|
||||||
anchor.next = &anchor;
|
|
||||||
return &anchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
int list_insert(const person_t *p)
|
|
||||||
{
|
|
||||||
node_t *at = find_insert(p);
|
|
||||||
node_t *insert = NULL;
|
|
||||||
if (at) {
|
|
||||||
insert = malloc(sizeof(node_t));
|
|
||||||
if (insert) {
|
|
||||||
insert->content = *p;
|
|
||||||
insert->next = at->next;
|
|
||||||
at->next = insert;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return at && insert;
|
|
||||||
}
|
|
||||||
|
|
||||||
int list_remove(const person_t *p)
|
|
||||||
{
|
|
||||||
node_t *at = find_remove(p);
|
|
||||||
if (at) {
|
|
||||||
remove_next(at);
|
|
||||||
}
|
|
||||||
return at != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void list_clear(void)
|
|
||||||
{
|
|
||||||
node_t *n = &anchor;
|
|
||||||
do {
|
|
||||||
remove_next(n);
|
|
||||||
} while (!is_anchor(n->next));
|
|
||||||
}
|
|
||||||
|
|
||||||
void list_show(void)
|
|
||||||
{
|
|
||||||
node_t *n = &anchor;
|
|
||||||
do {
|
|
||||||
if (!is_anchor(n)) printf("%20s %20s %u\n", n->content.name, n->content.first_name, n->content.age);
|
|
||||||
n = n->next;
|
|
||||||
} while(!is_anchor(n));
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#ifndef _LIST_H_
|
|
||||||
#define _LIST_H_
|
|
||||||
|
|
||||||
#include "person.h"
|
|
||||||
|
|
||||||
typedef struct node {
|
|
||||||
person_t content; // in diesem Knoten gespeicherte Person
|
|
||||||
struct node *next; // Pointer auf den nächsten Knoten in der Liste
|
|
||||||
} node_t;
|
|
||||||
|
|
||||||
const node_t *list_init();
|
|
||||||
int list_insert(const person_t *p);
|
|
||||||
int list_remove(const person_t *p);
|
|
||||||
void list_clear(void);
|
|
||||||
void list_show(void);
|
|
||||||
|
|
||||||
#endif // _LIST_H_
|
|
|
@ -1,68 +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 "person.h"
|
|
||||||
#include "list.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
|
|
||||||
list_init();
|
|
||||||
person_t p;
|
|
||||||
int show_menu = 1;
|
|
||||||
while(1) {
|
|
||||||
if (show_menu) printf("I(nsert), R(emove), S(how), C(lear), E(nd)\n");
|
|
||||||
show_menu = 1;
|
|
||||||
int op = getchar();
|
|
||||||
switch(op) {
|
|
||||||
case 'I': case 'i':
|
|
||||||
if (!person_read(&p) || !list_insert(&p)) {
|
|
||||||
printf("failed to insert person\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'R': case 'r':
|
|
||||||
if (!person_read(&p) || !list_remove(&p)) {
|
|
||||||
printf("failed to remove person\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'S': case 's':
|
|
||||||
list_show();
|
|
||||||
break;
|
|
||||||
case 'C': case 'c':
|
|
||||||
list_clear();
|
|
||||||
break;
|
|
||||||
case EOF:
|
|
||||||
case 'E': case 'e':
|
|
||||||
return EXIT_SUCCESS; // *** EARLY RETURN *** //
|
|
||||||
break;
|
|
||||||
case ' ': case '\n':
|
|
||||||
show_menu = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("Unknown command: %c\n", op);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "person.h"
|
|
||||||
|
|
||||||
int person_compare(const person_t *a, const person_t *b)
|
|
||||||
{
|
|
||||||
assert(a);
|
|
||||||
assert(b);
|
|
||||||
int res = strncmp(a->name, b->name, NAME_LEN);
|
|
||||||
if (res == 0) res = strncmp(a->first_name, b->first_name, NAME_LEN);
|
|
||||||
if (res == 0) res = a->age - b->age;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int person_read(person_t *p)
|
|
||||||
{
|
|
||||||
assert(p);
|
|
||||||
assert(NAME_LEN == 20);
|
|
||||||
return scanf("%19s %19s %u", p->name, p->first_name, &(p->age)) == 3;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
#ifndef _PERSON_H_
|
|
||||||
#define _PERSON_H_
|
|
||||||
|
|
||||||
#define NAME_LEN 20
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char name[NAME_LEN];
|
|
||||||
char first_name[NAME_LEN];
|
|
||||||
unsigned int age;
|
|
||||||
} person_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compares two persons in this sequence: 1st=name, 2nd=first_name, 3rd=age
|
|
||||||
* @param a [IN] const reference to 1st person in the comparison
|
|
||||||
* @param b [IN] const reference to 2nd person in the comparison
|
|
||||||
* @return =0 if all record fields are the same
|
|
||||||
* >0 if all previous fields are the same, but for this field, a is greater
|
|
||||||
* <0 if all previous fields are the same, but for this field, b is greater
|
|
||||||
* @remark strncmp() is used for producing the result of string field comparisons
|
|
||||||
* @remark a->age – b->age is used for producing the result of age comparison
|
|
||||||
*/
|
|
||||||
int person_compare(const person_t *a, const person_t *b);
|
|
||||||
|
|
||||||
int person_read(person_t *p);
|
|
||||||
|
|
||||||
#endif // _PERSON_H_
|
|
|
@ -1,299 +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 "person.h"
|
|
||||||
#include "list.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
|
|
||||||
person_t a = { "a", "a", 1 };
|
|
||||||
person_t b = { "a", "a", 2 };
|
|
||||||
person_t c = { "a", "b", 1 };
|
|
||||||
person_t d = { "a", "b", 2 };
|
|
||||||
person_t e = { "b", "a", 1 };
|
|
||||||
person_t f = { "b", "a", 2 };
|
|
||||||
person_t g = { "b", "b", 1 };
|
|
||||||
person_t h = { "b", "b", 2 };
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &a) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &b) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &c) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &d) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &e) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &f) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &g) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&a, &h) < 0);
|
|
||||||
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &a) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &b) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &c) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &d) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &e) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &f) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &g) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&b, &h) < 0);
|
|
||||||
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &a) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &b) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &c) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &d) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &e) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &f) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &g) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&c, &h) < 0);
|
|
||||||
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &a) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &b) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &c) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &d) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &e) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &f) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &g) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&d, &h) < 0);
|
|
||||||
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &a) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &b) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &c) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &d) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &e) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &f) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &g) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&e, &h) < 0);
|
|
||||||
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &a) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &b) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &c) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &d) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &e) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &f) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &g) < 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&f, &h) < 0);
|
|
||||||
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &a) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &b) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &c) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &d) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &e) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &f) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &g) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&g, &h) < 0);
|
|
||||||
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &a) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &b) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &c) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &d) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &e) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &f) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &g) > 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&h, &h) == 0);
|
|
||||||
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_list_insert(void)
|
|
||||||
{
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
// arrange
|
|
||||||
const node_t *anchor = list_init();
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next);
|
|
||||||
|
|
||||||
// act & assert: insert one
|
|
||||||
person_t p1 = { "a", "b", 123 };
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p1));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
|
|
||||||
// act & assert: insert a second after first
|
|
||||||
person_t p2 = { "a", "b", 124 };
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p2));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->content), &p2) == 0);
|
|
||||||
|
|
||||||
// act & assert: insert a second before first
|
|
||||||
person_t p3 = { "a", "b", 122 };
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p3));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p3) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->content), &p1) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->next->content), &p2) == 0);
|
|
||||||
|
|
||||||
// act & assert: reject inserting same
|
|
||||||
CU_ASSERT_FALSE(list_insert(&p1));
|
|
||||||
// unchanged
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next->next->next);
|
|
||||||
// unchanged
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p3) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->content), &p1) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->next->content), &p2) == 0);
|
|
||||||
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_list_remove(void)
|
|
||||||
{
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
// arrange
|
|
||||||
const node_t *anchor = list_init();
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next);
|
|
||||||
|
|
||||||
// act & assert: remove one
|
|
||||||
person_t p1 = { "a", "b", 123 };
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p1));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
// remove same
|
|
||||||
CU_ASSERT_TRUE_FATAL(list_remove(&p1));
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next);
|
|
||||||
|
|
||||||
// act & assert: failed to remove
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p1));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
// remove not found
|
|
||||||
person_t p2 = { "a", "b", 124 };
|
|
||||||
CU_ASSERT_FALSE_FATAL(list_remove(&p2));
|
|
||||||
// unchanged
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
|
|
||||||
// act & assert: remove last
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p2));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->content), &p2) == 0);
|
|
||||||
CU_ASSERT_TRUE_FATAL(list_remove(&p2));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
|
|
||||||
// act & assert: remove first
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p2));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->content), &p2) == 0);
|
|
||||||
CU_ASSERT_TRUE_FATAL(list_remove(&p1));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p2) == 0);
|
|
||||||
|
|
||||||
// END-STUDENTS-TO-ADD-CODE
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_list_clear(void)
|
|
||||||
{
|
|
||||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
|
||||||
// arrange
|
|
||||||
const node_t *anchor = list_init();
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next);
|
|
||||||
|
|
||||||
// act & assert: empty list
|
|
||||||
list_clear();
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next);
|
|
||||||
|
|
||||||
// act & assert: clear list of one
|
|
||||||
person_t p1 = { "a", "b", 123 };
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p1));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
list_clear();
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next);
|
|
||||||
|
|
||||||
// act & assert: clear list of two
|
|
||||||
person_t p2 = { "a", "b", 124 };
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p1));
|
|
||||||
CU_ASSERT_TRUE(list_insert(&p2));
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next);
|
|
||||||
CU_ASSERT_PTR_NOT_EQUAL(anchor, anchor->next->next);
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next->next->next);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->content), &p1) == 0);
|
|
||||||
CU_ASSERT_TRUE(person_compare(&(anchor->next->next->content), &p2) == 0);
|
|
||||||
list_clear();
|
|
||||||
CU_ASSERT_PTR_EQUAL(anchor, anchor->next);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
digraph ProcessHierarchie {
|
|
||||||
|
|
||||||
P1[label="P01\nfork()"];
|
|
||||||
|
|
||||||
P11[label="P01\nfork()"];
|
|
||||||
P12[label="P02\nfork()"];
|
|
||||||
|
|
||||||
P111[label="P01\nfork()"];
|
|
||||||
P112[label="P03\nfork()"];
|
|
||||||
P121[label="P02\nfork()"];
|
|
||||||
P122[label="P04\nfork()"];
|
|
||||||
|
|
||||||
P1111[label="P01\nfork()"];
|
|
||||||
P1112[label="P05\nfork()"];
|
|
||||||
P1121[label="P03\nfork()"];
|
|
||||||
P1122[label="P06\nfork()"];
|
|
||||||
P1211[label="P02\nfork()"];
|
|
||||||
P1212[label="P07\nfork()"];
|
|
||||||
P1221[label="P04\nfork()"];
|
|
||||||
P1222[label="P08\nfork()"];
|
|
||||||
|
|
||||||
P11111[label="P01"];
|
|
||||||
P11112[label="P09"];
|
|
||||||
P11121[label="P05"];
|
|
||||||
P11122[label="P10"];
|
|
||||||
P11211[label="P03"];
|
|
||||||
P11212[label="P11"];
|
|
||||||
P11221[label="P06"];
|
|
||||||
P11222[label="P12"];
|
|
||||||
P12111[label="P02"];
|
|
||||||
P12112[label="P13"];
|
|
||||||
P12121[label="P07"];
|
|
||||||
P12122[label="P14"];
|
|
||||||
P12211[label="P04"];
|
|
||||||
P12212[label="P15"];
|
|
||||||
P12221[label="P08"];
|
|
||||||
P12222[label="P16"];
|
|
||||||
|
|
||||||
P1 -> P11
|
|
||||||
P1 -> P12
|
|
||||||
|
|
||||||
P11 -> P111
|
|
||||||
P11 -> P112
|
|
||||||
P12 -> P121
|
|
||||||
P12 -> P122
|
|
||||||
|
|
||||||
P111 -> P1111
|
|
||||||
P111 -> P1112
|
|
||||||
P112 -> P1121
|
|
||||||
P112 -> P1122
|
|
||||||
P121 -> P1211
|
|
||||||
P121 -> P1212
|
|
||||||
P122 -> P1221
|
|
||||||
P122 -> P1222
|
|
||||||
|
|
||||||
P1111 -> P11111
|
|
||||||
P1111 -> P11112
|
|
||||||
P1112 -> P11121
|
|
||||||
P1112 -> P11122
|
|
||||||
P1121 -> P11211
|
|
||||||
P1121 -> P11212
|
|
||||||
P1122 -> P11221
|
|
||||||
P1122 -> P11222
|
|
||||||
P1211 -> P12111
|
|
||||||
P1211 -> P12112
|
|
||||||
P1212 -> P12121
|
|
||||||
P1212 -> P12122
|
|
||||||
P1221 -> P12211
|
|
||||||
P1221 -> P12212
|
|
||||||
P1222 -> P12221
|
|
||||||
P1222 -> P12222
|
|
||||||
|
|
||||||
{ rank="same"; P11; P12; }
|
|
||||||
# { rank="same"; P1; P11; P111; P1111; P11111; }
|
|
||||||
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 77 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue