add labs
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,532 @@
|
||||
# 04 - Modularisieren von C Code
|
||||
|
||||
```{eval-rst}
|
||||
.. figure:: zhaw_neg_P2945.jpg
|
||||
:width: 100px
|
||||
:name: logo
|
||||
:align: right
|
||||
```
|
||||
|
||||
___
|
||||
|
||||
```{eval-rst}
|
||||
.. figure:: modularisieren_von_c_code.JPG
|
||||
:width: 500px
|
||||
:name: logo
|
||||
:align: center
|
||||
```
|
||||
|
||||
|
||||
___
|
||||
|
||||
## Inhalt
|
||||
|
||||
{ref}`04_introduction`
|
||||
|
||||
{ref}`04_learning_objectives`
|
||||
|
||||
{ref}`04_task_01`
|
||||
|
||||
{ref}`04_task_02`
|
||||
|
||||
{ref}`04_grading`
|
||||
|
||||
{ref}`04_appendix`
|
||||
|
||||
___
|
||||
|
||||
(04_introduction)=
|
||||
## 1. Übersicht
|
||||
|
||||
In diesem Praktikum üben Sie modulare Programmierung indem Sie ein
|
||||
Java Programm (bestehend aus drei Java Files) in ein entsprechendes C
|
||||
Programm aus drei Modulen (aus je einem Header- und Implementations-
|
||||
File) übersetzen. Sie passen das Makefile so an, dass die
|
||||
entsprechenden Module mit kompiliert werden.
|
||||
|
||||
In der zweiten Aufgabe erstellen Sie Makefile Regeln für die drei
|
||||
Schritte von den C Source Files zur graphischen Darstellung der
|
||||
Abhängigkeiten.
|
||||
|
||||
```{eval-rst}
|
||||
.. figure:: uebersicht.png
|
||||
:width: 500px
|
||||
:name: uebersicht
|
||||
:align: center
|
||||
```
|
||||
|
||||
|
||||
Im Anhang ist eine Übersicht über die verwendeten File Formate gegeben.
|
||||
|
||||
|
||||
(04_learning_objectives)=
|
||||
## 2. Lernziele
|
||||
|
||||
In diesem Praktikum lernen Sie die Handgriffe um ein Programm zu modularisieren, d.h. in mehrere Module aufzuteilen.
|
||||
|
||||
* Sie wissen, dass ein Modul aus einem C-File und einem passenden
|
||||
H-File besteht.
|
||||
* Sie können Header Files korrekt strukturieren.
|
||||
* Sie deklarieren im Header-File die öffentlichen Typen und Funktionen
|
||||
eines Moduls.
|
||||
* Sie wissen wie **Include Guards** anzuwenden sind.
|
||||
* Sie können Module im `Makefile` zur Kompilation hinzufügen.
|
||||
* Sie können `Makefile` Regeln schreiben.
|
||||
|
||||
Die Bewertung dieses Praktikums ist am Ende angegeben.
|
||||
|
||||
Erweitern Sie die vorgegebenen Code Gerüste, welche im `git`
|
||||
Repository `snp-lab-code` verfügbar sind.
|
||||
|
||||
|
||||
(04_task_01)=
|
||||
## 3. Aufgabe 1: Modularisieren
|
||||
Das zu ergänzende Programm dep2dot hat folgende Funktionalität:
|
||||
|
||||
Ergänzen Sie in **`modularize/src`** den Code in **`triangle.c`**,
|
||||
**`read.h`**, **`read.c`**, **`rectang.h`** und **`rectang.c`** so
|
||||
dass die Tests erfolgreich durchlaufen. Die C Implementation soll
|
||||
dieselbe Funktionalität haben wie die gegebenen Java Files. Lehnen Sie
|
||||
sich so nahe wie möglich an die Java Files an.
|
||||
|
||||
1. In den Header-Files implementieren Sie den Include-Guard und
|
||||
deklarieren Sie die öffentlichen Funktionen und gegebenenfalls
|
||||
**`#define`**.
|
||||
2. In den Implementations-Files implementieren Sie die Funktionen.
|
||||
|
||||
Die drei Java Files liegen in **`modularize/java`**.
|
||||
|
||||
### Tipps
|
||||
|
||||
* Implementieren Sie die Symbole welche vollständig in Grossbuchstaben
|
||||
geschrieben sind als **`#define`**.
|
||||
* **`EOF`** kommt schon aus **`stdio.h`** und sollte deshalb nicht
|
||||
mehr definiert werden.
|
||||
* Jene **`#define`** welche von andern Modulen verwendet werden
|
||||
kommen ins Header-File, die andern ins Implementations-File.
|
||||
* Ein Grossteil des Java Codes aus den Methoden Bodies kann
|
||||
eins-zu-eins in C übernommen werden. Listen Sie auf welche
|
||||
Unterschiede es gibt:
|
||||
|
||||
<table>
|
||||
<style>
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table th:first-of-type {
|
||||
width: 50%;
|
||||
}
|
||||
table th:nth-of-type(2) {
|
||||
width: 50%;
|
||||
}
|
||||
</style>
|
||||
<tr><th>Java</th><th>C</th></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
byte
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
boolean
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
|
||||
```Java
|
||||
true
|
||||
```
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
false
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
System.out.print(…)
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
System.out.println(…)
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
System.in.read()
|
||||
```
|
||||
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
byte[] buffer = new byte[BUFFERSIZE];
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
public class rectang {
|
||||
public boolean Rectangular(…)
|
||||
{ … }
|
||||
}
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
public class read {
|
||||
public int getInt(...)
|
||||
throws java.io.IOException
|
||||
{ ... }
|
||||
}
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
class triangle {
|
||||
public static void main(String[] args)
|
||||
throws java.io.IOException
|
||||
{ ... }
|
||||
}
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
read ReadInt = new read();
|
||||
...
|
||||
word = ReadInt.getInt(MAX_NUMBER);
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```Java
|
||||
rectang Rect = new rectang();
|
||||
...
|
||||
if (Rect.Rectangular(a, b, c) == true) { ... }
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
<tr><td>
|
||||
|
||||
```
|
||||
System.out.println(
|
||||
"-> Dreieck " + a + "-" + b + "-" + c
|
||||
+ " ist rechtwinklig");
|
||||
```
|
||||
|
||||
</td><td></td></tr>
|
||||
</table>
|
||||
|
||||
(04_task_02)=
|
||||
## 4. Aufgabe 2: Makefile Regeln
|
||||
|
||||
Die folgenden drei Schritte erstellen von einem C Source File eine
|
||||
graphische Darstellung der Abhängigkeiten:
|
||||
|
||||
1. `gcc ... -H .. file.c ... 2> file.dep` (Regeln im Makefile bereits vorhanden)
|
||||
2. `dep2dot file.c <file.dep >file.dot` (in dieser Aufgabe zu erstellen)
|
||||
3. `dot -Tpng file.dot >file.png` (in dieser Aufgabe zu erstellen)
|
||||
|
||||
Sie sollen für die Compiler-ähnlichen Programme `dep2dot` und `dot`
|
||||
Makefile Regeln schreiben.
|
||||
|
||||
```{eval-rst}
|
||||
.. figure:: uebersicht.png
|
||||
:width: 500px
|
||||
:name: uebersicht
|
||||
:align: center
|
||||
```
|
||||
|
||||
|
||||
Das Programm `dep2dot` hat folgende Funktionalität:
|
||||
|
||||
|
||||
1. Es liest von `stdin` die vom Compiler generierten
|
||||
Abhängigkeits-Daten in Form des `dep` Formates ein.
|
||||
2. Das erste und einzige Command Line Argument gibt das File an für
|
||||
welches die von `stdin` gelesenen Abhängigkeiten gelten.
|
||||
3. Auf `stdout` werden die Abhängigkeiten von `stdin` übersetzt als
|
||||
`dot`-File Format ausgegeben.
|
||||
|
||||
Das Programm `dot` hat folgende Funktionalität:
|
||||
1. Es liest die textuelle Beschreibung eines Graphen aus der
|
||||
übergebenen Datei (erstes Argument) ein.
|
||||
2. Auf `stdout` wird die grafische Darstellung der Beschreibung der
|
||||
Eingabe-Datei im `png`-File Format ausgegeben.
|
||||
|
||||
Das `dep`-Format und das `dot`-Format sind im Anhang beschrieben.
|
||||
|
||||
Sie können die Funktionalität des Programms `dep2dot` kennen lernen,
|
||||
indem Sie folgende Zeilen auf der Bash Shell ausführen. Das
|
||||
`dep.input` File ist Teil der automatisierten Test Suite im
|
||||
Verzeichnis `tests`:
|
||||
|
||||
|
||||
```bash
|
||||
bin/dep2dot dir/file <tests/dep.input >dep.dot
|
||||
dot -Tpng dep.dot >dep.png
|
||||
firefox dep.png
|
||||
```
|
||||
|
||||
Als Resultat sollte Firefox folgende Graphik darstellen:
|
||||
|
||||
|
||||
```{eval-rst}
|
||||
.. figure:: dep_dot.png
|
||||
:width: 150px
|
||||
:name: dep_dot
|
||||
:align: center
|
||||
```
|
||||
|
||||
|
||||
|
||||
Definieren Sie im `Makefile` Regeln, welche die einzelnen Schritte von
|
||||
den Source Files zu den `png` Files ausführen.
|
||||
|
||||
|
||||
Prüfen Sie schliesslich die Umsetzung Aufgabe mittels `make dep-clean
|
||||
dep && firefox src/*.png.`
|
||||
|
||||
|
||||
### 4.1 Neue Regeln hinzufügen
|
||||
|
||||
|
||||
Führen Sie im `Makefile` an den angegebenen Stellen folgende
|
||||
Ergänzungen durch
|
||||
|
||||
* definieren Sie eine Variable `DEPFILES` deren Inhalt die Liste alle
|
||||
Einträge der Variable `SOURCES` ist, wobei bei allen die Endung `.c`
|
||||
durch die Endung `.c.png` ersetzt ist
|
||||
* fügen Sie zum `Pseudo-Target .PHONEY` das Target `dep` dazu – dies
|
||||
besagt, dass das später folgenden Target `dep` nicht ein File
|
||||
repräsentiert (ohne dieses Setting würde make gegebenenfalls nach
|
||||
einem File mit Namen `dep` suchen um zu entscheiden ob es
|
||||
inkrementell gebildet werden muss)
|
||||
* schreiben Sie das Target `dep` gemäss der Beschreibung im Makefile
|
||||
* schreiben Sie die Suffix Regel für die Übersetzung von `.png <-
|
||||
.dot` gemäss Vorgabe im `Makefile` (als Inspiration, siehe auch die
|
||||
`%.c.dep: %.c` Suffix Regel weiter unten im `Makefile`) – erklären
|
||||
Sie was die Regel macht
|
||||
* schreiben Sie die Suffix Regel für die Übersetzung von` .dot <-
|
||||
.dep` gemäss Vorgabe im `Makefile` – erklären Sie was die Regel
|
||||
macht
|
||||
|
||||
Die Umsetzung der obigen Änderungen sind erfolgreich, wenn Sie
|
||||
folgende Shell Command Line erfolgreich ausführen können und in
|
||||
Firefox die Abhängigkeiten der C-Files von den Inclu-de Files
|
||||
dargestellt wird.
|
||||
|
||||
`make dep-clean dep && firefox src/*.png.`
|
||||
|
||||
|
||||
|
||||
|
||||
(04_grading)=
|
||||
## 5. Bewertung
|
||||
|
||||
Die gegebenenfalls gestellten Theorieaufgaben und der funktionierende Programmcode müssen der Praktikumsbetreuung gezeigt werden. Die Lösungen müssen mündlich erklärt werden.
|
||||
|
||||
| Aufgabe | Kriterium | Punkte |
|
||||
| :-- | :-- | :-- |
|
||||
| 1 | Sie können das funktionierende Programm inklusive funktionierende Tests demonstrieren und erklären. | |
|
||||
| 1 | Module einbinden, Header Files schreiben | 2 |
|
||||
| 2 | Sie können das funktionierende Makefile demonstrieren und erklären. | |
|
||||
| 2 | Neue Regeln hinzufügen | 2 |
|
||||
|
||||
|
||||
|
||||
|
||||
(04_appendix)=
|
||||
## 6. Anhang
|
||||
|
||||
|
||||
|
||||
|
||||
### 6.1 Verwendete zusätzliche Sprach Elemente
|
||||
|
||||
<table><tr><td>
|
||||
|
||||
**Sprach Element**
|
||||
|
||||
</td><td>
|
||||
|
||||
**Beschreibung**
|
||||
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
|
||||
|
||||
|
||||
```C
|
||||
fprintf(stderr, "v=%d", v)
|
||||
```
|
||||
|
||||
</td><td>
|
||||
|
||||
Formatierte Ausgabe auf den Standard Error Stream. Siehe ***man 3
|
||||
stderr*** und ***man 3 fprintf***.
|
||||
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
### 6.2 Verarbeitung und verwendete File Formate <a name="file_formats"></a>
|
||||
|
||||
Das Programm in diesem Praktikum ist Teil für die graphische
|
||||
Darstellung von `#include` File Abhängigkeit von C Files.
|
||||
|
||||
Den ersten Schritt für die Darstellung der `#include` File
|
||||
Abhängigkeiten bietet der Compiler. Der Compiler kann mittels der `-H`
|
||||
Command Line Option auf `stderr` ein Text File generieren, welches die
|
||||
tatsächlich verwendeten Header Files auflistet. Zusätzlich wird im
|
||||
Resultat die Verschachtelungstiefe der Includes angegeben.
|
||||
|
||||
Im zweiten Schritt übersetzt das Programm (`dep2dot`) dieses
|
||||
Praktikums solche Dependency Files (`dep`) in eine Text Repräsentation
|
||||
der Abhängigkeiten (`dot`) welche in graphische Darstel-lung (`png`)
|
||||
übersetzt werden kann.
|
||||
|
||||
Als Tool zur Übersetzung der `dot` Files in das `png` Format dient das
|
||||
`dot` Tool. Dieses Tool muss gegebenenfalls installiert werden:
|
||||
|
||||
```sudo apt install graphviz```
|
||||
|
||||
Die `png` Files können dann z.B. in der Programm Dokumentation
|
||||
integriert werden (Darstellung zu Test Zwecken z.B. mittels `firefox
|
||||
file.png`).
|
||||
|
||||
|
||||
#### 6.2.1 dep File
|
||||
|
||||
|
||||
Siehe: `man gcc`
|
||||
|
||||
```bash
|
||||
-H Print the name of each header file used, in addition to other
|
||||
normal activities. Each name is indented to show how deep in the
|
||||
#include stack it is. [...]
|
||||
```
|
||||
|
||||
Das File wird auf `stderr` ausgegeben.
|
||||
|
||||
**Beispiel File** (für Abhängigkeiten des `main.c` Files des `dep2dot` Programms)
|
||||
|
||||
```bash
|
||||
. /usr/include/stdio.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/libc-header-start.h
|
||||
... /usr/include/features.h
|
||||
.... /usr/include/x86_64-linux-gnu/sys/cdefs.h
|
||||
..... /usr/include/x86_64-linux-gnu/bits/wordsize.h
|
||||
..... /usr/include/x86_64-linux-gnu/bits/long-double.h
|
||||
.... /usr/include/x86_64-linux-gnu/gnu/stubs.h
|
||||
..... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h
|
||||
.. /usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/types.h
|
||||
... /usr/include/x86_64-linux-gnu/bits/wordsize.h
|
||||
... /usr/include/x86_64-linux-gnu/bits/typesizes.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/types/__FILE.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/types/FILE.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/libio.h
|
||||
... /usr/include/x86_64-linux-gnu/bits/_G_config.h
|
||||
.... /usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h
|
||||
.... /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h
|
||||
... /usr/lib/gcc/x86_64-linux-gnu/7/include/stdarg.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/stdio_lim.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/sys_errlist.h
|
||||
. /usr/include/stdlib.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/libc-header-start.h
|
||||
.. /usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/floatn.h
|
||||
... /usr/include/x86_64-linux-gnu/bits/floatn-common.h
|
||||
.... /usr/include/x86_64-linux-gnu/bits/long-double.h
|
||||
.. /usr/include/x86_64-linux-gnu/bits/stdlib-float.h
|
||||
. src/error.h
|
||||
.. /usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h
|
||||
. src/data.h
|
||||
.. /usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h
|
||||
. src/output.h
|
||||
Multiple include guards may be useful for:
|
||||
/usr/include/x86_64-linux-gnu/bits/stdlib-float.h
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h
|
||||
```
|
||||
|
||||
|
||||
#### 6.2.2 dot File
|
||||
|
||||
**Graphviz** ist ein mächtiges Tool-Set welches Graphen, definiert in
|
||||
einem `dot`-Text File, automatisch anordnet und in `png`, `gif` und
|
||||
andere Formate übersetzt.
|
||||
|
||||
Siehe die offizielle Web-Page
|
||||
[https://www.graphviz.org/](https://www.graphviz.org/).
|
||||
|
||||
Es gibt als Teil dieses Tool-Sets verschiedene Übersetzer. Der hier
|
||||
verwendete ist der Basis-übersetzer: `dot`.
|
||||
|
||||
Das `dot`-File Format kennt viele Möglichkeiten die Knoten und Kanten
|
||||
eines Graphen und de-ren Anordnung anzugeben.
|
||||
|
||||
Der Vorteil eines solchen Tool-Sets ist, dass man den Inhalt (den
|
||||
Graphen) einfach definieren kann und sich nicht um das komplexe
|
||||
Problem der ansprechenden Visualisierung kümmern muss.
|
||||
|
||||
**Beispiel File** (`dot -Tpng sample.dot > sample.png`)
|
||||
|
||||
```C
|
||||
digraph G {
|
||||
node [shape=box]
|
||||
A [label="a.c"];
|
||||
B [label="a.h"];
|
||||
C [label="b.h"];
|
||||
|
||||
subgraph cluster_c0 {
|
||||
label="main"; color=black;
|
||||
A;
|
||||
}
|
||||
|
||||
subgraph cluster_c1 {
|
||||
label="others"; style=filled; col-or=lightgrey;
|
||||
{ B; C; rank=same; }
|
||||
}
|
||||
|
||||
A -> B;
|
||||
A -> C;
|
||||
B -> C;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 6.2.3 png File
|
||||
|
||||
Das `png` Format ist ein verlustfrei komprimiertes Raster Graphik
|
||||
Format. Es wird oft in Web Pages verwendet.
|
||||
|
||||
|
||||
___
|
||||
Version: 15.02.2022
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 392 KiB |
@@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2022-02-07T21:41:53.021Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.5.1 Chrome/96.0.4664.110 Electron/16.0.7 Safari/537.36" etag="nbLc9Vjb_iVSFHhKpDKu" version="16.5.1" type="device"><diagram id="L8fo7XVtsVLzhWI8Oabt" name="Page-1">7VnRcuIgFP2aPLoTiIn6WLXd7sx2ptPuTrf7RhM0TDG4BGvs1y9RYgLoGjPqVLtPkgtc4Jx74IKON5hkXzmaxncswtSBbpQ53tCBEAReR/7kloWyuK67sow5iZStNDySd1w0VNYZiXCqNRSMUUGmujFkSYJDodkQ52yuNxsxqo86RWNsGR5DRG3rE4lErKwg6JUVt5iMYzV0F6oVT1DRWK0kjVHE5hWTd+14A86YWJUm2QDTHL0Cl1W/my2164lxnIg6He5GrYenJLv986310P99tfj56oKW8vKG6EwtWE1WLAoEcBJd5UDKr5CiNCXhj5gkjtePxYRKI5BFzmZJhPOBXPkle9wQWtStHOLIwrmcOFjDIQMJswkWfCGbzEvAfQViXIG6sHFMkSBvunukeB+v3a1HuGdEDgxdFaR+EWoqRNtdV3eRshkPsepVBdhw1G3vcCQQH2NhOZKFyrJL05K/PbiE/7n0oUFBryGXpiMAT8ultxeXCUvwv0j86LQFro62Z6Jdl7ZOoDuC7dPSVmwlFd6oTZzk4Tt6kSelRhmiZJzkwpScYC4Nb5gLIk+iK1UxIVGU++hznJJ39LL0l9M7zZezXKDfd/zhmvDcAc40TtQxqTqXh1M1FLYHpB0fyrv7BcBuT4f+IJHR0p0WuigcsNEoxUdhst1EgBFK46XowDmr0RTR2aqxY3EYX4YY2zvEGLQ7UNcNOEhkGAoPTiVG//OK0TwaG2c0O8/YI4sxsDh8+QAkrq+lqx5ntsE25bR0dHztdj+vdk2eG2t3Z8AcWbu9z8vhwa4m5jPDqTkE9lPPPbBolCmK0OlKBWeveMAo4yW3I0KpYaqfMc1jIvDjFIX5mHOOpluCYkPGVCMsCri7vgY37NlbPNwQNp67PUI0SvbGH9r42zK6GPyt3H/DEXta/Bs9qdTbxHBGxK9K+Vm1ysvDrFIxXOy57cnpLfeXnYH1UVIb36DdvPI13S7r3h1PmdoA+16SXa6ireftoJ6iTeIOp2g7LVlcLvymIIBbD34zzagBv/ws/5ZaiaX8d8+7/gs=</diagram></mxfile>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -0,0 +1,127 @@
|
||||
# 04 - Modularisieren von C Code
|
||||
|
||||
___
|
||||
## 1. Übersicht
|
||||
|
||||
In diesem Praktikum wird eine kleine Sammlung von Funktionen als Modul erstellt.
|
||||
|
||||
In der ersten Aufgabe schreiben Sie zu einem bestehenden C Programm die notwendigen Header Files plus passen das Makefile so an, dass die entsprechenden Module mit kompiliert werden.
|
||||
|
||||
In der zweiten Aufgabe erstellen Sie Makefile Regeln um aus Konfigurationsdateien graphischen Darstellungen zu erzeugen.
|
||||
|
||||
___
|
||||
## 2. Lernziele
|
||||
|
||||
In diesem Praktikum lernen Sie die Handgriffe um ein Programm zu modularisieren, d.h. in mehrere Module aufzuteilen.
|
||||
|
||||
- Sie wissen, dass ein Modul aus einem C-File und einem passenden H-File bestehen.
|
||||
- Sie können Header Files korrekt strukturieren.
|
||||
- Sie wissen wie **Include Guards** anzuwenden sind.
|
||||
- Sie können Module im **Makefile** zur Kompilation hinzufügen.
|
||||
- Sie können anhand einer Beschreibung Typen und Funktionen in den passenden Header Files deklarieren.
|
||||
- Sie können **Makefile** Regeln schreiben.
|
||||
|
||||
Die Bewertung dieses Praktikums ist am Ende angegeben.
|
||||
|
||||
Erweitern Sie die vorgegebenen Code Gerüste, welche im **git** Repository **snp-lab-code** verfügbar sind.
|
||||
|
||||
___
|
||||
## 3. Aufgabe 1: Modularisieren
|
||||
|
||||

|
||||
|
||||
### 3.1 Teilaufgabe Modules einbinden, Header Files schreiben
|
||||
|
||||
- src/objects.h
|
||||
- 2 Datenstukturen definieren
|
||||
- `struct point` mit 2 double für x und y Koordinate
|
||||
- `struct line` mit 2 point
|
||||
- src/functions.h und .c
|
||||
- 2 Funktionen deklarieren und definieren
|
||||
- Berechnung der Länge `get_length`einer Linie (Annahme: Koordinaten sind alle positiv)
|
||||
- l = sqrt(h^ 2 + b^ 2)
|
||||
- ev. muss hier in den Anhang `#include <math.h>`
|
||||
- Berechnung der Steigung `get_slope` der Linie gegenüber dem Koordinatensystem
|
||||
- m = h / b
|
||||
- tests vorgeben
|
||||
|
||||
- src/objects.h
|
||||
- Include Guard
|
||||
- Includes
|
||||
- Struct für Punkt und Linie
|
||||
- Include Guard
|
||||
- src/functions.h
|
||||
- Include Guard
|
||||
- Includes
|
||||
- Deklarationen der Funktionen für Berechnung der Länge und Steigung
|
||||
- Include Guard
|
||||
- src/functions.c
|
||||
- Includes
|
||||
- Definitionen der Funktionen für Berechnung der Länge und Steigung
|
||||
- Include Guard
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
___
|
||||
## 4. Aufgabe 2: Makefile Regeln
|
||||
|
||||
Makefile ergänzen, damit Modul `functions` korrekt eingebunden und kompiliert wird.
|
||||
|
||||
1. Kompilieren Sie das ganze mittels **make clean default**. Es sollten keine Compiler Fehler auftreten.
|
||||
|
||||
### 4.1 Neue Regeln hinzufügen
|
||||
|
||||
- Vorraussetzung: tab2svg.sh aus Praktikum 3 wird um die Möglichkeit erweitert eine Linie zu zeichnen (`line:x1:y1:x2:y2:color`)
|
||||
- Studierende erstellen
|
||||
- mind. 2 Files `long.line` und `short.line` mit 2 unterschiedlichen Linien
|
||||
- Makefile Regeln um aus einem File `.line` ein File `.svg` mit Hilfe des Scripts zu erstellen
|
||||
- PHONY Regel `display` um beide `.svg` mit Firefox darzustellen
|
||||
- Vorgabe: sie sollen eine Variable für die Input-Dateien nutzen
|
||||
|
||||
Nachdem das Programm in Aufgabe 1 umgesetzt ist, geht es nun darum, im **Makefile** Regeln zu definieren welche die einzelnen Schritte von den Source Files zu den **png** Files ausführen.
|
||||
|
||||
Prüfen Sie schliesslich die Umsetzung mittels `make display`.
|
||||
|
||||
___
|
||||
## 5. Aufgabe 3
|
||||
- Studierende sollen Ausgabe von `make doc` analysieren und die Include Diagramme erklären können
|
||||
```
|
||||
make doc
|
||||
firefox doc/index.html &
|
||||
```
|
||||
|
||||
___
|
||||
## 6. Bewertung
|
||||
|
||||
|
||||
Die gegebenenfalls gestellten Theorieaufgaben und der funktionierende Programmcode müssen der Praktikumsbetreuung gezeigt werden. Die Lösungen müssen mündlich erklärt werden.
|
||||
|
||||
___
|
||||
## 7. Erweiterung Doxyfile für Abhängigkeitsanalyse
|
||||
|
||||
```
|
||||
--- /home/vagrant/huno/snp-new/snp/praktika/Shared/work/Doxyfile 2022-02-07 21:16:42.343302707 +0100
|
||||
+++ /home/vagrant/snp/Doxyfile 2022-02-07 22:22:36.266839126 +0100
|
||||
@@ -297,14 +297,14 @@
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
TEMPLATE_RELATIONS = NO
|
||||
-INCLUDE_GRAPH = NO
|
||||
-INCLUDED_BY_GRAPH = NO
|
||||
+INCLUDE_GRAPH = YES
|
||||
+INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
-GRAPHICAL_HIERARCHY = NO
|
||||
-DIRECTORY_GRAPH = NO
|
||||
+GRAPHICAL_HIERARCHY = YES
|
||||
+DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
-INTERACTIVE_SVG = NO
|
||||
+INTERACTIVE_SVG = YES
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*****************************************************************************
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
// begin students to add code for task 4.1
|
||||
|
||||
// end students to add code
|
||||
@@ -0,0 +1,16 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
// begin students to add code for task 4.1
|
||||
|
||||
// end students to add code
|
||||
@@ -0,0 +1,16 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
// begin students to add code for task 4.1
|
||||
|
||||
// end students to add code
|
||||
@@ -0,0 +1,16 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
// begin students to add code for task 4.1
|
||||
|
||||
// end students to add code
|
||||
@@ -0,0 +1,16 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||||
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||||
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||||
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Lab implementation
|
||||
*/
|
||||
// begin students to add code for task 4.2
|
||||
|
||||
// end students to add code
|
||||
@@ -0,0 +1,34 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ 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)
|
||||
{
|
||||
// begin students to add code for task 4.1
|
||||
|
||||
// end students to add code
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
a
|
||||
a
|
||||
a
|
||||
3
|
||||
4444
|
||||
4444
|
||||
44444444444444
|
||||
4
|
||||
4
|
||||
5
|
||||
5
|
||||
@@ -0,0 +1,12 @@
|
||||
3
|
||||
4
|
||||
6
|
||||
5
|
||||
4
|
||||
4
|
||||
3
|
||||
5
|
||||
5
|
||||
33
|
||||
43
|
||||
55
|
||||
@@ -0,0 +1,12 @@
|
||||
3
|
||||
4
|
||||
5
|
||||
5
|
||||
4
|
||||
3
|
||||
3
|
||||
5
|
||||
4
|
||||
33
|
||||
44
|
||||
55
|
||||
@@ -0,0 +1,205 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ 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
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk")
|
||||
|
||||
TARGET := bin/dep2dot
|
||||
# Add all additional c-files to the SOURCES variable
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
SOURCES := src/main.c
|
||||
# END-STUDENTS-TO-ADD-CODE
|
||||
TSTSOURCES := tests/tests.c
|
||||
|
||||
include $(SNP_SHARED_MAKEFILE)
|
||||
|
||||
|
||||
# DEPFILES := ... define a list of png file names: %.c -> %.c.png
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define dep target as .PHONEY
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define dep target depending on FULLTARGET and DEPFILES above
|
||||
# action: echo some text telling that the target is done using $@ - the echo command shall not be echoed before execution
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define new suffix rule for %.png depending on %.dot
|
||||
# action: dot -Tpng $< >$@ || $(RM) $@
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# define new suffix rule for %.dot depending on %.dep
|
||||
# action: call $(TARGET) $(@:.dot=) <$< >$@ || $(RM) $@
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
# BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
# converts any .c file into a .c.dep file by means of GCC -H switch
|
||||
# note: it removes intermediate files which were created as side effect
|
||||
%.c.dep: %.c
|
||||
$(COMPILE.c) -H -o $@.x $< 2>$@ && $(RM) $@.x $@.d
|
||||
|
||||
|
||||
# cleanup all results, including the ones od creating the dependencies
|
||||
dep-clean: clean
|
||||
$(RM) $(DEPFILES) $(wildcard src/*.dep src/*.dot)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @mainpage SNP - P04 Modularisation
|
||||
*
|
||||
* @section Purpose
|
||||
*
|
||||
* This is a lab for splitting functionality into multiple modules.
|
||||
*
|
||||
*/
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Access to the GCC produced dependency data (via gcc -H command line option).
|
||||
*/
|
||||
|
||||
// begin of include guard
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// includes which are needed in this header file
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Directory container for file entries of the dependency file.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
/**
|
||||
* @brief File container for the file entries of the dependency file.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Overall container for all directories and all files from the dependency file.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entry function to read the deendency data from stdin.
|
||||
* @param root [IN] The name of the root file (the deoendency file does not mention the root file, so, it has to be passed from outside).
|
||||
* @return The container of the read data from stdin. See the documentation on gcc -H for details on the dependencies, etc.
|
||||
*/
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
// end of include guard
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @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_
|
||||
@@ -0,0 +1,36 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ 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;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Provides output functions for various file formats.
|
||||
*/
|
||||
#include "output.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief Writes the node name of the given file.
|
||||
* @param file [IN] The file for which to write the node name.
|
||||
* @remark The dependency data contain duplicates of file entries - the node name must be unique for the path and the *basename* of the files.
|
||||
*/
|
||||
static void print_node(file_t file)
|
||||
{
|
||||
printf("\"%s (cluster_c%zd)\"", file.name, file.dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursively writes the individual direct dependencies for the file given by curr.
|
||||
* @param files [IN] The array of all files - the sequence is relevant.
|
||||
* @param len [IN] The lenght of the files array, i.e. the upper limit for curr values and the subsequent index values.
|
||||
* @param curr [IN] The index into files for the current root for dependencies: curr -> x, curr -> y, ...
|
||||
* @return Returns the index into files for the next file to process (i.e. curr value for the next call to this function).
|
||||
* @remark For a given *curr* file, all following files are with depth level + 1 are direct include files.
|
||||
* @remark All files with a higher level are *indirect* include files, thus *direct* includes from files processed by recursive calls.
|
||||
* @remark The list of direct includes to the *curr* file terminates with a level equal of less the the *curr* one (or when the list is exchausted).
|
||||
*/
|
||||
static size_t dependencies(file_t files[], size_t len, size_t curr)
|
||||
{
|
||||
assert(curr < len);
|
||||
size_t level = files[curr].level;
|
||||
size_t file = curr + 1;
|
||||
while(file < len && files[file].level > level) {
|
||||
if (files[file].level == level + 1) {
|
||||
// Write to stdout " file -> include;\n" where file and include are the DOT node names of the respective files
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
file = dependencies(files, len, file);
|
||||
} else {
|
||||
file++;
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public interface
|
||||
*/
|
||||
void output_dot(const data_t data)
|
||||
{
|
||||
printf("digraph dep {\n");
|
||||
// nodes
|
||||
printf(" node [shape=box]\n");
|
||||
for (size_t file = 0; file < data.n_files; file++) {
|
||||
// Write to stdout " file [label=\"name\"];\n" where file is the DOT node name and name is the file name
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
// directory clusters
|
||||
for (size_t dir = 0; dir < data.n_dirs; dir++) {
|
||||
printf(" subgraph cluster_c%zd {\n", dir);
|
||||
printf(" label=\"%s\"; %s\n", data.dirs[dir].name, strncmp(data.dirs[dir].name, "/usr/", 5) == 0 ? "style=filled; color=lightgrey;" : "color=black;");
|
||||
for (size_t file = 0; file < data.n_files; file++) {
|
||||
if (data.files[file].dir == dir) {
|
||||
// Write to stdout " file;\n" where file is the DOT node name
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
}
|
||||
}
|
||||
printf(" }\n");
|
||||
}
|
||||
|
||||
// dependencies
|
||||
size_t curr = 0;
|
||||
do {
|
||||
curr = dependencies(data.files, data.n_files, curr);
|
||||
} while(curr < data.n_files);
|
||||
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Provides output functions for various file formats.
|
||||
*/
|
||||
// define proper header file here, with include gaurd, etc.
|
||||
// BEGIN-STUDENTS-TO-ADD-CODE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// END-STUDENTS-TO-ADD-CODE
|
||||
@@ -0,0 +1,7 @@
|
||||
Test File
|
||||
. dir1/h1_1
|
||||
.. dir1/h1_1_2
|
||||
. dir1/h1_2
|
||||
. dir2/h2_1
|
||||
.. dir1/h1_1
|
||||
Done
|
||||
@@ -0,0 +1,2 @@
|
||||
Test File
|
||||
Done
|
||||
@@ -0,0 +1,140 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* -- _____ ______ _____ -
|
||||
* -- |_ _| | ____|/ ____| -
|
||||
* -- | | _ __ | |__ | (___ 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
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user