Toy Story & Debian

“Toy Story was released by Pixar November 22nd, 1995. One year later Debian 1.1 was released. Bruce Perens was the DebianProjectLeader then and also worked for Pixar. He started the tradition of naming Debian releases after Toy Story characters.” – wiki.debian.org/ToyStory -> Debian


debian_wallpaper_by_voku1987
debian_wallpaper_by_voku1987

SpeedUp Ubuntu

1.) Kenne dein System (Hardware)

Am besten ist es den Flaschenhals an seinem System ausfindig zu machen, dafür sollte man wissen wie viel Arbeitsspeicher zur Verfügung steht, CPU Auslastung, Festplattengeschwindigkeit etc. aktuell verbraucht wird. Ggf. kann man auch mit neuer Hardware (z.B. > RAM) das System beschleunigen, dies muss natürlich bei jedem System einzeln geprüft werden.


1.1) Arbeitsspeicher


free -mt


  • total: kompletter physikalischer Speicher ( – ein wenig für den Kernel)
  • use: verwendeter Speicher
  • free: freier Speicher
  • buffers/cache: Speicher der wieder freigegeben werden kann, wenn dieser benötig wird. (Cache)

Somit sollte auch klar sein, dass es GUT ist, wenn der Arbeitsspeicher gut ausgenutzt wird, sollte jedoch “use” – “buffer/cache” zu klein werden oder bereits “Swap” (Auslagerungsspeicher -> meist Festplattenplatz) verbracht wird und somit das System wirklich ausbremst.


1.2) Festplatte


hdparm -t /dev/harddrive


Wenn es ewig dauert bis das System gebootet ist oder Programme starten, sollte man die Lesegeschwindigkeit seiner Festplatte einmal testen und ggf. eine neue Festplatte kaufen. ;-) Dabei sollte die Festplatte nicht unter ~50MB/s sein. Moderne SATA-Festplatten haben im Durchschnitt 100MB/s und bei SSD-Festplatten ist eine Datenraten bis zu ~500 MB/s möglich. (SATA-600).


1.3) CPU


top


Ich hatte das Programm “top” bereits in einem vorherigen Blog-Post beschrieben -> http://suckup.de/blog/2010/11/09/linux-server-analysieren/ <- top zeigt unter anderem die Auslastung der CPU je Programm an.


1.4) Grafikkarte


glxinfo | grep direct


Wenn du Engpässe beim abspielen von Videos oder beim Spielen feststellst, kannst du mit dem vorherigem Befehl feststellen, ob “Direct Rendering” aktiviert ist. Ggf. reicht es aus andere Treiber zu installieren, nach meiner Erfahrung sind die Proprietäten Treiber bei neuen Grafikkarten (ATI & NVIDIA) sehr gut. (http://suckup.de/blog/2010/02/09/lxde-compiz-emerald-awn-ubuntu-howto/) Wer eine alte Grafikkarte hat, kann auch diese 3D-Effekte (Compiz) ausschalten, ggf. andere Treiber installieren und schauen, ob der Desktop dadruch flüssiger läuft.


2.) Lightweight Software

Bevor man in neue Hardware investiert (oder sich diese zu Weihnachten schenken lässt) sollte man einmal “Lightweight Software” ausprobieren, diese bieten zwar ggf. weniger Funktionen, sind dafür aber schneller.


z.B.:
Desktop: Gnome -> LXDE oder Xfce
Browser: Firefox -> Chromium


https://wiki.archlinux.org/index.php/Lightweight_Applications


3.) Speicherplatz

3.1) Filesystem
[stextbox id=”alert” caption=”Achtung”]Achtung: Backup nicht vergessen!!![/stextbox]


Als erstes sollte man sich ein wenig mit dem Filesystem beschäfitigen, da ganz nach verwenddung ggf. ein anderes Filesystem verwendet werden sollte.


Zusammenfassung:
XFS: ausgezeichnete Leistung bei großen Dateien, dafür langsamere Geschwindigkeit bei kleinen Dateien (z.B. für ISO’s oder großen Downloads unter /home)


Reiserfs: ausgezeichnete Leistung bei kleinen Dateien (z.B. für viele kleine Dateien unter /var)


Ext3: durchschnittliche Leistung


Ext4: super Gesamtleistung (Leistungsprobleme bei sqlite und anderen Datenbanken)


JFS: gute Gesamtleistung (sehr geringe CPU-Last)


Btrfs: super Gesamtleistung (besser als ext4 ABER ggf. unstable)


3.2) Mount Optionen

/dev/partition /mnt/partition partitiontype option1,option2 0 0


Ein weitere Möglichkeit das Dateisystem zu optimieren, sind die “Mount Optionen”, diese trägst du in der Datei “/etc/fstab” ein. So kann man z.B. durch “relatime” oder “noatime” verhindern, dass die Zugriffszeiten in der Inodetabelle gespeichert werden und so die Festplattenaktivität reduziert werden.



sudo tune2fs -O dir_index /dev/partition


Mit dem vorigem Befehl wird die automatische Indizierung von Ordnerinhalten aktiviert, so dass man schneller aus die Daten zugreifen kann.
(wer ggf. von Ext3 auf Ext4 wechseln möchte kann dies tun: http://suckup.de/blog/2010/02/14/konvertiere-ext3-zu-ext4/)
Sowohl bei Ext3 als auch bei Ext4 wird ein Journal geschrieben, dieses kann man mit der Option “data=writeback” einschränken und somit die Preformance steigern, kann jedoch zu Problemen führen, da die metadata nun “träge” gespeichert werden.


Journal‘ – Langsamster und sicherster Modus. Nicht nur die Metadaten sondern auch die Nutzdaten werden zunächst in das Journal, und dann erst auf die Festplatte geschrieben.
Ordered‘ – Guter Kompromiss aus Sicherheit und Geschwindigkeit (Standard). Die Nutzdaten werden auf die Festplatte geschrieben sobald die Metadaten im Journal abgelegt wurden.
Writeback‘ – Schnell, dafür relativ unsicher. Die Nutzdaten werden sofort auf die Festplatte geschrieben ohne das gewartet wird bis die Metadaten im Journal abgelegt wurden.


tune2fs -o journal_data_writeback /dev/partition


mit dem vorherigem Befehl schreibt man das vorhandene Journal um…


/dev/partition / ext4 errors=remount-ro,noatime,nodiratime,data=writeback,barrier=0,nobh,commit=100,nouser_xattr 0 1


noatime” sagt aus, dass nicht gespeichert wird, wann die Datei angesehen wurde. (man liest eine Datei und gleichzeitig wird auf die Dateien geschrieben) Auch “barrier=0” trägt dazu bei, dass deine Daten unsicherer sind, die Option steigert jedoch die Performance. (so soll die Option einen sehr positiven Einfluss auf die Schreib-Performance von MySQL haben) Die Option “nobh” versucht “associating buffer heads” zu vermeiden und bringt eine kleine Performace verbesserung. Als nächstes kommt die Option “commit=100“, diese Option sagt aus, dass die Daten nur alle 100 Sekunden auf die Festplatte geschrieben werden, dafür verliet man ggf. auch 100 Sekunden bei einem Ausfall (default 5). “nouser_xattr” schaltet einige weitere Optionen vom Dateisystem aus und bringt noch einmal einen kleinen Performanceschub.



XFS –> zur optimierung kann man das Dateisystem mit dem folgedem Kommando anlegen …


mkfs.xfs -l internal,lazy-count=1,size=128m -d agcount=2 /dev/partition


… und die “Mount Option” -> “logbufs=8” in der fstab einfügen. Zudem kann man das gemountete XFS-Filesysteme per “filesystem reorganizer for XFS” Optimieren.


xfs_db -c frag -r /dev/partition


-> stellt den Fragmentationsgrad fest


xfs_fsr /dev/partition


-> defragmentiert die Partition (apt-get install xfsdump)


Die Option “data=writeback” beschleunigt das Dateisystem, kann jedoch zu Datenverlust beim Stromausfall führen. Auch “notail” beschleunigt Reiserfs bewirkt jedoch, dass zirka 5% mehr an Festplattenplatz benötigt wird. Zudem kann man mit dem nächsten Befehl bereits beim erstellen das Dateisystems dieses beschleunigen, indem man das Journal auf eine zweite Partition auslagert.


mkreiserfs –j /dev/hda1 /dev/hdb1



Dieses neue Dateisystem bietet “online Defragmentation”, “Optimierungen für SSDs”, “Snapshots” und viele weitere Sinnvolle Funktionen, wird jedoch momentan noch aktiv entwickelt.


Informationen zum optimieren von SSDs findest du hier -> https://wiki.archlinux.org/index.php/SSD#Tips_for_Maximizing_SSD_Performance


(Im Arch-Linux Wiki habe ich auch noch von der Möglichkeit gelesen “/usr” komplett zu komprimieren (aufs2 + squashfs-tools) da moderne CPUs schneller die Dateien entpacken können als das größere Daten von der Festplatte geladen werden können, leider habe ich diesbezüglich keine Infos zu Ubuntu gefunden.)


4.) CPU

Hier kann man in erster Lienie Overclocking betreiben und somit einiges an Geschwindigkeit herausholen, so habe ich z.B. aus einem “AMD Athlon II X3” einen “AMD Athlon II X4” gemacht. (PS: wer Fragen zur Hardware hat, sollte sich einmal das Computerbase-Forum anschauen, habe dort auch meinen neuen PC gemeinsam mit anderen Mitgliedern zusammengestellt -> “http://www.computerbase.de/forum/showthread.php?p=8532713” + Vorlagen für verschiedene Preisklassen http://www.computerbase.de/forum/showthread.php?p=3395405)


Wenn man auf der Software-Seite seine CPU besser nutzen möchte kann man einen optimierten Kernel bauen oder zumindest bei Arch-Linux sein System mit neuen “CFLAGS & CXXFLAGS” neu-kompilieren lassen. (https://wiki.archlinux.org/index.php/Pacbuilder) Falls jemand ein ähliches Programm für Ubuntu kennt, würde ich dies gerne erfahren. :-)


4.1) optimierten Kernel bauen

Download: KernelCheck – .deb


Download: Patch


Install: KernelCheck
dpkg -i *.deb


Starte KernelCheck
-> “custom complication”
-> “normal performance patch”
-> “Configure kernel options manually, auto-configure ALSA options for sound, Optimize the kernel, Install kernel package after complication”
-> “Apply custom path to kernel”


Nachdem die Dateien heruntergeladen und entpackt wurden, bekommst du eine Shell in der du den Patch einspielen musst.


cd linux
cp /home/USER/Desktop/patch-2.6.36-ck2 .
patch < patch-2.6.36-ck2 -p1


Nachdem du das Fenster wieder verlässt kannst du noch einige Optimierungen auswählen:


-> “Processor type and features”



4.2) optimierten Kernel (+ Brain Fuck Scheduler)


… man kann hier natürlich auch auf ppa zurückgreifen (jedoch noch nicht getestet)!


sudo add-apt-repository ppa:chogydan/ppa && sudo apt-get update
sudo apt-get install linux-ck-generic linux-ck-headers-generic


5.) RAM & swap


5.1) Auslagerung von Speicher
swappiness” ist eine Einstellung, welche dem Kernel mitteilt ob der RAM oder der SWAP bevorzugt werden soll. Der Wert der Variablen kann zwischen 0 und 100 liegen. Der Wert 0 bedeutet, dass der Kernel den Auslagerungsspeicher auf der Festplatte (swap) nur dann nutzt, wenn es nicht anders geht. Der Wert 100 bedeutet das genaue Gegenteil. Es wird so früh wie möglich ein unbenutzter Speicherbereich in den Swapspeicher geschoben.


vim /etc/sysctl.conf
vm.swappiness=20
vm.vfs_cache_pressure=50


5.2) Compcache
Compcache, auch als “ramzswap kernel module” bezeichnet erstellt Swap im Arbeitsspeicher und komprimiert diesen. So dass zwar die CPU wieder mehr zu tun hat, wir jedoch mehr Auslagern können, ausserdem hat dies den Vorteil, dass die Lese-/Schreizugriffe auf der Festplatte weiter reduziert werden.



5.3) tmpfs
Einen ählichen Ansatz, wie “Compcache” verfolgt auch “tmpfs” hier werden die Daten jedoch einfach in den Arbeitsspeicher geschrieben, ohne diese zu komprmieren. Wenn man jedoch genügent Speicher übrig hat, kann man so z.B. die “/tmp”-Daten in den Speicher auslagern.
vim /etc/fstab
tmpfs /tmp tmpfs defaults,noatime,nodev,nosuid,mode=1777 0 0
(nach diesem Prinzip kann man auch z.B. den Cache vom ff oder vom Chrome auslagern)


6.) Netzwerk & Internet


6.1) DNS
Ggf. sollte man schauen, ob man nicht einen schnelleren DNS-Server in seiner nähe findet ;-) -> http://suckup.de/blog/2010/02/13/find-a-fast-dns-server/
zumdem sollte man seinen eigenen Hostnamen in die der Datei “/etc/hosts” eintragen.
127.0.0.1 localhost
127.0.1.1 Rechnername
wird zu …
127.0.0.1 localhost Rechnername
127.0.1.1 Rechnername


Wer Spaß hat kann sich auch einen kleinen lokalen DNS-Cache installieren.
sudo apt-get install dnsmasq
vim /etc/dnsmasq.conf
listen-address=127.0.0.1
vim /etc/dhcp3/dhclient.conf
prepend domain-name-servers 127.0.0.1;
z.B.:
#supersede domain-name "suckup.de voku-online.de";
prepend domain-name-servers 127.0.0.1;
request subnet-mask, broadcast-address, time-offset, routers,
domain-name, domain-name-servers, host-name,
netbios-name-servers, netbios-scope;
vim /etc/resolv.conf
z.B.:
search suckup.de
nameserver 127.0.0.1
nameserver 8.8.4.4
vim /etc/resolv.dnsmasq.conf
resolv-file=/etc/resolv.dnsmasq.conf
listen-address=127.0.0.1
vim /etc/resolv.dnsmasq.conf
nameserver 8.8.4.4
vim /etc/resolv.conf
z.B.:
search suckup.de
nameserver 127.0.0.1
sudo /etc/init.d/dnsmasq restart


6.2) SYSCTL

In der Datei “sysctl.conf” kannst du Paramether für dein System einstellen.


wget -c http://www.rubyringtechnologies.com/files/sysctl.conf.txt -O ~/sysctl.conf
sed -i 's/\(net\.core\.hot_list_length\ =\ 256\)/\#\1/' ~/sysctl.conf
cat < ~/sysctl.conf >> /etc/sysctl.conf
sysctl -p


6.3) MTU


Typische MTU-Größen:
Medium MTU in Bytes
Hyperchannel 65535
Token Ring(4)(802.5) 4464
Token Ring(16) 17914
FDDI 4352
Ethernet 1500
Gigabit Ethernet
mit Jumboframes
9000
PPPoE (z. B. DSL) ≤ 1492
SLIP/PPP (low delay) 296
X.25 576
FibreChannel theoretisch unbegrenzt
ISDN 576
DQDB
HIPPI
ATM 4500, s. u.
ARCNET
802.11 2312 (WiFi)

Quelle: http://de.wikipedia.org/wiki/Maximum_Transmission_Unit


ping -Mdo -s 1500 8.8.8.8


-> mit dem vorherigem Befehl kannst du testen welche MTU funktioniert (z.B. 1500)


Konfig-Beispiel:

vim /etc/network/interfaces

iface eth0 inet static
address 192.168.0.1
network 192.168.0.0
gateway 192.168.0.254
netmask 255.255.255.0
mtu 1492


7.) preload, ureadahead etc.

ureadahead ist standardmäßig bereis bei Ubuntu installiert und lädt Programme bereits beim Bootvorgang in den RAM, falls man z.B. preload (apt-get install preload) einsetzten will, sollte man ureadahead deaktivieren, da es die selbe Aufgabe übernimmt. “preload” hat den Vorteil, dass es im Betrieb protokolliert welche Programme wirklich verwendet werden und nur diese bereits beim Boot in den RAM lädt, daher startet das System schneller, die Programm werden jedoch nicht schneller gestartet als mit ureadahead. (persönliche Meinung – nicht auf die Millisekunde gemessen) außerdem verursacht das Programm “preload” immer CPU-Last und verbraucht somit mehr Strom als wie ohne. ;-) Um den Boot-Vorgang näher zu analysieren soll man sich einmal “bootchart” (http://wiki.ubuntuusers.de/bootchart) anschauen.


8.) prelink

Wenn man den Start von Programmen beschleunigen will, kann man “prelink” (apt-get install prelink) ausprobieren, besonders bei KDE bringt dies einiges, da somit bei “dynamic linking” Programmen (Programm die nicht gelinkt sind, um z.B. Speicherplatz zu sparen) die Libraries nicht jedesmal bei geladen werden müssen. Prelink nutzt dies insofern aus, als dass es das Linken im Voraus ausführt und in der Programmdatei abspeichert. Somit kann man (fast) jedes Programm beschleunigen.


vim /etc/default/prelink

PRELINKING=unknown 

wird zu …

PRELINKING=yes 


http://wiki.ubuntuusers.de/Prelink


9.) localepurge

Nicht verwendete Sprachdateien zu entfernen erscheint zwar auf den ersten Blick nicht wirklich als Optimierung, jedoch hat sich in der Praxis gezeigt, dass einige Programm diese Sprachdateien z.B. beim Start in den Speicher laden, daher kann man so nicht nur Festplattenplatz, sondern ggf. auch Arbeitsspeicher einsparen und Programme schneller starten.



Quellen:

https://wiki.archlinux.org/index.php/Maximizing_Performance

http://sidux.com/index.php?module=Wikula&tag=SiduxTweaks

http://wiki.ubuntuusers.de/tuning

C-Programm – Palindrom

Dieses Programm teilt einen String in Wörter auf (strtok), anschließend wird jeweils geprüft ob diese von vorn und von hinten gelesen gleich bleiben und somit Palindrome sind.

#include <stdio.h>
#include <string.h>
#define LENGTH 150

// Testdatensatz:  "Ha/n/nah", "La-ger-regal", "O%t/to", "(Reit-)tier", "Reliefpfeiler", "Ren--tner", "R!o!t)or", "st--ets", "nein", "Hall67o" und "Lastwa$gen"

// Funktion: lengthOfString - die laenge von dem gegebenen String herausfinden
int lengthOfString(char wort[]) {
	int i = 0;
// solang das Ende (\0) nicht erreicht ist, wird der Wert i um 1 erhöht 
	while (wort[i] != '\0') {
        i++;
    }
    return i;
}

// Funktion: isPalindrom - prueft, ob der angegebe String ein Palindrom (lal, otto, lagerregal ...) ist
int isPalindrom(char wort[]) {
    int i;
    int length = lengthOfString(wort);

	for (i=0; wort[i] != '\0'; i++) {
	// for (i = 0; i <= (length-1); i++) { // Alternativ, solange keine Zeichen aus der Zeichenkette entfernt werden :-)
// vergleiche ersten und letzten, zweiten und vorletzten ... 
        if (wort[i] != wort[((length-1)-i)]) {
			return 0;
        }
    }
    return 1;
}

// Funktion: toLower - aus GROß wird klein -> ASCII-Tabelle anschauen ;-)
// Alternative-Funktion: tolower + ctype.h
int toLower(char wort[]) {
	int i;

	for (i=0; wort[i] != '\0'; i++) {
		if (wort[i] <= 90 && wort[i] >= 65) {
			wort[i] = wort[i]+32;
		}
	}
}

// Funktion: cleanString - entfernt '"' und ',' 
int cleanString(char wort[]) {
	int i,j;

	for (i=0, j=0; wort[i] != '\0'; i++) {
			if (wort[i] != 34 && wort[i] != 44) {
				wort[j++] = wort[i];
			}
		}
	wort[j]='\0';
}

// Funktion: removeNonLetters - entfernt Sonderzeichen aus einem String
int removeNonLetters(char wort[]) {
	int i,j;
	int alphabet_small_num = 97;
	int alphabet_big_num = 65;

	for (i=0, j=0; wort[i] != '\0'; i++) {
		while (alphabet_small_num <= 122) {
			if (wort[i] == alphabet_small_num) {
				wort[j++] = wort[i];
			}
			alphabet_small_num++;
		}
		while (alphabet_big_num <= 90) {
			if (wort[i] == alphabet_big_num) {
				wort[j++] = wort[i];
			}
			alphabet_big_num++;
		}
		alphabet_small_num = 97;
		alphabet_big_num = 65;
	}
	wort[j]='\0';
}

/*
// Alternative-Funktion: removeNonLetters + ctype.h - entfernt Sonderzeichen aus einem String
int removeNonLetters(char wort[]) {
	int i,j;

	for (i=0, j=0; wort[i] != '\0'; i++) {
		if (isalpha(wort[i])) {
			wort[j++] = wort[i];
		}
	}
	wort[j]='\0';
}
*/

// main - Hauptprogramm
int main(void) {
    char zeichenkette[LENGTH];
	char trennzeichen[] = " ";
	char *wort;

    printf("Bitte eine Zeichenkette eingeben: \n");
    fgets(zeichenkette, sizeof(zeichenkette), stdin);

	wort = strtok(zeichenkette, trennzeichen);
	while(wort != NULL) {

		cleanString(wort);

		printf("\n\nOriginal: %s\n", wort);
		if (isPalindrom(wort)) {
        	printf("Palindrom: %s\n", wort);
    	}
    	else {
        	 printf("kein Palindrom: %s\n", wort);
		}

		removeNonLetters(wort);
		printf("nach removeNonLetters: %s\n", wort);
    	if (isPalindrom(wort)) {
        	printf("Palindrom: %s\n", wort);
    	}
    	else {
        	 printf("kein Palindrom: %s \n", wort);
		}

		toLower(wort);
		printf("nach toLower: %s\n", wort);
    	if (isPalindrom(wort)) {
        	printf("Palindrom: %s \n", wort);
    	}
    	else {
    		printf("kein Palindrom: %s \n", wort);
		}
		printf("***********************************\n");

   		wort = strtok(NULL, trennzeichen); 
    }

    return 0;
}

weitere hilfreiche Tipps findest du unter: de.wikibooks.org

Ziproxy – HTTP-Traffic Kompression

Ziproxy ist ein nicht HTTP-Proxy Server, welcher Daten nicht zwischenspeichert, diese jedoch komprimiert und weiterleitet. Die meiste Bandbreite wird eingespart, indem Bilder neu-konvertiert werden und andere Daten per gzip komprimiert werden.

Ziproxy benötige keine Client-Software, solange der Browser die gzip-Daten korrekt dekomprimieren kann und auch mit JPEG 2000 Bildern umgehen kann. Der Proxy kann auf unterschiedliche Arten konfiguriert werden, ich hatte bereits vor langer Zeit über Ziproxy berichtet (Mein Proxy-Server) und da ich darauf aufmerksam gemacht wurde, dass die gezeigte Konfiguration in der neuen Version nicht mehr funktioniert, ich jedoch den gezeigten Proxy-Aufbau nicht mehr im Einsatz habe, wollte ich in diesem Blog-Post zumindest die beiden Grundkonfigurationen zeigen. (ggf. wäre ein solcher Proxy auch für Smartphones hilfreich)


1.) Ziproxy als Remote-Proxy

Als erstes die einfachste Variante, hier verbindet sich der Ziproxy über eine schnelle Verbindung (extern) mit dem HTTP-Servern und schickt die Daten über eine langsame Verbindung weiter.


Konfiguration: ziproxy.conf (mit ein paar Kommentaren)




Ziproxy-Standard
Ziproxy-Standard





2.) Ziproxy als Remote-Proxy + Local-Proxy

Die Konfiguration des Remote-Proxys unterscheidet sich im Grunde nicht von der ersten Variante, auch hier wird keine Client-Software benötigt, da ein zweiter lokaler Ziproxy sozusagen als Client fungiert, dies hat den Vorteil:

  • der Browser muss nicht “JPEG 2000” unterstützen
  • der Client (z.B. Squid) muss nicht “gzip” unterstützen
  • CPU-Last wird auf einen Server verlagert (ggf. wenn der Browser durch “JPEG 2000”-Bilder hohe CPU-Last erzeugt)

Konfiguration: Ziproxy-Client

Port = 8080
Address = "127.0.0.1"
NextProxy="81.169.188.94"
NextPort=3128
ImageQuality = {85,85,85,85}
JP2ImageQuality = {85,85,85,85}
MaxUncompressedGzipRatio = 4000
MinUncompressedGzipStreamEval = 250000
MaxSize = 2097152
Gzip = true
DecompressIncomingGzipData = true




Ziproxy_Dual
Ziproxy_Dual




Link: ziproxy.sourceforge.net

Android Debug Bridge (adb) – HowTo


In diesem Blog-Post beschreibe ich ein wenig die Funktionen der “Android Debug Bridge” (adb), dies ist ein Programm um von einen PC (Linux, Windows, MAC) mit dem Android-Handy zu kommunizieren, ich habe in diesem HowTo Windows verwendet. Adb ist im “Android-SDK” enthalten.

1. Vorbereitung

Als erstes müssen wir uns die Android-SDK herunterladen und installieren.


1.1) Treiber
Wenn du dein Handy noch nie mit deinem PC verbunden hast, musst du ggf. auch noch die Treiber installieren.


Windows XP” -> “SAMSUNG New PC Studio” -> Download-Link

Windows 7” -> “SAMSUNG Kies“ -> Download-Link


1.2) Download


1.3) Installation
android-sdk*.zip entpacken wir als erstes, dann kopieren wir “android-sdk-windows” nach C:\ und starten den darin enthaltenen “SDK Manager.exe”.



ADB
ADB


1.4) USB Debug aktivieren
USB debug auf dem Handy aktivieren…
Einstellungen – Anwendung – Entwicklung: „USB-Debugging“
…und danach dein Android per USB mit dem PC verbinden.


2.) ADB-Kommandos

Nun starten die die Windows-Kommandozeile…



cmd
cmd



… und können nun folgende Befehle ausführen.
# in folgndes Verzeichnis wechseln
cd C:\android-sdk-windows\platform-tools
# ADB-Hile anziegen lassen
adb -h
# zeigt die angeschlossenen Android-Geräte an
adb devices
# Android wird neu-gestartet
adb reboot
# Android wird im Recovery-Modus gestartet
adb reboot recovery
# dumping Debug Information (~ tail -f /var/log/everything.log) ;-)
adb logcat
# der allgemine Befehl für Kommandos
adb [-s ] 
# startet die Android-Konsole, dann kannst
adb [-s ] shell
# zeigt das Android-Logfile an (~tail -f /var/log/everything)
adb logcat
V —> Verbose (lowest priority)
D —> Debug
I —> Info
W —> Warning
E —> Error
F —> Fatal
S —> Silent (highest priority, on which nothing is ever printed)
# z.B. alle Error-Meldungen anziegen lassen
adb logcat *:E
radio  —> View the buffer that contains radio/telephony related messages.
events —> View the buffer containing events-related messages.
main   —> View the main log buffer (default)
# z.B. alle Event-Meldungen anziegen lassen
adb logcat -b events
# installiert ein App von deinem PC aus
adb install \
# Upload eine Datei von deinem PC (localfile) zum Handy
adb push  
# Download eine Datei von Handy zu deinem PC
adb pull  


In dem CyanogenMod – Wiki gibt es noch weitere hilfreiche Befehle: http://wiki.cyanogenmod.com/index.php?title=ADB


— die nachfolgenden Befehle werden in der “adb shell” ausgeführt —


Dabei können die meisten der folgenden Befehle können auch in anderen Linux-Systemen verwendet werden… :-)


# zeigt das Android-Logfile an (~tail -f /var/log/everything)
logcat
# zeigt Kernel-Debug Infos an
dmesg
# zeigt die System-Apps an (ls = dir unter Windows)
ls /system/app/
# zeigt die installierten Apps an
ls /data/app/
# zeigt Daten auf deiner SD-Karte an
ls /mnt/sdcard/
# zeigt den Inhalt einer Datei an oder kopiert diese auch, wenn nötig
cat lall.txt
cat lall.txt > lall_copy.txt
# zeigt an wer du bist ;-)
whoami
# zeigt die laufenden Prozesse an
ps 
#zeigt die Systemauslastung an
top | tail
# zeigt alle eingehängten Partitionan an
mount
# grep filtert z.B. Ausgaben
mount | grep system
# root-Rechte erhalten (su = substitute user)
su
# alle Partition können nun beschrieben werden
remount rw
# z.B. die Partition /system kann nun beschrieben werden (read & write)
remount rw /system
# die Partition /system kann nun nicht mehr beschrieben werden (read only)
remount ro /system
# z.B. löscht ein System-App (rm = del unter Windows)
rm /system/app/
# löscht ein installiertes App
rm /data/app/


PS: Da ich den “Cyanogenmod” bei mir installiert habe, stehen mir noch viele weitere Programme wie z.B. einen SSH-Server (dropbear), wget… zur Verfügung, :-) die hier gezeigten Befehle sollten aber auch ohne diesen Mod funktionieren.

Weihnachtsgeschenke für Geeks

Ein Geschenk für einen Computer-Freak zu finden ist gar nicht so schwer wie man auf Anhieb denkt. Denn es gibt ganze Webseiten, welche sich auf diese Kundschaft ausgerichtet haben. :-) Um einigen ahnungslosen Eltern, Freunden/-innen von (uns) Geeks einen Tipp zu geben, habe ich folgende kleine Liste zusammengestellt und wie man sieht müssen die Geschenke nicht einmal viel kosten.


1.) Taschentücher -> 1,25 €

US_Dollar
US Dollar als Taschentuch

2.) PC-Sticker -> 1.99 $

casebadges
casebadges


3.) 3D Notizblock -> 5,90 €

3D Notizblock
3D Notizblock

4.) Sudoku-Klopapier -> 6,95 €

sudoku_klopapier
sudoku Klopapier


5.) bOOleO Kartenspiel -> 11,90 €

bOOleO Kartenspiel
bOOleO Kartenspiel


6.) Lesezeichen an der Wand -> 14,90 €

Lesezeichen + Buchhalter
Lesezeichen + Buchhalter

7.) außergewöhnliche Ohrstöpsel -> 14,95 €

witzige Kopfhörer
witzige Kopfhörer

8.) myAVR Board light, Bausatz -> 14,95 Euro

board light Bausatz
board light Bausatz

9.) myBrett ->  15 €

myBrett
myBrett

10.) Widerstand ist zwecklos (T-Shirt) -> ~14,90 €

widerstand-zwecklos
widerstand-zwecklos

11.) Kaffee ist unverzichtbar -> 18.00 $

Kaffeetasse
Kaffeetasse

12.) Slide to unlock (Fußmatte) -> 19,90 €

Fußmatte Slide to unlock
Fußmatte Slide to unlock

13.) Selbstrührende Thermo-Tasse -> 19,95 €

selbstruehrende-tasse
selbstruehrende-tasse

14.)  W-Lan – T-Shirt -> 29,90 €

wlan_shirt
wlan_shirt


Auf den Webseiten gibt es natürlich noch Unmengen weitere interessante Dinge, über die sich jeder Geek freuen wird -> z.B.: “Fernzündung von Feuerwerkskörpern“, “Musikkissen“…

unoconv: umwandlung zwischen allen Dokument-Formaten von OpenOffice

Mit unoconv kann man viele Dokument-Formate konvertieren, unterstützte Formate sind unter anderem das  “Open Document Format” (.odt), “MS Word” (.doc), “MS Office Open/MS OOXML” (.xml), “Portable Document Format” (.pdf), “HTML”, “XHTML”, “RTF”, “Docbook” (.xml)…  

Funktionen:

  • konvertiert alle Formate die OpenOffice unterstützt
  • OpenOffice unterstützt bis zu 100 Dokument Formate :-)
  • kann genutzt werden um Vorgänge zu automatisieren (Skripte -> z.B. shell oder php)
  • unterstützt weitere Tools -> “asciidoc”, “docbook2odf/xhtml2odt”
  • kann Style-Vorlagen (templates) während der Konvertierung anwenden (corporate identity)
  • kann sowohl als Server, als auch als Client fungieren


Formate:

Es folgt eine Liste von Ausgabe-Formaten von OpenOffice (und somit auch von unoconv), die Eingabe-Formate können sich jedoch unterscheiden -> INPUT / EXPORT


Export:

  • bib – BibTeX [.bib]
  • doc – Microsoft Word 97/2000/XP [.doc]
  • doc6 – Microsoft Word 6.0 [.doc]
  • doc95 – Microsoft Word 95 [.doc]
  • docbook – DocBook [.xml]
  • html – HTML Document (OpenOffice.org Writer) [.html]
  • odt – Open Document Text [.odt]
  • ott – Open Document Text [.ott]
  • ooxml – Microsoft Office Open XML [.xml]
  • pdb – AportisDoc (Palm) [.pdb]
  • pdf – Portable Document Format [.pdf]
  • psw – Pocket Word [.psw]
  • rtf – Rich Text Format [.rtf]
  • latex – LaTeX 2e [.ltx]
  • sdw – StarWriter 5.0 [.sdw]
  • sdw4 – StarWriter 4.0 [.sdw]
  • sdw3 – StarWriter 3.0 [.sdw]
  • stw – Open Office.org 1.0 Text Document Template [.stw]
  • sxw – Open Office.org 1.0 Text Document [.sxw]
  • text – Text Encoded [.txt]
  • txt – Plain Text [.txt]
  • vor – StarWriter 5.0 Template [.vor]
  • vor4 – StarWriter 4.0 Template [.vor]
  • vor3 – StarWriter 3.0 Template [.vor]
  • xhtml – XHTML Document [.html]
  • […]


Installation:

aptitude install unoconv asciidoc docbook2od


Beispiele 1: Standard

Als erstes ein simples Beispiel, hier wird einfach “odt” in ein “pdf” umgewandelt. Sehr hilfreich ist auch sich die Optionen einmal anzuschauen.

# unoconv - Dienst starten
unoconv --listener &
# odt -> pdf 
unoconv -f pdf some-document.odt
# Standard 
(unoconv --server localhost --port 2002 --stdout -f pdf some-document.odt)

Beispiele 2: Vorlage

Wie bereits auf der Entwicklerseite zu lesen ist, hilf uns ein Screenshot nicht wirklich weiter, daher folgt ein zweites Beispiel mit Vorlagen.

# Beispiel Dateien herunterladen 
wget http://dag.wieers.com/cv/Makefile
wget http://dag.wieers.com/cv/curriculum-vitae-dag-wieers.txt
wget http://dag.wieers.com/cv/curriculum-vitae-docbook.ott

# unoconv - Dienst starten
unoconv --listener &
# resume.txt -> resume.xm
asciidoc -b docbook -d article -o resume.xml resume.txt
# resume.xml -> resume.tmp.odt
docbook2odf -f --params generate.meta=0 -o resume.tmp.odt resume.xml
# resume.tmp.odt -> resume.odt + Template
unoconv -f odt -t template.ott -o resume.odt resume.tmp.odt
# resume.tmp.odt -> resume.pdf + Template
unoconv -f pdf -t template.ott -o resume.pdf resume.odt
# resume.tmp.odt -> resume.html + Template
unoconv -f html -t template.ott -o resume.html resume.odt
# resume.tmp.odt -> resume.doc + Template
unoconv -f doc -t template.ott -o resume.doc resume.odt

Beispiele 3: Server <-> Client

Wie bereits erwähnt kann man den Dienst auch als Server starten und von anderen Rechnern darauf zugreifen.

# unoconv - Server-Dienst starten
unoconv --listener --server 1.2.3.4 --port 4567
# Client -> Server 
unoconv --server 1.2.3.4 --port 4567

Beispiele 4: PHP

Man kann dies nun auch in Shell-Skripten nutzen oder wie in diesem Beispiel in PHP einbinden.

$this->Filegenerator = new FilegeneratorComponent ($this->params["form"]['uploaddocfile']);
// if the filegenerator did all it's magic ok then process
if($this->Filegenerator)
// returns the text version of the PDF
$text = $this->Filegenerator->convertDocToTxt();
// returns the html of the PDF
$html = $this->Filegenerator->convertDocToHtml();
// returns the generated pdf file
$pdf = $this->Filegenerator->convertDocToPdf($doc_id);
}
<?php
/**
* Class Used to convert files.
*@author jamiescott.net
*/
class FilegeneratorComponent extends Object {

// input folder types
private $allowable_files = array ('application/msword' => 'doc' );
// variable set if the constuctor loaded correctly.
private $pass = false;
// store the file info from constuctor reference
private $fileinfo;

/**
* Enter description here...
*
* @param array $fileinfo
* Expected :
* (
[name] => test.doc
[type] => application/msword
[tmp_name] => /Applications/MAMP/tmp/php/php09PYNO
[error] => 0
[size] => 79360
)
*
*
* @return unknown
*/
function __construct($fileinfo) {

// folder to process all the files etc
define ( 'TMP_FOLDER', TMP . 'filegenerator/' . $this->generatefoldername () . '/' );

// where unoconv is installed
define ( 'UNOCONV_PATH', '/usr/bin/unoconv' );
// where to store pdf files
define ( 'PDFSTORE', ROOT . '/uploads/generatedpdfs/' );
// where to store doc files
define ( 'DOCSTORE', ROOT . '/uploads/docfiles/' );
// apache home dir
define ( 'APACHEHOME', '/home/apache' );
// set some shell enviroment vars
putenv ( "HOME=".APACHEHOME );
putenv ( "PWD=".APACHEHOME );

// check the file info is passed the tmp file is there and the correct file type is set
// and the tmp folder could be created
if (is_array ( $fileinfo ) &amp;amp;&amp;amp; file_exists ( $fileinfo ['tmp_name'] ) &amp;amp;&amp;amp; in_array ( $fileinfo ['type'], array_keys ( $this->allowable_files ) ) &amp;amp;&amp;amp; $this->createtmp ()) {

// bass by reference
$this->fileinfo = &amp;amp;$fileinfo;
// the constuctor ran ok
$this->pass = true;
// return true to the instantiation
return true;

} else {
// faild to instantiate
return false;

}

}

/**
*      * takes the file set in the constuctor and turns it into a pdf
* stores it in /uploads/docfiles and returns the filename
*
* @return filename if pdf was generated
*/
function convertDocToPdf($foldername=false) {

if ($this->pass) {

// generate a random name
$output_pdf_name = $this->generatefoldername () . '.pdf';

// move it to the tmp folder for processing
if (! copy ( $this->fileinfo ['tmp_name'], TMP_FOLDER . 'input.doc' ))
die ( 'Error copying the doc file' );

$command = UNOCONV_PATH;
$args = ' --server localhost --port 2002 --stdout -f pdf ' . TMP_FOLDER . 'input.doc';

$run = $command . $args;

//echo $run; die;
$pdf = shell_exec ( $run );
$end_of_line = strpos ( $pdf, "\n" );
$start_of_file = substr ( $pdf, 0, $end_of_line );

if (! eregi ( '%PDF', $start_of_file ))
die ( 'Error Generating the PDF file' );

if(!file_exists(PDFSTORE.$foldername)){
mkdir(PDFSTORE.$foldername);
}

// file saved
if(!$this->_createandsave($pdf, PDFSTORE.'/'.$foldername.'/', $output_pdf_name)){
die('Error Saving The PDF');
}

return $output_pdf_name;

}

}

/**
* Return a text version of the Doc
*
* @return unknown
*/
function convertDocToTxt() {

if ($this->pass) {

// move it to the tmp folder for processing
if (! copy ( $this->fileinfo ['tmp_name'], TMP_FOLDER . 'input.doc' ))
die ( 'Error copying the doc file' );

$command = UNOCONV_PATH;
$args = ' --server localhost --port 2002 --stdout -f txt ' . TMP_FOLDER . 'input.doc';

$run = $command . $args;

//echo $run; die;
$txt = shell_exec ( $run );

// guess that if there is less than this characters probably an error
if (strlen($txt) < 10)
die ( 'Error Generating the TXT' );

// return the txt from the PDF
return $txt;

}

}

/**
* Convert the do to heml and return the html
*
* @return unknown
*/
function convertDocToHtml() {

if ($this->pass) {

// move it to the tmp folder for processing
if (! copy ( $this->fileinfo ['tmp_name'], TMP_FOLDER . 'input.doc' ))
die ( 'Error copying the doc file' );

$command = UNOCONV_PATH;
$args = ' --server localhost --port 2002 --stdout -f html ' . TMP_FOLDER . 'input.doc';

$run = $command . $args;

//echo $run; die;
$html= shell_exec ( $run );
$end_of_line = strpos ( $html, "\n" );
$start_of_file = substr ( $html, 0, $end_of_line );

if (! eregi ( 'HTML', $start_of_file ))
die ( 'Error Generating the HTML' );

// return the txt from the PDF
return $html;

}

}
/**
* Create file and store data
*
* @param unknown_type $data
* @param unknown_type $location
* @return unknown
*/
function _createandsave($data, $location, $file) {

if (is_writable ( $location )) {

// In our example we're opening $filename in append mode.
// The file pointer is at the bottom of the file hence
// that's where $somecontent will go when we fwrite() it.
if (! $handle = fopen ( $location.$file, 'w' )) {
trigger_error("Cannot open file ($location$file)");
return false;
}

// Write $somecontent to our opened file.
if (fwrite ( $handle, $data ) === FALSE) {
trigger_error("Cannot write to file ($location$file)");
return false;
}

fclose ( $handle );
return true;

} else {
trigger_error("The file $location.$file is not writable");
return false;
}

}

function __destruct() {

// remove the tmp folder

if (file_exists ( TMP_FOLDER ) &amp;amp;&amp;amp; strlen ( TMP_FOLDER ) > 4)
$this->removetmp ();

}

/**
* Create the tmp directory to hold and process the files
*
* @return unknown
*/
function createtmp() {

if (is_writable ( TMP )) {

if (mkdir ( TMP_FOLDER ))
return true;

} else {

return false;
}

return false;

}

/**
* Delete the tmp dir
*
* @return unknown
*/
function removetmp() {

if (strlen ( TMP_FOLDER ) > 3 &amp;amp;&amp;amp; file_exists ( TMP_FOLDER )) {

if ($this->recursive_remove_directory ( TMP_FOLDER ))
return true;

}

return false;
}

/**
* Return a rendom string for the folder name
*
* @return unknown
*/
function generatefoldername() {

return md5 ( microtime () );

}

/**
* Recursivly delete directroy or empty it
*
* @param unknown_type $directory
* @param unknown_type $empty
* @return unknown
*/
function recursive_remove_directory($directory, $empty = FALSE) {
// if the path has a slash at the end we remove it here
if (substr ( $directory, - 1 ) == '/') {
$directory = substr ( $directory, 0, - 1 );
}

// if the path is not valid or is not a directory ...
if (! file_exists ( $directory ) || ! is_dir ( $directory )) {
// ... we return false and exit the function
return FALSE;

// ... if the path is not readable
} elseif (! is_readable ( $directory )) {
// ... we return false and exit the function
return FALSE;

// ... else if the path is readable
} else {

// we open the directory
$handle = opendir ( $directory );

// and scan through the items inside
while ( FALSE !== ($item = readdir ( $handle )) ) {
// if the filepointer is not the current directory
// or the parent directory
if ($item != '.' &amp;amp;&amp;amp; $item != '..') {
// we build the new path to delete
$path = $directory . '/' . $item;

// if the new path is a directory
if (is_dir ( $path )) {
// we call this function with the new path
recursive_remove_directory ( $path );

// if the new path is a file
} else {
// we remove the file
unlink ( $path );
}
}
}
// close the directory
closedir ( $handle );

// if the option to empty is not set to true
if ($empty == FALSE) {
// try to delete the now empty directory
if (! rmdir ( $directory )) {
// return false if not possible
return FALSE;
}
}
// return success
return TRUE;
}
}
}
?>

CLI Companion – die GUI in der Konsole

CLI Companion ist ein Terminal mit integrierter GUI oder sollte ich besser sagen ein GUI mit integriertem Terminal? Egal. Du kannst Shell-Kommandos (mit Beschreibung) abspeichern, so dass du diese mit der Zeit lernen kannst.


Installation:

sudo add-apt-repository ppa:clicompanion-devs/clicompanion-nightlies
sudo apt-get update
sudo apt-get install clicompanion


Beispiel:

CLICompanion
CLI Companion


Quelle:
launchpad.net/clicompanion

Droopy – Datenübertragung per HTTP

Das Python-Skript Droopy wird auf dem Zielrechner ausgeführt, so dass hier ein kleiner HTTP-Server gestartet wird, der eine einfache Seite mit Uploadformular enthält. Nun muss man nur noch dessen IP-Adresse zusammen mit der Portnummer in die Adresszeile des Browsers eingeben und kann Dateien verschicken (egal ob Windows, Mac, Linux …). Einzige Voraussetzung auf dem Zielrechner ist Python!


Download: droopy

wget http://stackp.online.fr/wp-content/uploads/droopy
mkdir uploads


Usage: droopy [options] [PORT]

Options:
  -h, --help                            show this help message and exit
  -m MESSAGE, --message=MESSAGE         set the message
  -p PICTURE, --picture=PICTURE         set the picture
  -d DIRECTORY, --directory=DIRECTORY   set the directory to upload files to
  --save-config                         save options in a configuration file
  --delete-config                       delete the configuration file and exit


Beispiel: droopy

python2 droopy -d uploads -m "Hi, schick mir doch mal ein paar Dateien... :-)" -p ~/Bilder/gemma-atkinson-108-06.jpg


droopy-Beispiel
droopy-Beispiel

C-Programm – Matrix-Addition

Mit diesen kleinen Programmen kann man Matrix-Addition durchführen, indem die Werte der Matrizen jeweils zusammengerechnet werden. In dem zweiten Programm habe ich mit Funktionen und Pointeren gearbeitet.

/*
 ============================================================================
 Name        : matrix-addition_1.c
 Author      : Voku
 Version     : 1.0
 Description : Matrix-Addition
 ============================================================================
 */

#include <stdio.h>
#define MAX_ZEILEN 10
#define MAX_SPALTEN 10

int main (void) {
	int index_zeile, zeile, index_spalte, spalte;
	double array_a[MAX_ZEILEN][MAX_SPALTEN], array_b[MAX_ZEILEN][MAX_SPALTEN], array_c[MAX_ZEILEN][MAX_SPALTEN];

	// Anzahl der Zeilen einlesen
	do {
		printf("Anzahl der Zeilen (1-%i): ",MAX_ZEILEN);
		scanf("%i",&zeile);
		if (zeile > MAX_ZEILEN ) {
			printf("\n zu viel Zeilen...\n\n");
		} else if (zeile < 1) {
			printf("\n zu wenig Zeilen...\n\n");
		}
	} while (zeile > MAX_ZEILEN || zeile < 1);
	printf("\n");
	// Anzahl der Spalten einlesen
	do {
		printf("Anzahl der Spalten (1-%i): ",MAX_SPALTEN);
		scanf("%i",&spalte);
		if (spalte > MAX_SPALTEN ) {
			printf("\n zu viel Spalten...\n\n");
		} else if (zeile < 1) {
			printf("\n zu wenig Spalten...\n\n");
		}
	} while (spalte > MAX_SPALTEN || spalte < 1);
	printf("\n");

	// Werte fuer Matrize 1 einlesen
	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
  			printf("Wert fuer Zeile %i und Spalte %i (Matrize 1) eingeben: ",index_zeile+1, index_spalte+1);
        		scanf("%lf",&array_a[index_zeile][index_spalte]);
    		}
    	}
	printf("\n");
    	// Werte fuer Matrize 2 einlesen
    	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
    		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
    			printf("Wert fuer Zeile %i und Spalte %i (Matrize 2) eingeben: ",index_zeile+1, index_spalte+1);
        		scanf("%lf",&array_b[index_zeile][index_spalte]);
    		}
    	}

	// Array A und B addieren und in Array C schreiben
	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
    		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
        		array_c[index_zeile][index_spalte]=array_a[index_zeile][index_spalte]+array_b[index_zeile][index_spalte];
    		}
	}

	// Ausgabe
	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
		printf("\n (");
    		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
        		printf(" %.2lf", array_a[index_zeile][index_spalte]);
        	}
		printf(" ) ");
	}
	printf("\n\n +\n");
	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
		printf("\n (");
    		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
			printf(" %.2lf", array_b[index_zeile][index_spalte]);
		}
		printf(" ) ");
	}
	printf("\n\n =\n");
	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
		printf("\n (");
    		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
			printf(" %.2lf", array_c[index_zeile][index_spalte]);
    		}
		printf(" ) ");
	}

	return 0;
}
/*
 ============================================================================
 Name        : matrix-addition_2.c
 Author      : Voku
 Version     : 1.0
 Description : Matrix-Addition mit Funktionen (+Pointer)
 ============================================================================
 */

#include <stdio.h>
#define MAX_ZEILEN 10
#define MAX_SPALTEN 10

void matrix_addition (double *array_a, double *array_b, double *array_c, int zeile, int spalte) {
	int index_zeile, index_spalte;
	// printf("*array_a %lf\n*array_b %lf\n*array_c %lf\n", *array_a, *array_b, *array_c); // TEST-Ausgabe
	for(index_zeile=0; index_zeile < zeile; index_zeile++) {
		for(index_spalte=0; index_spalte < spalte; index_spalte++) {
			*(array_c + (index_zeile * spalte) + index_spalte) = *(array_a + (index_zeile * spalte) + index_spalte) + *(array_b + (index_zeile * spalte) + index_spalte);
		}
		printf("\n");
	}
}

void matrix_ausgabe (double *matrix, int zeile, int spalte) {
	int index_zeile, index_spalte;
	// printf("*matrix %lf", *matrix); // TEST-Ausgabe
	printf("\n\n");
	for(index_zeile=0; index_zeile < zeile; index_zeile++) {
		for(index_spalte=0; index_spalte < spalte; index_spalte++) {
			printf(" %.2lf", *(matrix + (index_zeile * spalte) + index_spalte));
		}
		printf("\n");
	}
}

int main (void) {
	int index_zeile, zeile, index_spalte, spalte;

	// Anzahl der Zeilen einlesen
	do {
		printf("Anzahl der Zeilen (1-%i): ",MAX_ZEILEN);
		scanf("%i",&zeile);
		if (zeile > MAX_ZEILEN ) {
			printf("\n zu viel Zeilen...\n\n");
		} else if (zeile < 1) {
			printf("\n zu wenig Zeilen...\n\n");
		}
	} while (zeile > MAX_ZEILEN || zeile < 1);
	printf("\n");
	// Anzahl der Spalten einlesen
	do {
		printf("Anzahl der Spalten (1-%i): ",MAX_SPALTEN);
		scanf("%i",&spalte);
		if (spalte > MAX_SPALTEN ) {
			printf("\n zu viel Spalten...\n\n");
		} else if (zeile < 1) {
			printf("\n zu wenig Spalten...\n\n");
		}
	} while (spalte > MAX_SPALTEN || spalte < 1);
	printf("\n");

	double array_a[zeile][spalte], array_b[zeile][spalte], array_c[zeile][spalte];

	// Werte fuer Matrize 1 einlesen
	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
    			printf("Wert fuer Zeile %i und Spalte %i (Matrize 1) eingeben: ",index_zeile+1, index_spalte+1);
        		scanf("%lf",&array_a[index_zeile][index_spalte]);
    		}
	}
    	printf("\n");
    	// Werte fuer Matrize 2 einlesen
    	for (index_zeile=0; index_zeile < zeile; index_zeile++) {
    		for ( index_spalte=0; index_spalte < spalte; index_spalte++) {
    			printf("Wert fuer Zeile %i und Spalte %i (Matrize 2) eingeben: ",index_zeile+1, index_spalte+1);
        		scanf("%lf",&array_b[index_zeile][index_spalte]);
    		}
	}

	// printf("zeile + spalta: %i, %i", zeile, spalte); // TEST-Ausgabe

	// Array A und B addieren und in Array C schreiben
	matrix_addition(&array_a[0][0], &array_b[0][0], &array_c[0][0], zeile, spalte);

	// Ausgabe
	matrix_ausgabe(&array_a[0][0], zeile, spalte);
	printf("\n +");
	matrix_ausgabe(&array_b[0][0], zeile, spalte);
	printf("\n =");
	matrix_ausgabe(&array_c[0][0], zeile, spalte);

	return 0;
}