From be57a974c947e56db8d59575da09509867bcfe51 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 3 Sep 2011 20:46:12 -0700 Subject: [PATCH 001/145] working through exercise 1 --- .gitignore | 1 + ex1.c | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 .gitignore create mode 100644 ex1.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d697d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +ex1 diff --git a/ex1.c b/ex1.c new file mode 100644 index 0000000..f18c9d8 --- /dev/null +++ b/ex1.c @@ -0,0 +1,6 @@ +int main() +{ + puts("Hello world."); + + return 0; +} From e83c2a0f101fbfba59d9bfa976d30d90a73534ed Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 3 Sep 2011 20:47:36 -0700 Subject: [PATCH 002/145] adding include so that "puts" is not implicitly declared --- ex1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ex1.c b/ex1.c index f18c9d8..0d77642 100644 --- a/ex1.c +++ b/ex1.c @@ -1,3 +1,5 @@ +#include + int main() { puts("Hello world."); From 9ed30444e2ba234af14df1cf1ec2ceb3d0deaf8b Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 3 Sep 2011 20:50:44 -0700 Subject: [PATCH 003/145] extra credit stuff --- ex1.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ex1.c b/ex1.c index 0d77642..ea59ec4 100644 --- a/ex1.c +++ b/ex1.c @@ -3,6 +3,11 @@ int main() { puts("Hello world."); + puts("Hello man."); + puts("Hello to you."); + puts("Hello woman."); + puts("Hello to the world of learning C the hard way, mkay?"); + puts("yup."); return 0; } From e5116578987d438c176b1fa44dc5967655307a4e Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 3 Sep 2011 21:00:55 -0700 Subject: [PATCH 004/145] adding makefile for ch. 4 --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..931a728 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +CFLAGS=-Wall -g + +clean: + rm -f ex1 From a1902d9af4f8bc2526d147a4d4955e375a0cf347 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 3 Sep 2011 21:03:26 -0700 Subject: [PATCH 005/145] adding an "all" target and marking both it and "clean" as phony --- Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Makefile b/Makefile index 931a728..ee08819 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,11 @@ CFLAGS=-Wall -g + +all: ex1 + + clean: rm -f ex1 + + +.PHONY: all clean From 357323bdc8d2f453203b1d7cce91f1a08ffcb878 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 4 Sep 2011 22:18:49 -0400 Subject: [PATCH 006/145] up to chapter 7 --- .gitignore | 2 ++ Makefile | 6 ++++-- ex3.c | 12 ++++++++++++ ex4.c | 12 ++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 ex3.c create mode 100644 ex4.c diff --git a/.gitignore b/.gitignore index 2d697d2..da2db83 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ ex1 +ex3 +ex4 diff --git a/Makefile b/Makefile index ee08819..e390978 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,13 @@ CFLAGS=-Wall -g +EXERCISES = ex1 ex3 ex4 -all: ex1 + +all: $(EXERCISES) clean: - rm -f ex1 + rm -f $(EXERCISES) .PHONY: all clean diff --git a/ex3.c b/ex3.c new file mode 100644 index 0000000..df2f7ef --- /dev/null +++ b/ex3.c @@ -0,0 +1,12 @@ +#include + +int main() +{ + int age = 10; + int height = 72; + + printf("I am %d years old.\n", age); + printf("I am %d inches tall.\n", height); + + return 0; +} diff --git a/ex4.c b/ex4.c new file mode 100644 index 0000000..df2f7ef --- /dev/null +++ b/ex4.c @@ -0,0 +1,12 @@ +#include + +int main() +{ + int age = 10; + int height = 72; + + printf("I am %d years old.\n", age); + printf("I am %d inches tall.\n", height); + + return 0; +} From 6a0e1ba5e6731e0682448f9b62b8e37404273819 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 4 Sep 2011 22:33:10 -0400 Subject: [PATCH 007/145] done up to chapter 8 --- .gitignore | 1 + Makefile | 2 +- ex5.c | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 ex5.c diff --git a/.gitignore b/.gitignore index da2db83..aaabdc6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ ex1 ex3 ex4 +ex5 diff --git a/Makefile b/Makefile index e390978..74a0619 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 +EXERCISES = ex1 ex3 ex4 ex5 all: $(EXERCISES) diff --git a/ex5.c b/ex5.c new file mode 100644 index 0000000..ac12e73 --- /dev/null +++ b/ex5.c @@ -0,0 +1,12 @@ +#include + +/* This is a comment. */ +int main(int argc, char *argv[]) +{ + int distance = 100; + + // this is also a comment + printf("You are %d miles away.\n", distance); + + return 0; +} From 997b3784c74dcac3913bc1a38cd65cfa4abfd155 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 5 Sep 2011 08:14:12 -0400 Subject: [PATCH 008/145] working version of ex6.c --- .gitignore | 1 + ex6.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 ex6.c diff --git a/.gitignore b/.gitignore index aaabdc6..530a0f4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ ex1 ex3 ex4 ex5 +ex6 diff --git a/ex6.c b/ex6.c new file mode 100644 index 0000000..4f4bca7 --- /dev/null +++ b/ex6.c @@ -0,0 +1,22 @@ +#include + +int main(int argc, char *argv[]) +{ + int distance = 100; + float power = 2.345f; + double super_power = 56789.4532f; + char initial = 'A'; + char first_name[] = "Zed"; + char last_name[] = "Shaw"; + + printf("You are %d miles away.\n", distance); + printf("You have %f levels of power.\n", power); + printf("You have %f awesome super powers.\n", super_power); + printf("I have an initial %c.\n", initial); + printf("I have a first name %s.\n", first_name); + printf("I have a last name %s.\n", last_name); + printf("My whole name is %s %c. %s.\n", + first_name, initial, last_name); + + return 0; +} From 5e41db6c1362334e25741852480806722add0c6e Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 5 Sep 2011 08:20:20 -0400 Subject: [PATCH 009/145] adding exercise 6 to makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 74a0619..a1a4945 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 ex5 +EXERCISES = ex1 ex3 ex4 ex5 ex6 all: $(EXERCISES) From 67d44d78dd447daa25f32807d5814d8fb57ce5d5 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 5 Sep 2011 09:10:19 -0400 Subject: [PATCH 010/145] doing 7.3 extra credit --- ex6.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ex6.c b/ex6.c index 4f4bca7..118d615 100644 --- a/ex6.c +++ b/ex6.c @@ -2,16 +2,16 @@ int main(int argc, char *argv[]) { - int distance = 100; - float power = 2.345f; + int distance = 0xaf + 0747; + float power = 2.345f + 'Z' + 'A' + 'P'; double super_power = 56789.4532f; char initial = 'A'; char first_name[] = "Zed"; - char last_name[] = "Shaw"; + char last_name[] = {'S', 'h', 'a', 'w', '\0'}; - printf("You are %d miles away.\n", distance); - printf("You have %f levels of power.\n", power); - printf("You have %f awesome super powers.\n", super_power); + printf("You are %08d miles away.\n", distance); + printf("You have %.2f levels of power.\n", power); + printf("You have %.3f awesome super powers.\n", super_power); printf("I have an initial %c.\n", initial); printf("I have a first name %s.\n", first_name); printf("I have a last name %s.\n", last_name); From cd54bb1c46f06391bdb833fd3e54517ffd48ef6f Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 5 Sep 2011 09:17:01 -0400 Subject: [PATCH 011/145] adding a README to appease the octocat --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c394c3b --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +Zed asked for folks to work through +Learn C The Hard Way and provide feedback, so that's what I'm doing. From 5328793953201282d4e0258b8cfd819e28fd2a17 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 5 Sep 2011 20:50:39 -0400 Subject: [PATCH 012/145] first draft of ex7.c --- .gitignore | 1 + Makefile | 2 +- ex7.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 ex7.c diff --git a/.gitignore b/.gitignore index 530a0f4..c6be593 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ ex3 ex4 ex5 ex6 +ex7 diff --git a/Makefile b/Makefile index a1a4945..f910ecc 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 ex5 ex6 +EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 all: $(EXERCISES) diff --git a/ex7.c b/ex7.c new file mode 100644 index 0000000..6f3ef30 --- /dev/null +++ b/ex7.c @@ -0,0 +1,30 @@ +#include + +int main(int argc, char *argv[]) +{ + int bugs = 100; + double bug_rate = 1.2; + + printf("You have %d bugs imaginary rate of %f.\n", + bugs, bug_rate); + + long universe_of_defects = 1 * 1024 * 1024 * 1024; + printf("The entire universe has %ld bugs.\n", + universe_of_defects); + + double expected_bugs = bugs * bug_rate; + printf("You are expected to have %f bugs.\n", + expected_bugs); + + double part_of_universe = expected_bugs / universe_of_defects; + printf("That is only a %e portion of the universe.\n", + part_of_universe); + + + char nul_byte = '\0'; + int care_percentage = bugs * nul_byte; + printf("Which means you should care %d%%.\n", + care_percentage); + + return 0; +} From 3b34c6ce0def0cf5022f2f0085c9b389f4533e38 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 5 Sep 2011 21:03:40 -0400 Subject: [PATCH 013/145] breaking stuff and futzing with null --- ex7.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ex7.c b/ex7.c index 6f3ef30..c27caba 100644 --- a/ex7.c +++ b/ex7.c @@ -26,5 +26,11 @@ int main(int argc, char *argv[]) printf("Which means you should care %d%%.\n", care_percentage); + puts("also..."); + int nul = (int)nul_byte; + int *nul_ptr = &nul; + printf("char '\\0' = '%c', (int)'\\0' = '%d', &(int)'\\0' = '%n'.\n", + nul_byte, nul, nul_ptr); + return 0; } From 3a7ae25fa35359cd112fba0be3fe61e3ab1fd527 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 15:57:49 -0400 Subject: [PATCH 014/145] messing around with the size of "universe_of_defects" --- ex7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex7.c b/ex7.c index c27caba..074acc6 100644 --- a/ex7.c +++ b/ex7.c @@ -8,7 +8,7 @@ int main(int argc, char *argv[]) printf("You have %d bugs imaginary rate of %f.\n", bugs, bug_rate); - long universe_of_defects = 1 * 1024 * 1024 * 1024; + unsigned long universe_of_defects = 63.99999999999 * 32 * 1024 * 1024; printf("The entire universe has %ld bugs.\n", universe_of_defects); From 593c551085ec04bf1317268b90774308b616a14a Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 16:10:21 -0400 Subject: [PATCH 015/145] first version of ex8.c --- .gitignore | 1 + Makefile | 2 +- ex8.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 ex8.c diff --git a/.gitignore b/.gitignore index c6be593..f37cd25 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ ex4 ex5 ex6 ex7 +ex8 diff --git a/Makefile b/Makefile index f910ecc..fe4ee5d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 +EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 all: $(EXERCISES) diff --git a/ex8.c b/ex8.c new file mode 100644 index 0000000..07891c9 --- /dev/null +++ b/ex8.c @@ -0,0 +1,36 @@ +#include + +int main(int argc, char *argv[]) +{ + int areas[] = {10, 12, 13, 14, 20}; + char name[] = "Zed"; + char full_name[] = { + 'Z', 'e', 'd', + ' ', 'A', '.', ' ', + 'S', 'h', 'a', 'w', '\0' + }; + + printf("The size of an int: %d\n", sizeof(int)); + printf("The size of areas (int[]): %d\n", + sizeof(areas)); + printf("The number of ints in areas: %d\n", + sizeof(areas) / sizeof(int)); + printf("The first area is %d, then 2nd %d.\n", + areas[0], areas[1]); + + printf("The size of char: %d\n", sizeof(char)); + printf("The size of name (char[]): %d\n", + sizeof(name)); + printf("The number of chars: %d\n", + sizeof(name) / sizeof(char)); + + printf("The size of full_name (char[]): %d\n", + sizeof(full_name)); + printf("The number of chars: %d\n", + sizeof(full_name) / sizeof(char)); + + printf("name=\"%s\" and full_name=\"%s\"\n", + name, full_name); + + return 0; +} From cfd8e8cca0fab655f3015d1a4160e8a1020496fe Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 22:28:01 -0400 Subject: [PATCH 016/145] more in how to break it for chapter 9 --- ex8.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ex8.c b/ex8.c index 07891c9..f2f1b34 100644 --- a/ex8.c +++ b/ex8.c @@ -32,5 +32,8 @@ int main(int argc, char *argv[]) printf("name=\"%s\" and full_name=\"%s\"\n", name, full_name); + printf("name[0] is %c.\n", name[0]); + printf("full_name[7] is %c.\n", full_name[7]); + return 0; } From 7998233c9b403d9f922a25fce1d61c5fdab0bc5a Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 22:33:37 -0400 Subject: [PATCH 017/145] extra credit for ch. 9 --- ex8.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ex8.c b/ex8.c index f2f1b34..e89e124 100644 --- a/ex8.c +++ b/ex8.c @@ -17,6 +17,10 @@ int main(int argc, char *argv[]) sizeof(areas) / sizeof(int)); printf("The first area is %d, then 2nd %d.\n", areas[0], areas[1]); + areas[0] = 100; + areas[2] = areas[1]; + printf("Now the first area is %d and the 3rd area is %d.\n", + areas[0], areas[2]); printf("The size of char: %d\n", sizeof(char)); printf("The size of name (char[]): %d\n", @@ -35,5 +39,18 @@ int main(int argc, char *argv[]) printf("name[0] is %c.\n", name[0]); printf("full_name[7] is %c.\n", full_name[7]); + name[0] = 'X'; + printf("Now name[0] is %c.\n", name[0]); + + full_name[7] = 'T'; + printf("Now full_name[7] is %c.\n", full_name[7]); + + printf("name=\"%s\" and full_name=\"%s\"\n", + name, full_name); + + areas[2] = name[0]; + printf("First area is now name[0]: %%c=%c, %%d=%d.\n", + areas[2], areas[2]); + return 0; } From 34505c7200a79d5b09beb3c87429d713837d89d5 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 22:41:34 -0400 Subject: [PATCH 018/145] working version of exercise 9 --- .gitignore | 1 + Makefile | 2 +- ex9.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 ex9.c diff --git a/.gitignore b/.gitignore index f37cd25..f65443b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ ex5 ex6 ex7 ex8 +ex9 diff --git a/Makefile b/Makefile index fe4ee5d..6edda90 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 +EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 ex9 all: $(EXERCISES) diff --git a/ex9.c b/ex9.c new file mode 100644 index 0000000..e7feec9 --- /dev/null +++ b/ex9.c @@ -0,0 +1,39 @@ +#include + +int main(int argc, char *argv[]) +{ + int numbers[4] = {0}; + char name[4] = {'a'}; + + printf("numbers: %d %d %d %d\n", + numbers[0], numbers[1], + numbers[2], numbers[3]); + + printf("name each: %c %c %c %c\n", + name[0], name[1], + name[2], name[3]); + + printf("name: %s\n", name); + + numbers[0] = 1; + numbers[1] = 2; + numbers[2] = 3; + numbers[3] = 4; + + name[0] = 'Z'; + name[1] = 'e'; + name[2] = 'd'; + name[3] = '\0'; + + printf("numbers: %d %d %d %d\n", + numbers[0], numbers[1], + numbers[2], numbers[3]); + + printf("name each: %c %c %c %c\n", + name[0], name[1], + name[2], name[3]); + + printf("name: %s\n", name); + + return 0; +} From 458ed013bcf70eb70b89439ac30e0b74a4ca9d2c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 22:42:39 -0400 Subject: [PATCH 019/145] breaking it by not initializing the name --- ex9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex9.c b/ex9.c index e7feec9..190cfbe 100644 --- a/ex9.c +++ b/ex9.c @@ -3,7 +3,7 @@ int main(int argc, char *argv[]) { int numbers[4] = {0}; - char name[4] = {'a'}; + char name[4]; printf("numbers: %d %d %d %d\n", numbers[0], numbers[1], From c23968939a3566cdf1f36cf2add7f3b10f5a72fb Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 22:45:09 -0400 Subject: [PATCH 020/145] better again --- ex9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex9.c b/ex9.c index 190cfbe..e7feec9 100644 --- a/ex9.c +++ b/ex9.c @@ -3,7 +3,7 @@ int main(int argc, char *argv[]) { int numbers[4] = {0}; - char name[4]; + char name[4] = {'a'}; printf("numbers: %d %d %d %d\n", numbers[0], numbers[1], From 3be4117ef12ee0433e02841668a0963e61c18a47 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 22:47:27 -0400 Subject: [PATCH 021/145] assigning chars to numbers array --- ex9.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ex9.c b/ex9.c index e7feec9..5893e36 100644 --- a/ex9.c +++ b/ex9.c @@ -15,10 +15,15 @@ int main(int argc, char *argv[]) printf("name: %s\n", name); - numbers[0] = 1; - numbers[1] = 2; - numbers[2] = 3; - numbers[3] = 4; + numbers[0] = 'Z'; + numbers[1] = 'e'; + numbers[2] = 'd'; + numbers[3] = '\0'; + + printf("%c\n", numbers[0]); + printf("%c\n", numbers[1]); + printf("%c\n", numbers[2]); + printf("%c\n", numbers[3]); name[0] = 'Z'; name[1] = 'e'; From da1b3f85089c82559d33fdcd8e4fa503a1ed3a8e Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 8 Sep 2011 22:52:39 -0400 Subject: [PATCH 022/145] more int/char playing around, casting name as int --- ex9.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ex9.c b/ex9.c index 5893e36..02edc6e 100644 --- a/ex9.c +++ b/ex9.c @@ -15,21 +15,23 @@ int main(int argc, char *argv[]) printf("name: %s\n", name); - numbers[0] = 'Z'; - numbers[1] = 'e'; - numbers[2] = 'd'; - numbers[3] = '\0'; - - printf("%c\n", numbers[0]); - printf("%c\n", numbers[1]); - printf("%c\n", numbers[2]); - printf("%c\n", numbers[3]); + numbers[0] = 1; + numbers[1] = 2; + numbers[2] = 3; + numbers[3] = 4; name[0] = 'Z'; name[1] = 'e'; name[2] = 'd'; name[3] = '\0'; + printf("%d\n", name[0]); + printf("%d\n", name[1]); + printf("%d\n", name[2]); + printf("%d\n", name[3]); + + printf("name as int=%d\n", (int)name); + printf("numbers: %d %d %d %d\n", numbers[0], numbers[1], numbers[2], numbers[3]); From 5a86af46b08cc1eb22537ae8696de0b66dc68867 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 09:17:53 -0400 Subject: [PATCH 023/145] breaking ex10 --- .gitignore | 1 + Makefile | 2 +- break-ex10.py | 10 ++++++++++ ex10.c | 22 ++++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 break-ex10.py create mode 100644 ex10.c diff --git a/.gitignore b/.gitignore index f65443b..54570d1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ ex6 ex7 ex8 ex9 +ex10 diff --git a/Makefile b/Makefile index 6edda90..4c0c244 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 ex9 +EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 all: $(EXERCISES) diff --git a/break-ex10.py b/break-ex10.py new file mode 100644 index 0000000..bdba748 --- /dev/null +++ b/break-ex10.py @@ -0,0 +1,10 @@ +from __future__ import print_function + +import os +import sys + +argc = int(sys.argv[1]) if sys.argv[1:] else 23694 +command = "valgrind ./ex10 " + " ".join(map(str, range(argc))) +print("command = {}".format(command)) + +os.system(command) diff --git a/ex10.c b/ex10.c new file mode 100644 index 0000000..c06d77b --- /dev/null +++ b/ex10.c @@ -0,0 +1,22 @@ +#include + +int main(int argc, char *argv[]) +{ + int i = 0; + + for(i = 0; i < argc; i++) { + printf("arg %d: %s\n", i, argv[i]); + } + + char *states[] = { + "California", "Oregon", + "Washington", "Texas" + }; + int num_states = 4; + + for(i = 0; i < num_states; i++) { + printf("state %d: %s\n", i, states[i]); + } + + return 0; +} From 41e45ff12ab0ba0d1d5a7de647b71b504d8774db Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:24:47 -0400 Subject: [PATCH 024/145] putting evil into my for-loop --- ex10.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ex10.c b/ex10.c index c06d77b..75b34fe 100644 --- a/ex10.c +++ b/ex10.c @@ -4,9 +4,7 @@ int main(int argc, char *argv[]) { int i = 0; - for(i = 0; i < argc; i++) { - printf("arg %d: %s\n", i, argv[i]); - } + for(i = 0; i < argc && printf("arg %d: %s\n", i, argv[i]); i++); char *states[] = { "California", "Oregon", From 8f7bd1099c2002896f5066713d134b690b518bd3 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:25:01 -0400 Subject: [PATCH 025/145] extracting evil --- ex10.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ex10.c b/ex10.c index 75b34fe..c06d77b 100644 --- a/ex10.c +++ b/ex10.c @@ -4,7 +4,9 @@ int main(int argc, char *argv[]) { int i = 0; - for(i = 0; i < argc && printf("arg %d: %s\n", i, argv[i]); i++); + for(i = 0; i < argc; i++) { + printf("arg %d: %s\n", i, argv[i]); + } char *states[] = { "California", "Oregon", From e580f39207457aeca6e6bece4d6ba8be9110eb16 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:26:54 -0400 Subject: [PATCH 026/145] assigning within TEST of for-loop --- ex10.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ex10.c b/ex10.c index c06d77b..7cf8284 100644 --- a/ex10.c +++ b/ex10.c @@ -3,9 +3,10 @@ int main(int argc, char *argv[]) { int i = 0; + char *arg; - for(i = 0; i < argc; i++) { - printf("arg %d: %s\n", i, argv[i]); + for(i = 0; i < argc && (arg = argv[i]); i++) { + printf("arg %d: %s\n", i, arg); } char *states[] = { From 7fbe80ce254c32d7595822a4f5209e07495efb3a Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:31:50 -0400 Subject: [PATCH 027/145] making a mess in my for-loops --- ex10.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ex10.c b/ex10.c index 7cf8284..b1ea6a6 100644 --- a/ex10.c +++ b/ex10.c @@ -3,9 +3,9 @@ int main(int argc, char *argv[]) { int i = 0; - char *arg; + char *arg = ""; - for(i = 0; i < argc && (arg = argv[i]); i++) { + for(i = 0, arg = ""; i < argc && (arg = argv[i++]);) { printf("arg %d: %s\n", i, arg); } @@ -15,8 +15,8 @@ int main(int argc, char *argv[]) }; int num_states = 4; - for(i = 0; i < num_states; i++) { - printf("state %d: %s\n", i, states[i]); + for(i = 0, arg = ""; i < num_states && (arg = states[i++]);) { + printf("state %d: %s\n", i, arg); } return 0; From 16785fe9f2eb6c3dc771513bbc66001e63d9c233 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:32:33 -0400 Subject: [PATCH 028/145] cleaning up for-loops again --- ex10.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ex10.c b/ex10.c index b1ea6a6..c06d77b 100644 --- a/ex10.c +++ b/ex10.c @@ -3,10 +3,9 @@ int main(int argc, char *argv[]) { int i = 0; - char *arg = ""; - for(i = 0, arg = ""; i < argc && (arg = argv[i++]);) { - printf("arg %d: %s\n", i, arg); + for(i = 0; i < argc; i++) { + printf("arg %d: %s\n", i, argv[i]); } char *states[] = { @@ -15,8 +14,8 @@ int main(int argc, char *argv[]) }; int num_states = 4; - for(i = 0, arg = ""; i < num_states && (arg = states[i++]);) { - printf("state %d: %s\n", i, arg); + for(i = 0; i < num_states; i++) { + printf("state %d: %s\n", i, states[i]); } return 0; From 5b7748c99a81be851388f01f19a7c2110ccbebd1 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:34:26 -0400 Subject: [PATCH 029/145] using NULL sentinel instead of num_states --- ex10.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ex10.c b/ex10.c index c06d77b..d0aed12 100644 --- a/ex10.c +++ b/ex10.c @@ -10,12 +10,13 @@ int main(int argc, char *argv[]) char *states[] = { "California", "Oregon", - "Washington", "Texas" + "Washington", "Texas", + NULL }; - int num_states = 4; + char *state = ""; - for(i = 0; i < num_states; i++) { - printf("state %d: %s\n", i, states[i]); + for(i = 0; NULL != (state = states[i]); i++) { + printf("state %d: %s\n", i, state); } return 0; From 2830ca4774b10e73b6cb39af708d357ee2f9e889 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:34:40 -0400 Subject: [PATCH 030/145] using num_states again --- ex10.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ex10.c b/ex10.c index d0aed12..c06d77b 100644 --- a/ex10.c +++ b/ex10.c @@ -10,13 +10,12 @@ int main(int argc, char *argv[]) char *states[] = { "California", "Oregon", - "Washington", "Texas", - NULL + "Washington", "Texas" }; - char *state = ""; + int num_states = 4; - for(i = 0; NULL != (state = states[i]); i++) { - printf("state %d: %s\n", i, state); + for(i = 0; i < num_states; i++) { + printf("state %d: %s\n", i, states[i]); } return 0; From 947ce043195d27977e780cc7d83759396ff99657 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:36:58 -0400 Subject: [PATCH 031/145] assigning back and forth between char arrays --- ex10.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/ex10.c b/ex10.c index c06d77b..81e427a 100644 --- a/ex10.c +++ b/ex10.c @@ -3,17 +3,31 @@ int main(int argc, char *argv[]) { int i = 0; - - for(i = 0; i < argc; i++) { - printf("arg %d: %s\n", i, argv[i]); - } - char *states[] = { "California", "Oregon", "Washington", "Texas" }; int num_states = 4; + char *tmp = states[0]; + states[0] = argv[0]; + argv[0] = tmp; + + for(i = 0; i < argc; i++) { + printf("arg %d: %s\n", i, argv[i]); + } + + for(i = 0; i < num_states; i++) { + printf("state %d: %s\n", i, states[i]); + } + + argv[0] = states[0]; + states[0] = tmp; + + for(i = 0; i < argc; i++) { + printf("arg %d: %s\n", i, argv[i]); + } + for(i = 0; i < num_states; i++) { printf("state %d: %s\n", i, states[i]); } From 45ca45c9e1f9cdbe25defa7d93f22027df9db7d7 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 9 Sep 2011 14:37:10 -0400 Subject: [PATCH 032/145] back to initial state --- ex10.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/ex10.c b/ex10.c index 81e427a..c06d77b 100644 --- a/ex10.c +++ b/ex10.c @@ -3,31 +3,17 @@ int main(int argc, char *argv[]) { int i = 0; + + for(i = 0; i < argc; i++) { + printf("arg %d: %s\n", i, argv[i]); + } + char *states[] = { "California", "Oregon", "Washington", "Texas" }; int num_states = 4; - char *tmp = states[0]; - states[0] = argv[0]; - argv[0] = tmp; - - for(i = 0; i < argc; i++) { - printf("arg %d: %s\n", i, argv[i]); - } - - for(i = 0; i < num_states; i++) { - printf("state %d: %s\n", i, states[i]); - } - - argv[0] = states[0]; - states[0] = tmp; - - for(i = 0; i < argc; i++) { - printf("arg %d: %s\n", i, argv[i]); - } - for(i = 0; i < num_states; i++) { printf("state %d: %s\n", i, states[i]); } From 6c210c9b40c44fceb2949ab4caaa6b21d8cf2b5f Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 00:22:25 -0400 Subject: [PATCH 033/145] working version of ex11.c --- .gitignore | 1 + Makefile | 2 +- ex11.c | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 ex11.c diff --git a/.gitignore b/.gitignore index 54570d1..24128c8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ ex7 ex8 ex9 ex10 +ex11 diff --git a/Makefile b/Makefile index 4c0c244..83959bb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 +EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex11 all: $(EXERCISES) diff --git a/ex11.c b/ex11.c new file mode 100644 index 0000000..19fb531 --- /dev/null +++ b/ex11.c @@ -0,0 +1,24 @@ +#include + +int main(int argc, char *argv[]) +{ + int i = 0; + while(i < argc) { + printf("arg %d: %s\n", i, argv[i]); + i++; + } + + char *states[] = { + "California", "Oregon", + "Washington", "Texas" + }; + + int num_states = 4; + i = 0; + while(i < num_states) { + printf("state %d: %s\n", i, states[i]); + i++; + } + + return 0; +} From 1d4044d5861755b5e78e64761799e30ebb4386b5 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 00:26:24 -0400 Subject: [PATCH 034/145] counting backwards instead --- ex11.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ex11.c b/ex11.c index 19fb531..24273b5 100644 --- a/ex11.c +++ b/ex11.c @@ -2,10 +2,12 @@ int main(int argc, char *argv[]) { - int i = 0; - while(i < argc) { - printf("arg %d: %s\n", i, argv[i]); - i++; + int i = argc; + int arg; + while(i > 0) { + arg = argc - i; + printf("arg %d: %s\n", arg, argv[arg]); + i--; } char *states[] = { From 933a9a04fc49ffa5cdf4db0a9f4f12ca4211c4c8 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 00:27:04 -0400 Subject: [PATCH 035/145] back to a more normal while-loop --- ex11.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ex11.c b/ex11.c index 24273b5..19fb531 100644 --- a/ex11.c +++ b/ex11.c @@ -2,12 +2,10 @@ int main(int argc, char *argv[]) { - int i = argc; - int arg; - while(i > 0) { - arg = argc - i; - printf("arg %d: %s\n", arg, argv[arg]); - i--; + int i = 0; + while(i < argc) { + printf("arg %d: %s\n", i, argv[i]); + i++; } char *states[] = { From 1a1c89af7aa7ffe6fa6de724a977f6472355757e Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 00:29:54 -0400 Subject: [PATCH 036/145] "copying" strings into other array --- ex11.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ex11.c b/ex11.c index 19fb531..7ff7988 100644 --- a/ex11.c +++ b/ex11.c @@ -20,5 +20,12 @@ int main(int argc, char *argv[]) i++; } + i = 0; + while(i < num_states) { + states[i] = argv[i]; + printf("copied %s into state %d\n", states[i], i); + i++; + } + return 0; } From c5e4c2cf263fcf5c71703fba73d2b076cbfe3847 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 00:33:38 -0400 Subject: [PATCH 037/145] using strcpy instead of just copying pointers --- ex11.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ex11.c b/ex11.c index 7ff7988..4467f3a 100644 --- a/ex11.c +++ b/ex11.c @@ -1,4 +1,5 @@ #include +#include int main(int argc, char *argv[]) { @@ -22,8 +23,8 @@ int main(int argc, char *argv[]) i = 0; while(i < num_states) { - states[i] = argv[i]; - printf("copied %s into state %d\n", states[i], i); + strcpy((char *)(&states[i]), argv[i]); + printf("copied %s into state %d\n", argv[i], i); i++; } From de57b63f465d97c1dd3105cbfe8b58ec3a543a20 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 00:33:57 -0400 Subject: [PATCH 038/145] just doing pointer copy again --- ex11.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ex11.c b/ex11.c index 4467f3a..7ff7988 100644 --- a/ex11.c +++ b/ex11.c @@ -1,5 +1,4 @@ #include -#include int main(int argc, char *argv[]) { @@ -23,8 +22,8 @@ int main(int argc, char *argv[]) i = 0; while(i < num_states) { - strcpy((char *)(&states[i]), argv[i]); - printf("copied %s into state %d\n", argv[i], i); + states[i] = argv[i]; + printf("copied %s into state %d\n", states[i], i); i++; } From 7cb0c4aab58d94bde8f84284eca3ba1760103ddd Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 01:06:06 -0400 Subject: [PATCH 039/145] using strlen and strncpy to make copies of strings instead of just copying pointers, although the need for (char *) makes me think I don't have the right idea --- ex11.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ex11.c b/ex11.c index 7ff7988..eb4155d 100644 --- a/ex11.c +++ b/ex11.c @@ -1,4 +1,5 @@ #include +#include int main(int argc, char *argv[]) { @@ -21,11 +22,20 @@ int main(int argc, char *argv[]) } i = 0; + size_t l; + while(i < num_states) { - states[i] = argv[i]; + l = strlen((char *)&(argv[i])); + strncpy((char *)&(states[i]), (char *)&(argv[i]), l); printf("copied %s into state %d\n", states[i], i); i++; } + i = 0; + while(i < num_states) { + printf("state %d: %s\n", i, states[i]); + i++; + } + return 0; } From 84ee0d0ecb9f8b89b1f11a3ee4bb1a69daa81db3 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 02:09:53 -0300 Subject: [PATCH 040/145] fixed inconsistent python compatibility guarding :P --- break-ex10.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/break-ex10.py b/break-ex10.py index bdba748..2f2b2ea 100644 --- a/break-ex10.py +++ b/break-ex10.py @@ -5,6 +5,6 @@ import sys argc = int(sys.argv[1]) if sys.argv[1:] else 23694 command = "valgrind ./ex10 " + " ".join(map(str, range(argc))) -print("command = {}".format(command)) +print("command = {0}".format(command)) os.system(command) From 5f06f804b19a68abbbad51e3e3630df16bfe64de Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 01:15:38 -0400 Subject: [PATCH 041/145] cleaning up gitignore and Makefile so that they don't have to be updated every time a new .c file is added --- .gitignore | 16 ++++++---------- Makefile | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 24128c8..10d5414 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,6 @@ -ex1 -ex3 -ex4 -ex5 -ex6 -ex7 -ex8 -ex9 -ex10 -ex11 +* + +!*.c +!Makefile +!README.md +!*.py diff --git a/Makefile b/Makefile index 83959bb..bf1e2c6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -g -EXERCISES = ex1 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex11 +EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c)) all: $(EXERCISES) From 2a59add795d52fabd27eba78bfff3bec2dd63477 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 10 Sep 2011 11:54:21 -0400 Subject: [PATCH 042/145] first version of ex12 --- ex12.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 ex12.c diff --git a/ex12.c b/ex12.c new file mode 100644 index 0000000..91e7b3e --- /dev/null +++ b/ex12.c @@ -0,0 +1,20 @@ +#include + +int main(int argc, char *argv[]) +{ + int i = 0; + + if(argc == 1) { + printf("You only have one argument. You suck.\n"); + } else if(argc > 1 && argc < 4) { + printf("Here's your arguments:\n"); + + for (i = 0; i< argc; i++) { + printf("%s ", argv[i]); + } + printf("\n"); + } else { + printf("You have too many arguments. You suck.\n"); + } + return 0; +} From 049e7d4825a6ffbdfd2a80e97ab1e31023070fb9 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 21:43:47 -0400 Subject: [PATCH 043/145] first working version of ex13 --- ex13.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 ex13.c diff --git a/ex13.c b/ex13.c new file mode 100644 index 0000000..a3fad4e --- /dev/null +++ b/ex13.c @@ -0,0 +1,54 @@ +#include + +int main(int argc, char *argv[]) +{ + if(argc != 2) { + printf("ERROR: You need one argument.\n"); + return 1; + } + + int i = 0; + for(i = 0; argv[1][i] != '\0'; i++) { + char letter = argv[1][i]; + + switch(letter) { + case 'a': + case 'A': + printf("%d: 'A'\n", i); + break; + + case 'e': + case 'E': + printf("%d: 'E'\n", i); + break; + + case 'i': + case 'I': + printf("%d: 'I'\n", i); + break; + + case 'o': + case 'O': + printf("%d: 'O'\n", i); + break; + + case 'u': + case 'U': + printf("%d: 'U'\n", i); + break; + + case 'y': + case 'Y': + if (i > 2) { + printf("%d: 'Y'\n", i); + } + break; + + default: + printf("%d: %c is not a vowel\n", i, letter); + } + } + + return 0; +} + From 64879fb2adb90b30100f1cee0e1a3f85d0943dad Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 22:44:00 -0400 Subject: [PATCH 044/145] minor touchup, covering other case(s) for "y" --- ex13.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ex13.c b/ex13.c index a3fad4e..dd086fb 100644 --- a/ex13.c +++ b/ex13.c @@ -41,11 +41,13 @@ int main(int argc, char *argv[]) case 'Y': if (i > 2) { printf("%d: 'Y'\n", i); + } else { + printf("%d: 'Y' isn't a vowel this time\n", i); } break; default: - printf("%d: %c is not a vowel\n", i, letter); + printf("%d: '%c' is not a vowel\n", i, letter); } } From cbd2bc9cf511af11f5d6914ed256f658e2a41590 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 22:45:49 -0400 Subject: [PATCH 045/145] commenting out a break --- ex13.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex13.c b/ex13.c index dd086fb..c2bab05 100644 --- a/ex13.c +++ b/ex13.c @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) case 'u': case 'U': printf("%d: 'U'\n", i); - break; + //break; case 'y': case 'Y': From bfe47afbf23ffe4dca8f7228e13c6253468d8f30 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 22:45:59 -0400 Subject: [PATCH 046/145] fixing again --- ex13.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex13.c b/ex13.c index c2bab05..dd086fb 100644 --- a/ex13.c +++ b/ex13.c @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) case 'u': case 'U': printf("%d: 'U'\n", i); - //break; + break; case 'y': case 'Y': From 49383187bb8ffce5c43cc3ee785cdbfeec2d93cf Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 22:49:26 -0400 Subject: [PATCH 047/145] omitting default: --- ex13.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ex13.c b/ex13.c index dd086fb..b62b15c 100644 --- a/ex13.c +++ b/ex13.c @@ -46,8 +46,8 @@ int main(int argc, char *argv[]) } break; - default: - printf("%d: '%c' is not a vowel\n", i, letter); + //default: + // printf("%d: '%c' is not a vowel\n", i, letter); } } From 80c1c5d5f312cf04c70d5bd61c054dedef2a26d0 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 22:49:31 -0400 Subject: [PATCH 048/145] fixing again --- ex13.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ex13.c b/ex13.c index b62b15c..dd086fb 100644 --- a/ex13.c +++ b/ex13.c @@ -46,8 +46,8 @@ int main(int argc, char *argv[]) } break; - //default: - // printf("%d: '%c' is not a vowel\n", i, letter); + default: + printf("%d: '%c' is not a vowel\n", i, letter); } } From 4bbd9c87a59e5840287a0d05e76236bec4324dde Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 22:51:00 -0400 Subject: [PATCH 049/145] switching on non-ascii value --- ex13.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex13.c b/ex13.c index dd086fb..10c6789 100644 --- a/ex13.c +++ b/ex13.c @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) for(i = 0; argv[1][i] != '\0'; i++) { char letter = argv[1][i]; - switch(letter) { + switch(127 + (int)letter) { case 'a': case 'A': printf("%d: 'A'\n", i); From 0b7dbc78b428eb888e41626bd489aad5e94ddc79 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 22:51:08 -0400 Subject: [PATCH 050/145] fixing again --- ex13.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex13.c b/ex13.c index 10c6789..dd086fb 100644 --- a/ex13.c +++ b/ex13.c @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) for(i = 0; argv[1][i] != '\0'; i++) { char letter = argv[1][i]; - switch(127 + (int)letter) { + switch(letter) { case 'a': case 'A': printf("%d: 'A'\n", i); From d85c6d97eb4d89253b5177df46c301b159b94ee4 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 23:01:10 -0400 Subject: [PATCH 051/145] converting to lowercase and eliminating doubled-up case labels --- ex13.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/ex13.c b/ex13.c index dd086fb..8ec6454 100644 --- a/ex13.c +++ b/ex13.c @@ -8,37 +8,40 @@ int main(int argc, char *argv[]) } int i = 0; - for(i = 0; argv[1][i] != '\0'; i++) { + char letter; + int up_low_sep = (int)('a' - 'A'); + int upper_floor = (int)'A'; + int upper_ceil = (int)'Z'; + + for(i = 0; '\0' != (letter = argv[1][i]); i++) { char letter = argv[1][i]; + int i_letter = (int)letter; + if (upper_floor < i_letter && i_letter < upper_ceil) { + letter = (char)(i_letter + up_low_sep); + } switch(letter) { case 'a': - case 'A': - printf("%d: 'A'\n", i); + printf("%d: 'a'\n", i); break; case 'e': - case 'E': - printf("%d: 'E'\n", i); + printf("%d: 'e'\n", i); break; case 'i': - case 'I': - printf("%d: 'I'\n", i); + printf("%d: 'i'\n", i); break; case 'o': - case 'O': - printf("%d: 'O'\n", i); + printf("%d: 'o'\n", i); break; case 'u': - case 'U': - printf("%d: 'U'\n", i); + printf("%d: 'u'\n", i); break; case 'y': - case 'Y': if (i > 2) { printf("%d: 'Y'\n", i); } else { From 4c87139ab0ec0d6f6412d7e4bff59517163cd134 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 23:05:09 -0400 Subject: [PATCH 052/145] handling all args passed --- ex13.c | 71 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/ex13.c b/ex13.c index 8ec6454..33356ad 100644 --- a/ex13.c +++ b/ex13.c @@ -2,55 +2,58 @@ int main(int argc, char *argv[]) { - if(argc != 2) { - printf("ERROR: You need one argument.\n"); + if (argc < 2) { + fprintf(stderr, "ERROR: You must provide at least one argument.\n"); return 1; } - int i = 0; + int i; + int argn; + char letter; int up_low_sep = (int)('a' - 'A'); int upper_floor = (int)'A'; int upper_ceil = (int)'Z'; - for(i = 0; '\0' != (letter = argv[1][i]); i++) { - char letter = argv[1][i]; - int i_letter = (int)letter; - if (upper_floor < i_letter && i_letter < upper_ceil) { - letter = (char)(i_letter + up_low_sep); - } + for(argn = 1; argn < argc; argn++) { + for(i = 0; '\0' != (letter = argv[argn][i]); i++) { + int i_letter = (int)letter; + if (upper_floor < i_letter && i_letter < upper_ceil) { + letter = (char)(i_letter + up_low_sep); + } - switch(letter) { - case 'a': - printf("%d: 'a'\n", i); - break; + switch(letter) { + case 'a': + printf("%d: 'a'\n", i); + break; - case 'e': - printf("%d: 'e'\n", i); - break; + case 'e': + printf("%d: 'e'\n", i); + break; - case 'i': - printf("%d: 'i'\n", i); - break; + case 'i': + printf("%d: 'i'\n", i); + break; - case 'o': - printf("%d: 'o'\n", i); - break; + case 'o': + printf("%d: 'o'\n", i); + break; - case 'u': - printf("%d: 'u'\n", i); - break; + case 'u': + printf("%d: 'u'\n", i); + break; - case 'y': - if (i > 2) { - printf("%d: 'Y'\n", i); - } else { - printf("%d: 'Y' isn't a vowel this time\n", i); - } - break; + case 'y': + if (i > 2) { + printf("%d: 'Y'\n", i); + } else { + printf("%d: 'Y' isn't a vowel this time\n", i); + } + break; - default: - printf("%d: '%c' is not a vowel\n", i, letter); + default: + printf("%d: '%c' is not a vowel\n", i, letter); + } } } From 9f7dd8283ff59d07f75ae94c120735b50df2e099 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 23:07:15 -0400 Subject: [PATCH 053/145] using if-statement instead of switch-statement --- ex13.c | 49 ++++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/ex13.c b/ex13.c index 33356ad..b6e2ddd 100644 --- a/ex13.c +++ b/ex13.c @@ -22,37 +22,24 @@ int main(int argc, char *argv[]) letter = (char)(i_letter + up_low_sep); } - switch(letter) { - case 'a': - printf("%d: 'a'\n", i); - break; - - case 'e': - printf("%d: 'e'\n", i); - break; - - case 'i': - printf("%d: 'i'\n", i); - break; - - case 'o': - printf("%d: 'o'\n", i); - break; - - case 'u': - printf("%d: 'u'\n", i); - break; - - case 'y': - if (i > 2) { - printf("%d: 'Y'\n", i); - } else { - printf("%d: 'Y' isn't a vowel this time\n", i); - } - break; - - default: - printf("%d: '%c' is not a vowel\n", i, letter); + if (letter == 'a') { + printf("%d: 'a'\n", i); + } else if (letter == 'e') { + printf("%d: 'e'\n", i); + } else if (letter == 'i') { + printf("%d: 'i'\n", i); + } else if (letter == 'o') { + printf("%d: 'o'\n", i); + } else if (letter == 'u') { + printf("%d: 'u'\n", i); + } else if (letter == 'y') { + if (i > 2) { + printf("%d: 'Y'\n", i); + } else { + printf("%d: 'Y' isn't a vowel this time\n", i); + } + } else { + printf("%d: '%c' is not a vowel\n", i, letter); } } } From d4c567fd4daff5680087ec5ffe8c00f6bb216501 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 13 Sep 2011 23:07:39 -0400 Subject: [PATCH 054/145] back to using switch --- ex13.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/ex13.c b/ex13.c index b6e2ddd..33356ad 100644 --- a/ex13.c +++ b/ex13.c @@ -22,24 +22,37 @@ int main(int argc, char *argv[]) letter = (char)(i_letter + up_low_sep); } - if (letter == 'a') { - printf("%d: 'a'\n", i); - } else if (letter == 'e') { - printf("%d: 'e'\n", i); - } else if (letter == 'i') { - printf("%d: 'i'\n", i); - } else if (letter == 'o') { - printf("%d: 'o'\n", i); - } else if (letter == 'u') { - printf("%d: 'u'\n", i); - } else if (letter == 'y') { - if (i > 2) { - printf("%d: 'Y'\n", i); - } else { - printf("%d: 'Y' isn't a vowel this time\n", i); - } - } else { - printf("%d: '%c' is not a vowel\n", i, letter); + switch(letter) { + case 'a': + printf("%d: 'a'\n", i); + break; + + case 'e': + printf("%d: 'e'\n", i); + break; + + case 'i': + printf("%d: 'i'\n", i); + break; + + case 'o': + printf("%d: 'o'\n", i); + break; + + case 'u': + printf("%d: 'u'\n", i); + break; + + case 'y': + if (i > 2) { + printf("%d: 'Y'\n", i); + } else { + printf("%d: 'Y' isn't a vowel this time\n", i); + } + break; + + default: + printf("%d: '%c' is not a vowel\n", i, letter); } } } From f380dab29598f5e9cd7deec04295f26bd81779af Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 18 Sep 2011 10:35:00 -0400 Subject: [PATCH 055/145] first working version of ex14 --- ex14.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 ex14.c diff --git a/ex14.c b/ex14.c new file mode 100644 index 0000000..d2b2826 --- /dev/null +++ b/ex14.c @@ -0,0 +1,40 @@ +#include +#include + +int can_print_it(char ch); +void print_letters(char arg[]); + +void print_arguments(int argc, char *argv[]) +{ + int i = 0; + + for(i = 0; i < argc; i++) { + print_letters(argv[i]); + } +} + +void print_letters(char arg[]) +{ + int i = 0; + + for (i = 0; arg[i] != '\0'; i++) { + char ch = arg[i]; + + if(can_print_it(ch)) { + printf("'%c' == %d ", ch, ch); + } + } + + printf("\n"); +} + +int can_print_it(char ch) +{ + return isalpha(ch) || isblank(ch); +} + +int main(int argc, char *argv[]) +{ + print_arguments(argc, argv); + return 0; +} From 20da5c59fdfbbeaf09a19d8a66f46bee43094a07 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 18 Sep 2011 10:37:53 -0400 Subject: [PATCH 056/145] removing "can_print_it" --- ex14.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ex14.c b/ex14.c index d2b2826..6eeacbe 100644 --- a/ex14.c +++ b/ex14.c @@ -1,7 +1,6 @@ #include #include -int can_print_it(char ch); void print_letters(char arg[]); void print_arguments(int argc, char *argv[]) @@ -20,7 +19,7 @@ void print_letters(char arg[]) for (i = 0; arg[i] != '\0'; i++) { char ch = arg[i]; - if(can_print_it(ch)) { + if(isalpha(ch) || isblank(ch)) { printf("'%c' == %d ", ch, ch); } } @@ -28,11 +27,6 @@ void print_letters(char arg[]) printf("\n"); } -int can_print_it(char ch) -{ - return isalpha(ch) || isblank(ch); -} - int main(int argc, char *argv[]) { print_arguments(argc, argv); From c9de7b1c13eed4c4750d12bd28c82e5b0a24d2ca Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 18 Sep 2011 10:40:21 -0400 Subject: [PATCH 057/145] using strlen instead of null terminator --- ex14.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ex14.c b/ex14.c index 6eeacbe..403769b 100644 --- a/ex14.c +++ b/ex14.c @@ -1,22 +1,23 @@ #include #include +#include -void print_letters(char arg[]); +void print_letters(char arg[], int nchars); void print_arguments(int argc, char *argv[]) { int i = 0; for(i = 0; i < argc; i++) { - print_letters(argv[i]); + print_letters(argv[i], strlen(argv[i])); } } -void print_letters(char arg[]) +void print_letters(char arg[], int nchars) { int i = 0; - for (i = 0; arg[i] != '\0'; i++) { + for (i = 0; i < nchars; i++) { char ch = arg[i]; if(isalpha(ch) || isblank(ch)) { From f7f7f29a593da9496b993b3efa5c84dd86e54dd8 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 18 Sep 2011 10:41:35 -0400 Subject: [PATCH 058/145] printing alnum and not just alpha --- ex14.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex14.c b/ex14.c index 403769b..23292e1 100644 --- a/ex14.c +++ b/ex14.c @@ -20,7 +20,7 @@ void print_letters(char arg[], int nchars) for (i = 0; i < nchars; i++) { char ch = arg[i]; - if(isalpha(ch) || isblank(ch)) { + if(isalnum(ch) || isblank(ch)) { printf("'%c' == %d ", ch, ch); } } From 1e1ffb3f9d1afa6dee0f4c0aca5953f56d130676 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 18 Sep 2011 10:41:52 -0400 Subject: [PATCH 059/145] back to printing alpha and blanks --- ex14.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex14.c b/ex14.c index 23292e1..403769b 100644 --- a/ex14.c +++ b/ex14.c @@ -20,7 +20,7 @@ void print_letters(char arg[], int nchars) for (i = 0; i < nchars; i++) { char ch = arg[i]; - if(isalnum(ch) || isblank(ch)) { + if(isalpha(ch) || isblank(ch)) { printf("'%c' == %d ", ch, ch); } } From 9158c349b31acfaa4b5a399215a65ba3715d8e89 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 18 Sep 2011 13:30:03 -0400 Subject: [PATCH 060/145] first version of exercise 15 --- ex15.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 ex15.c diff --git a/ex15.c b/ex15.c new file mode 100644 index 0000000..c890f92 --- /dev/null +++ b/ex15.c @@ -0,0 +1,47 @@ +#include + +int main(int argc, char *argv[]) +{ + int ages[] = {23, 43, 12, 89, 2}; + char *names[] = { + "Alan", "Frank", + "Mary", "John", "Lisa" + }; + + int count = sizeof(ages) / sizeof(int); + int i = 0; + + for(i = 0; i < count; i++) { + printf("%s has %d years alive.\n", + names[i], ages[i]); + } + + printf("---\n"); + + int *cur_age = ages; + char **cur_name = names; + + for(i = 0; i < count; i++) { + printf("%s is %d years old.\n", + *(cur_name+i), *(cur_age+i)); + } + + printf("---\n"); + + for(i = 0; i < count; i++) { + printf("%s is %d years old again.\n", + cur_name[i], cur_age[i]); + } + + printf("---\n"); + + for(cur_name = names, cur_age = ages; + (cur_age - ages) < count; + cur_name++, cur_age++) + { + printf("%s lived %d years so far.\n", + *cur_name, *cur_age); + } + + return 0; +} From 8c6e140dad5eb3e97832db89515e0758ffa9e4f4 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 18 Sep 2011 13:34:09 -0400 Subject: [PATCH 061/145] adding in comments so that line numbers match up (which I should have been doing all along) --- ex15.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ex15.c b/ex15.c index c890f92..1853556 100644 --- a/ex15.c +++ b/ex15.c @@ -2,15 +2,17 @@ int main(int argc, char *argv[]) { + // create two arrays we care about int ages[] = {23, 43, 12, 89, 2}; char *names[] = { "Alan", "Frank", "Mary", "John", "Lisa" }; - + // safely get the size of ages int count = sizeof(ages) / sizeof(int); int i = 0; + // first way using indexing for(i = 0; i < count; i++) { printf("%s has %d years alive.\n", names[i], ages[i]); @@ -18,9 +20,11 @@ int main(int argc, char *argv[]) printf("---\n"); + // setup the pointers to the start of the arrays int *cur_age = ages; char **cur_name = names; + // second way using pointers for(i = 0; i < count; i++) { printf("%s is %d years old.\n", *(cur_name+i), *(cur_age+i)); @@ -28,6 +32,7 @@ int main(int argc, char *argv[]) printf("---\n"); + // third way, pointers are just arrays for(i = 0; i < count; i++) { printf("%s is %d years old again.\n", cur_name[i], cur_age[i]); @@ -35,6 +40,7 @@ int main(int argc, char *argv[]) printf("---\n"); + // fourth way with pointers in a stupid complex way for(cur_name = names, cur_age = ages; (cur_age - ages) < count; cur_name++, cur_age++) From bdeaaf48f5d0c4abb9b93019a9404824ec8e8064 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 13:19:12 -0400 Subject: [PATCH 062/145] breaking by pointing at wrong array --- ex15.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex15.c b/ex15.c index 1853556..d8cb037 100644 --- a/ex15.c +++ b/ex15.c @@ -21,7 +21,7 @@ int main(int argc, char *argv[]) printf("---\n"); // setup the pointers to the start of the arrays - int *cur_age = ages; + int *cur_age = (int*)names; char **cur_name = names; // second way using pointers From 22e3ed5406c00ce9111281cb96aa54e90f85c210 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 13:19:28 -0400 Subject: [PATCH 063/145] back to working --- ex15.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex15.c b/ex15.c index d8cb037..1853556 100644 --- a/ex15.c +++ b/ex15.c @@ -21,7 +21,7 @@ int main(int argc, char *argv[]) printf("---\n"); // setup the pointers to the start of the arrays - int *cur_age = (int*)names; + int *cur_age = ages; char **cur_name = names; // second way using pointers From 1b7572c7869453754816db308902c68cff78a053 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 19:06:10 -0400 Subject: [PATCH 064/145] using only pointers instead of array indexing --- ex15.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ex15.c b/ex15.c index 1853556..3b4eb15 100644 --- a/ex15.c +++ b/ex15.c @@ -15,7 +15,7 @@ int main(int argc, char *argv[]) // first way using indexing for(i = 0; i < count; i++) { printf("%s has %d years alive.\n", - names[i], ages[i]); + *(names + i), *(ages + i)); } printf("---\n"); @@ -27,7 +27,7 @@ int main(int argc, char *argv[]) // second way using pointers for(i = 0; i < count; i++) { printf("%s is %d years old.\n", - *(cur_name+i), *(cur_age+i)); + *(cur_name + i), *(cur_age + i)); } printf("---\n"); @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) // third way, pointers are just arrays for(i = 0; i < count; i++) { printf("%s is %d years old again.\n", - cur_name[i], cur_age[i]); + *(cur_name + i), *(cur_age + i)); } printf("---\n"); From c1ab498db3f0a2a22b0d69c8232845f1792736f6 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 19:08:19 -0400 Subject: [PATCH 065/145] back to mixed pointers and arrays version --- ex15.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ex15.c b/ex15.c index 3b4eb15..1853556 100644 --- a/ex15.c +++ b/ex15.c @@ -15,7 +15,7 @@ int main(int argc, char *argv[]) // first way using indexing for(i = 0; i < count; i++) { printf("%s has %d years alive.\n", - *(names + i), *(ages + i)); + names[i], ages[i]); } printf("---\n"); @@ -27,7 +27,7 @@ int main(int argc, char *argv[]) // second way using pointers for(i = 0; i < count; i++) { printf("%s is %d years old.\n", - *(cur_name + i), *(cur_age + i)); + *(cur_name+i), *(cur_age+i)); } printf("---\n"); @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) // third way, pointers are just arrays for(i = 0; i < count; i++) { printf("%s is %d years old again.\n", - *(cur_name + i), *(cur_age + i)); + cur_name[i], cur_age[i]); } printf("---\n"); From 971363ba897da9f138deaeff0ae11cbcedf49ab6 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 22:41:32 -0400 Subject: [PATCH 066/145] printing members of argv with pointer arithmetic --- ex15.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ex15.c b/ex15.c index 1853556..c1c0a31 100644 --- a/ex15.c +++ b/ex15.c @@ -49,5 +49,13 @@ int main(int argc, char *argv[]) *cur_name, *cur_age); } + printf("---\n"); + + char **arg = argv; + for(i = 0; i < argc; i++) { + printf("argument %d is '%s'\n", i, *arg); + arg++; + } + return 0; } From 9dfa986b5d411113af48be343526e5ec61d97cad Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 22:49:41 -0400 Subject: [PATCH 067/145] printing addresses of argv members --- ex15.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex15.c b/ex15.c index c1c0a31..d3f8626 100644 --- a/ex15.c +++ b/ex15.c @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) char **arg = argv; for(i = 0; i < argc; i++) { - printf("argument %d is '%s'\n", i, *arg); + printf("argument %d is '%s' (address = %p)\n", i, *arg, arg); arg++; } From 728a7c5bd8f6b2d1137cfa2c711d01d1d248dfe3 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 22:58:45 -0400 Subject: [PATCH 068/145] using separate func for printing different formats, but still need to write different funcs for different ways of looping? --- ex15.c | 55 ++++++++++++++++--------------------------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/ex15.c b/ex15.c index d3f8626..a7bf3c5 100644 --- a/ex15.c +++ b/ex15.c @@ -1,5 +1,16 @@ #include + +void print_names_ages(int count, char *names[], int ages[], const char *fmt) +{ + int i; + for(i = 0; i < count; i++) { + printf(fmt, names[i], ages[i]); + } + printf("---\n"); +} + + int main(int argc, char *argv[]) { // create two arrays we care about @@ -10,47 +21,13 @@ int main(int argc, char *argv[]) }; // safely get the size of ages int count = sizeof(ages) / sizeof(int); - int i = 0; - // first way using indexing - for(i = 0; i < count; i++) { - printf("%s has %d years alive.\n", - names[i], ages[i]); - } - - printf("---\n"); - - // setup the pointers to the start of the arrays - int *cur_age = ages; - char **cur_name = names; - - // second way using pointers - for(i = 0; i < count; i++) { - printf("%s is %d years old.\n", - *(cur_name+i), *(cur_age+i)); - } - - printf("---\n"); - - // third way, pointers are just arrays - for(i = 0; i < count; i++) { - printf("%s is %d years old again.\n", - cur_name[i], cur_age[i]); - } - - printf("---\n"); - - // fourth way with pointers in a stupid complex way - for(cur_name = names, cur_age = ages; - (cur_age - ages) < count; - cur_name++, cur_age++) - { - printf("%s lived %d years so far.\n", - *cur_name, *cur_age); - } - - printf("---\n"); + print_names_ages(count, names, ages, "%s has %d years alive.\n"); + print_names_ages(count, names, ages, "%s is %d years old.\n"); + print_names_ages(count, names, ages, "%s is %d years old again.\n"); + print_names_ages(count, names, ages, "%s lived %d years so far.\n"); + int i; char **arg = argv; for(i = 0; i < argc; i++) { printf("argument %d is '%s' (address = %p)\n", i, *arg, arg); From 0a0fc453c5d54cd0771dd4f33cbd4e996aa7a0dc Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 22:59:40 -0400 Subject: [PATCH 069/145] back to version with long main func --- ex15.c | 55 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/ex15.c b/ex15.c index a7bf3c5..d3f8626 100644 --- a/ex15.c +++ b/ex15.c @@ -1,16 +1,5 @@ #include - -void print_names_ages(int count, char *names[], int ages[], const char *fmt) -{ - int i; - for(i = 0; i < count; i++) { - printf(fmt, names[i], ages[i]); - } - printf("---\n"); -} - - int main(int argc, char *argv[]) { // create two arrays we care about @@ -21,13 +10,47 @@ int main(int argc, char *argv[]) }; // safely get the size of ages int count = sizeof(ages) / sizeof(int); + int i = 0; - print_names_ages(count, names, ages, "%s has %d years alive.\n"); - print_names_ages(count, names, ages, "%s is %d years old.\n"); - print_names_ages(count, names, ages, "%s is %d years old again.\n"); - print_names_ages(count, names, ages, "%s lived %d years so far.\n"); + // first way using indexing + for(i = 0; i < count; i++) { + printf("%s has %d years alive.\n", + names[i], ages[i]); + } + + printf("---\n"); + + // setup the pointers to the start of the arrays + int *cur_age = ages; + char **cur_name = names; + + // second way using pointers + for(i = 0; i < count; i++) { + printf("%s is %d years old.\n", + *(cur_name+i), *(cur_age+i)); + } + + printf("---\n"); + + // third way, pointers are just arrays + for(i = 0; i < count; i++) { + printf("%s is %d years old again.\n", + cur_name[i], cur_age[i]); + } + + printf("---\n"); + + // fourth way with pointers in a stupid complex way + for(cur_name = names, cur_age = ages; + (cur_age - ages) < count; + cur_name++, cur_age++) + { + printf("%s lived %d years so far.\n", + *cur_name, *cur_age); + } + + printf("---\n"); - int i; char **arg = argv; for(i = 0; i < argc; i++) { printf("argument %d is '%s' (address = %p)\n", i, *arg, arg); From bf6752edd6a7e75673a979a2240ff5eb136a13c1 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 23:05:31 -0400 Subject: [PATCH 070/145] using separate funcs for each way of looping/printing --- ex15.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/ex15.c b/ex15.c index d3f8626..52eea30 100644 --- a/ex15.c +++ b/ex15.c @@ -1,15 +1,7 @@ #include -int main(int argc, char *argv[]) +void print_with_array_indexing(int count, char *names[], int ages[]) { - // create two arrays we care about - int ages[] = {23, 43, 12, 89, 2}; - char *names[] = { - "Alan", "Frank", - "Mary", "John", "Lisa" - }; - // safely get the size of ages - int count = sizeof(ages) / sizeof(int); int i = 0; // first way using indexing @@ -19,7 +11,11 @@ int main(int argc, char *argv[]) } printf("---\n"); +} +void print_with_pointer_arithmetic(int count, char *names[], int ages[]) +{ + int i; // setup the pointers to the start of the arrays int *cur_age = ages; char **cur_name = names; @@ -31,7 +27,13 @@ int main(int argc, char *argv[]) } printf("---\n"); +} +void print_with_pointers_as_arrays(int count, char *names[], int ages[]) +{ + int i; + int *cur_age = ages; + char **cur_name = names; // third way, pointers are just arrays for(i = 0; i < count; i++) { printf("%s is %d years old again.\n", @@ -40,6 +42,13 @@ int main(int argc, char *argv[]) printf("---\n"); +} + +void print_in_stupidly_complex_way(int count, char *names[], int ages[]) +{ + int *cur_age = ages; + char **cur_name = names; + // fourth way with pointers in a stupid complex way for(cur_name = names, cur_age = ages; (cur_age - ages) < count; @@ -50,7 +59,26 @@ int main(int argc, char *argv[]) } printf("---\n"); +} + +int main(int argc, char *argv[]) +{ + // create two arrays we care about + int ages[] = {23, 43, 12, 89, 2}; + char *names[] = { + "Alan", "Frank", + "Mary", "John", "Lisa" + }; + // safely get the size of ages + int count = sizeof(ages) / sizeof(int); + + print_with_array_indexing(count, names, ages); + print_with_pointer_arithmetic(count, names, ages); + print_with_pointers_as_arrays(count, names, ages); + print_in_stupidly_complex_way(count, names, ages); + + int i; char **arg = argv; for(i = 0; i < argc; i++) { printf("argument %d is '%s' (address = %p)\n", i, *arg, arg); From a584141d4d710e46bff9195334ff60fb3dd3c6ad Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 23:06:33 -0400 Subject: [PATCH 071/145] treating pointer args as arrays --- ex15.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ex15.c b/ex15.c index 52eea30..294f003 100644 --- a/ex15.c +++ b/ex15.c @@ -1,6 +1,6 @@ #include -void print_with_array_indexing(int count, char *names[], int ages[]) +void print_with_array_indexing(int count, char **names, int *ages) { int i = 0; @@ -13,7 +13,7 @@ void print_with_array_indexing(int count, char *names[], int ages[]) printf("---\n"); } -void print_with_pointer_arithmetic(int count, char *names[], int ages[]) +void print_with_pointer_arithmetic(int count, char **names, int *ages) { int i; // setup the pointers to the start of the arrays @@ -29,7 +29,7 @@ void print_with_pointer_arithmetic(int count, char *names[], int ages[]) printf("---\n"); } -void print_with_pointers_as_arrays(int count, char *names[], int ages[]) +void print_with_pointers_as_arrays(int count, char **names, int *ages) { int i; int *cur_age = ages; @@ -44,7 +44,7 @@ void print_with_pointers_as_arrays(int count, char *names[], int ages[]) } -void print_in_stupidly_complex_way(int count, char *names[], int ages[]) +void print_in_stupidly_complex_way(int count, char **names, int *ages) { int *cur_age = ages; char **cur_name = names; From 4d824d341f2719823c9f79932f596e99d164f0ee Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 19 Sep 2011 23:09:29 -0400 Subject: [PATCH 072/145] switching for-loops to while-loops --- ex15.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ex15.c b/ex15.c index 294f003..1621a1c 100644 --- a/ex15.c +++ b/ex15.c @@ -5,9 +5,10 @@ void print_with_array_indexing(int count, char **names, int *ages) int i = 0; // first way using indexing - for(i = 0; i < count; i++) { + while(i < count) { printf("%s has %d years alive.\n", names[i], ages[i]); + i++; } printf("---\n"); @@ -15,15 +16,16 @@ void print_with_array_indexing(int count, char **names, int *ages) void print_with_pointer_arithmetic(int count, char **names, int *ages) { - int i; + int i = 0; // setup the pointers to the start of the arrays int *cur_age = ages; char **cur_name = names; // second way using pointers - for(i = 0; i < count; i++) { + while(i < count) { printf("%s is %d years old.\n", *(cur_name+i), *(cur_age+i)); + i++; } printf("---\n"); @@ -31,13 +33,14 @@ void print_with_pointer_arithmetic(int count, char **names, int *ages) void print_with_pointers_as_arrays(int count, char **names, int *ages) { - int i; + int i = 0; int *cur_age = ages; char **cur_name = names; // third way, pointers are just arrays - for(i = 0; i < count; i++) { + while(i < count) { printf("%s is %d years old again.\n", cur_name[i], cur_age[i]); + i++; } printf("---\n"); @@ -50,12 +53,9 @@ void print_in_stupidly_complex_way(int count, char **names, int *ages) char **cur_name = names; // fourth way with pointers in a stupid complex way - for(cur_name = names, cur_age = ages; - (cur_age - ages) < count; - cur_name++, cur_age++) - { + while((cur_age - ages) < count) { printf("%s lived %d years so far.\n", - *cur_name, *cur_age); + *cur_name++, *cur_age++); } printf("---\n"); From 55fddaff46119cb4f1651dcd731ddeb986297e58 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 20 Sep 2011 14:32:33 -0400 Subject: [PATCH 073/145] first working version of ex16 --- ex16.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 ex16.c diff --git a/ex16.c b/ex16.c new file mode 100644 index 0000000..e586bab --- /dev/null +++ b/ex16.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +struct Person { + char *name; + int age; + int height; + int weight; +}; + +struct Person *Person_create(char *name, int age, int height, int weight) +{ + struct Person *who = malloc(sizeof(struct Person)); + assert(who != NULL); + + who->name = strdup(name); + who->age = age; + who->height = height; + who->weight = weight; + + return who; +} + +void Person_destroy(struct Person *who) +{ + assert(who != NULL); + + free(who->name); + free(who); +} + +void Person_print(struct Person *who) +{ + printf("Name: %s\n", who->name); + printf("\tAge: %d\n", who->age); + printf("\tHeight: %d\n", who->height); + printf("\tWeight: %d\n", who->weight); +} + +int main(int argc, char *argv[]) +{ + // make two people structures + struct Person *joe = Person_create( + "Joe Alex", 32, 64, 140); + + struct Person *frank = Person_create( + "Frank Blank", 20, 72, 180); + + // print them out and where they are in memory + printf("Joe is at memory location %p:\n", joe); + Person_print(joe); + + printf("Frank is at memory location %p:\n", frank); + Person_print(frank); + + // make everyone age 20 years and print them again + joe->age += 20; + joe->height -= 2; + joe->weight += 40; + Person_print(joe); + + frank->age += 20; + frank->weight += 20; + Person_print(frank); + + // destroy them both so we clean up + Person_destroy(joe); + Person_destroy(frank); + + return 0; +} From 9d258d22b830ea2c93401d2e4ebe79a43f7f8322 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 20 Sep 2011 14:38:34 -0400 Subject: [PATCH 074/145] version of ex16 with structs created on the stack, using dot syntax instead of ->, passing by value --- ex16.c | 56 ++++++++++++++------------------------------------------ 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/ex16.c b/ex16.c index e586bab..2e505c7 100644 --- a/ex16.c +++ b/ex16.c @@ -10,64 +10,36 @@ struct Person { int weight; }; -struct Person *Person_create(char *name, int age, int height, int weight) +void Person_print(struct Person who) { - struct Person *who = malloc(sizeof(struct Person)); - assert(who != NULL); - - who->name = strdup(name); - who->age = age; - who->height = height; - who->weight = weight; - - return who; -} - -void Person_destroy(struct Person *who) -{ - assert(who != NULL); - - free(who->name); - free(who); -} - -void Person_print(struct Person *who) -{ - printf("Name: %s\n", who->name); - printf("\tAge: %d\n", who->age); - printf("\tHeight: %d\n", who->height); - printf("\tWeight: %d\n", who->weight); + printf("Name: %s\n", who.name); + printf("\tAge: %d\n", who.age); + printf("\tHeight: %d\n", who.height); + printf("\tWeight: %d\n", who.weight); } int main(int argc, char *argv[]) { // make two people structures - struct Person *joe = Person_create( - "Joe Alex", 32, 64, 140); - - struct Person *frank = Person_create( - "Frank Blank", 20, 72, 180); + struct Person joe = {"Joe Alex", 32, 64, 140}; + struct Person frank = {"Frank Blank", 20, 72, 180}; // print them out and where they are in memory - printf("Joe is at memory location %p:\n", joe); + printf("Joe is at memory location %p:\n", &joe); Person_print(joe); - printf("Frank is at memory location %p:\n", frank); + printf("Frank is at memory location %p:\n", &frank); Person_print(frank); // make everyone age 20 years and print them again - joe->age += 20; - joe->height -= 2; - joe->weight += 40; + joe.age += 20; + joe.height -= 2; + joe.weight += 40; Person_print(joe); - frank->age += 20; - frank->weight += 20; + frank.age += 20; + frank.weight += 20; Person_print(frank); - // destroy them both so we clean up - Person_destroy(joe); - Person_destroy(frank); - return 0; } From f7b89eb28f2ade359abc5677c3e1dc5871c87b9c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 20 Sep 2011 14:39:07 -0400 Subject: [PATCH 075/145] back to version that uses malloc/free and pointers --- ex16.c | 56 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/ex16.c b/ex16.c index 2e505c7..e586bab 100644 --- a/ex16.c +++ b/ex16.c @@ -10,36 +10,64 @@ struct Person { int weight; }; -void Person_print(struct Person who) +struct Person *Person_create(char *name, int age, int height, int weight) { - printf("Name: %s\n", who.name); - printf("\tAge: %d\n", who.age); - printf("\tHeight: %d\n", who.height); - printf("\tWeight: %d\n", who.weight); + struct Person *who = malloc(sizeof(struct Person)); + assert(who != NULL); + + who->name = strdup(name); + who->age = age; + who->height = height; + who->weight = weight; + + return who; +} + +void Person_destroy(struct Person *who) +{ + assert(who != NULL); + + free(who->name); + free(who); +} + +void Person_print(struct Person *who) +{ + printf("Name: %s\n", who->name); + printf("\tAge: %d\n", who->age); + printf("\tHeight: %d\n", who->height); + printf("\tWeight: %d\n", who->weight); } int main(int argc, char *argv[]) { // make two people structures - struct Person joe = {"Joe Alex", 32, 64, 140}; - struct Person frank = {"Frank Blank", 20, 72, 180}; + struct Person *joe = Person_create( + "Joe Alex", 32, 64, 140); + + struct Person *frank = Person_create( + "Frank Blank", 20, 72, 180); // print them out and where they are in memory - printf("Joe is at memory location %p:\n", &joe); + printf("Joe is at memory location %p:\n", joe); Person_print(joe); - printf("Frank is at memory location %p:\n", &frank); + printf("Frank is at memory location %p:\n", frank); Person_print(frank); // make everyone age 20 years and print them again - joe.age += 20; - joe.height -= 2; - joe.weight += 40; + joe->age += 20; + joe->height -= 2; + joe->weight += 40; Person_print(joe); - frank.age += 20; - frank.weight += 20; + frank->age += 20; + frank->weight += 20; Person_print(frank); + // destroy them both so we clean up + Person_destroy(joe); + Person_destroy(frank); + return 0; } From c64e1beeaa3ca3de7da3bb490edc32a45c8463a4 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 20 Sep 2011 15:15:43 -0400 Subject: [PATCH 076/145] first working version of ex17.c --- ex17.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 ex17.c diff --git a/ex17.c b/ex17.c new file mode 100644 index 0000000..8e3cbb1 --- /dev/null +++ b/ex17.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include + +#define MAX_DATA 512 +#define MAX_ROWS 100 + +struct Address { + int id; + int set; + char name[MAX_DATA]; + char email[MAX_DATA]; +}; + +struct Database { + struct Address rows[MAX_ROWS]; +}; + +struct Connection { + FILE *file; + struct Database *db; +}; + +void die(const char *message) +{ + if(errno) { + perror(message); + } else { + printf("ERROR: %s\n", message); + } + + exit(1); +} + +void Address_print(struct Address *addr) +{ + printf("%d %s %s\n", + addr->id, addr->name, addr->email); +} + +void Database_load(struct Connection *conn) +{ + int rc = fread(conn->db, sizeof(struct Database), 1, conn->file); + if(rc != 1) die("Failed to load database."); +} + +struct Connection* Database_open(const char *filename, char mode) +{ + struct Connection *conn = malloc(sizeof(struct Connection)); + if(!conn) die("Memory error"); + + conn->db = malloc(sizeof(struct Database)); + if(!conn->db) die("Memory error"); + + if(mode == 'c') { + conn->file = fopen(filename, "w"); + } else { + conn->file = fopen(filename, "r+"); + + if(conn->file) { + Database_load(conn); + } + } + + if(!conn->file) die("Failed to open the file"); + + return conn; +} + +void Database_close(struct Connection *conn) +{ + if(conn) { + if(conn->file) fclose(conn->file); + if(conn->db) free(conn->db); + free(conn); + } +} + +void Database_write(struct Connection *conn) +{ + rewind(conn->file); + + int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file); + if(rc != 1) die("Failed to write database."); + + rc = fflush(conn->file); + if(rc == -1) die("Cannot flush database."); +} + +void Database_create(struct Connection *conn) +{ + int i = 0; + + for(i = 0; i < MAX_ROWS; i++) { + // make a prototype to initialize it + struct Address addr = {.id = i, .set = 0}; + // then just assign it + conn->db->rows[i] = addr; + } +} + +void Database_set(struct Connection *conn, int id, const char *name, const char *email) +{ + struct Address *addr = &conn->db->rows[id]; + if(addr->set) die("Already set, delete it first."); + + addr->set = 1; + // WARNING: bug, read the "How To Break It" and fix this + char *res = strncpy(addr->name, name, MAX_DATA); + // demonstrate the strncpy bug + if(!res) die("Name copy failed"); + + res = strncpy(addr->email, email, MAX_DATA); + if(!res) die("Email copy failed"); +} + +void Database_get(struct Connection *conn, int id) +{ + struct Address *addr = &conn->db->rows[id]; + + if(addr->set) { + Address_print(addr); + } else { + die("ID is not set"); + } +} + +void Database_delete(struct Connection *conn, int id) +{ + struct Address addr = {.id = id, .set = 0}; + conn->db->rows[id] = addr; +} + +void Database_list(struct Connection *conn) +{ + int i = 0; + struct Database *db = conn->db; + + for(i = 0; i < MAX_ROWS; i++) { + struct Address *cur = &db->rows[i]; + + if(cur->set) { + Address_print(cur); + } + } +} + +int main(int argc, char *argv[]) +{ + if(argc < 3) die("USAGE: ex17 [action params]"); + + char *filename = argv[1]; + char action = argv[2][0]; + struct Connection *conn = Database_open(filename, action); + int id = 0; + + if(argc > 3) id = atoi(argv[3]); + if(id >= MAX_ROWS) die("There's not that many records."); + + switch(action) { + case 'c': + Database_create(conn); + Database_write(conn); + break; + + case 'g': + if(argc != 4) die("Need an id to get"); + + Database_get(conn, id); + break; + + case 's': + if(argc != 6) die("Need id, name, email to set"); + + Database_set(conn, id, argv[4], argv[5]); + Database_write(conn); + break; + + case 'd': + if(argc != 4) die("Need id to delete"); + + Database_delete(conn, id); + Database_write(conn); + break; + + case 'l': + Database_list(conn); + break; + default: + die("Invalid action, only: c=create, g=get, s=set, d=del, l=list"); + } + + Database_close(conn); + + return 0; +} From 791f3b132782cf0f5e19227051f0ad361983ec1d Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 21 Sep 2011 13:24:43 -0400 Subject: [PATCH 077/145] altering to match book source code so that I can reliably spot line ref errors --- ex17.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ex17.c b/ex17.c index 8e3cbb1..493d9a1 100644 --- a/ex17.c +++ b/ex17.c @@ -104,7 +104,7 @@ void Database_create(struct Connection *conn) void Database_set(struct Connection *conn, int id, const char *name, const char *email) { struct Address *addr = &conn->db->rows[id]; - if(addr->set) die("Already set, delete it first."); + if(addr->set) die("Already set, delete it first"); addr->set = 1; // WARNING: bug, read the "How To Break It" and fix this @@ -196,3 +196,4 @@ int main(int argc, char *argv[]) return 0; } + From 198b54d316aa944ddb1033c4a9b6026a9f23b4b2 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 21 Sep 2011 22:23:37 -0400 Subject: [PATCH 078/145] fixing (?) the strncpy bug --- ex17.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ex17.c b/ex17.c index 493d9a1..19289e7 100644 --- a/ex17.c +++ b/ex17.c @@ -107,13 +107,13 @@ void Database_set(struct Connection *conn, int id, const char *name, const char if(addr->set) die("Already set, delete it first"); addr->set = 1; - // WARNING: bug, read the "How To Break It" and fix this char *res = strncpy(addr->name, name, MAX_DATA); - // demonstrate the strncpy bug if(!res) die("Name copy failed"); + addr->name[MAX_DATA - 1] = '\0'; res = strncpy(addr->email, email, MAX_DATA); if(!res) die("Email copy failed"); + addr->email[MAX_DATA - 1] = '\0'; } void Database_get(struct Connection *conn, int id) From c5a1f902007f930b7b2ef5d7cbb43743ae8dcb84 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 21 Sep 2011 22:30:46 -0400 Subject: [PATCH 079/145] augmenting "die" to close db connection --- ex17.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/ex17.c b/ex17.c index 19289e7..45588b2 100644 --- a/ex17.c +++ b/ex17.c @@ -23,7 +23,9 @@ struct Connection { struct Database *db; }; -void die(const char *message) +void Database_close(struct Connection *conn); + +void die(const char *message, struct Connection *conn) { if(errno) { perror(message); @@ -31,6 +33,8 @@ void die(const char *message) printf("ERROR: %s\n", message); } + Database_close(conn); + exit(1); } @@ -43,16 +47,16 @@ void Address_print(struct Address *addr) void Database_load(struct Connection *conn) { int rc = fread(conn->db, sizeof(struct Database), 1, conn->file); - if(rc != 1) die("Failed to load database."); + if(rc != 1) die("Failed to load database.", conn); } struct Connection* Database_open(const char *filename, char mode) { struct Connection *conn = malloc(sizeof(struct Connection)); - if(!conn) die("Memory error"); + if(!conn) die("Memory error", conn); conn->db = malloc(sizeof(struct Database)); - if(!conn->db) die("Memory error"); + if(!conn->db) die("Memory error", conn); if(mode == 'c') { conn->file = fopen(filename, "w"); @@ -64,14 +68,14 @@ struct Connection* Database_open(const char *filename, char mode) } } - if(!conn->file) die("Failed to open the file"); + if(!conn->file) die("Failed to open the file", conn); return conn; } void Database_close(struct Connection *conn) { - if(conn) { + if(conn != NULL) { if(conn->file) fclose(conn->file); if(conn->db) free(conn->db); free(conn); @@ -83,10 +87,10 @@ void Database_write(struct Connection *conn) rewind(conn->file); int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file); - if(rc != 1) die("Failed to write database."); + if(rc != 1) die("Failed to write database.", conn); rc = fflush(conn->file); - if(rc == -1) die("Cannot flush database."); + if(rc == -1) die("Cannot flush database.", conn); } void Database_create(struct Connection *conn) @@ -104,15 +108,15 @@ void Database_create(struct Connection *conn) void Database_set(struct Connection *conn, int id, const char *name, const char *email) { struct Address *addr = &conn->db->rows[id]; - if(addr->set) die("Already set, delete it first"); + if(addr->set) die("Already set, delete it first", conn); addr->set = 1; char *res = strncpy(addr->name, name, MAX_DATA); - if(!res) die("Name copy failed"); + if(!res) die("Name copy failed", conn); addr->name[MAX_DATA - 1] = '\0'; res = strncpy(addr->email, email, MAX_DATA); - if(!res) die("Email copy failed"); + if(!res) die("Email copy failed", conn); addr->email[MAX_DATA - 1] = '\0'; } @@ -123,7 +127,7 @@ void Database_get(struct Connection *conn, int id) if(addr->set) { Address_print(addr); } else { - die("ID is not set"); + die("ID is not set", conn); } } @@ -149,7 +153,7 @@ void Database_list(struct Connection *conn) int main(int argc, char *argv[]) { - if(argc < 3) die("USAGE: ex17 [action params]"); + if(argc < 3) die("USAGE: ex17 [action params]", NULL); char *filename = argv[1]; char action = argv[2][0]; @@ -157,7 +161,7 @@ int main(int argc, char *argv[]) int id = 0; if(argc > 3) id = atoi(argv[3]); - if(id >= MAX_ROWS) die("There's not that many records."); + if(id >= MAX_ROWS) die("There's not that many records.", conn); switch(action) { case 'c': @@ -166,20 +170,20 @@ int main(int argc, char *argv[]) break; case 'g': - if(argc != 4) die("Need an id to get"); + if(argc != 4) die("Need an id to get", conn); Database_get(conn, id); break; case 's': - if(argc != 6) die("Need id, name, email to set"); + if(argc != 6) die("Need id, name, email to set", conn); Database_set(conn, id, argv[4], argv[5]); Database_write(conn); break; case 'd': - if(argc != 4) die("Need id to delete"); + if(argc != 4) die("Need id to delete", conn); Database_delete(conn, id); Database_write(conn); @@ -189,7 +193,7 @@ int main(int argc, char *argv[]) Database_list(conn); break; default: - die("Invalid action, only: c=create, g=get, s=set, d=del, l=list"); + die("Invalid action, only: c=create, g=get, s=set, d=del, l=list", conn); } Database_close(conn); From ab98180af01d29bf219b3af24944db73ed6b936f Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 23 Sep 2011 22:54:52 -0400 Subject: [PATCH 080/145] BUSTED while trying to do extra credit #2 --- ex17.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/ex17.c b/ex17.c index 45588b2..17f0fc7 100644 --- a/ex17.c +++ b/ex17.c @@ -4,18 +4,20 @@ #include #include -#define MAX_DATA 512 -#define MAX_ROWS 100 +#define DEFAULT_MAX_DATA 512 +#define DEFAULT_MAX_ROWS 100 struct Address { int id; int set; - char name[MAX_DATA]; - char email[MAX_DATA]; + char *name; + char *email; }; struct Database { - struct Address rows[MAX_ROWS]; + int max_data; + int max_rows; + struct Address rows[]; }; struct Connection { @@ -93,11 +95,13 @@ void Database_write(struct Connection *conn) if(rc == -1) die("Cannot flush database.", conn); } -void Database_create(struct Connection *conn) +void Database_create(struct Connection *conn, int max_rows, int max_data) { int i = 0; + conn->db->max_rows = max_rows; + conn->db->max_data = max_data; - for(i = 0; i < MAX_ROWS; i++) { + for(i = 0; i < conn->db->max_rows; i++) { // make a prototype to initialize it struct Address addr = {.id = i, .set = 0}; // then just assign it @@ -107,17 +111,18 @@ void Database_create(struct Connection *conn) void Database_set(struct Connection *conn, int id, const char *name, const char *email) { + int max_data = conn->db->max_data; struct Address *addr = &conn->db->rows[id]; if(addr->set) die("Already set, delete it first", conn); addr->set = 1; - char *res = strncpy(addr->name, name, MAX_DATA); + char *res = strncpy(addr->name, name, max_data); if(!res) die("Name copy failed", conn); - addr->name[MAX_DATA - 1] = '\0'; + addr->name[max_data - 1] = '\0'; - res = strncpy(addr->email, email, MAX_DATA); + res = strncpy(addr->email, email, max_data); if(!res) die("Email copy failed", conn); - addr->email[MAX_DATA - 1] = '\0'; + addr->email[max_data - 1] = '\0'; } void Database_get(struct Connection *conn, int id) @@ -142,7 +147,7 @@ void Database_list(struct Connection *conn) int i = 0; struct Database *db = conn->db; - for(i = 0; i < MAX_ROWS; i++) { + for(i = 0; i < conn->db->max_rows; i++) { struct Address *cur = &db->rows[i]; if(cur->set) { @@ -153,19 +158,27 @@ void Database_list(struct Connection *conn) int main(int argc, char *argv[]) { - if(argc < 3) die("USAGE: ex17 [action params]", NULL); + if(argc < 3) die("USAGE: ex17 [:max_data,max_rows] [action params]", NULL); char *filename = argv[1]; + + int max_data = DEFAULT_MAX_DATA; + int max_rows = DEFAULT_MAX_ROWS; + char action = argv[2][0]; + if(':' == argv[2][1]) { + sscanf(argv[2], "%c:%d,%d", &action, &max_data, &max_rows); + } + struct Connection *conn = Database_open(filename, action); int id = 0; if(argc > 3) id = atoi(argv[3]); - if(id >= MAX_ROWS) die("There's not that many records.", conn); + if(id >= max_rows) die("There's not that many records.", conn); switch(action) { case 'c': - Database_create(conn); + Database_create(conn, max_rows, max_data); Database_write(conn); break; From 314faf66f8af49c05e7aa9230ca3ae9a9ca51bda Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 12 Oct 2011 08:04:23 -0400 Subject: [PATCH 081/145] busted, but really must move along... --- ex17.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/ex17.c b/ex17.c index 17f0fc7..1eaece1 100644 --- a/ex17.c +++ b/ex17.c @@ -15,9 +15,10 @@ struct Address { }; struct Database { + size_t size; int max_data; int max_rows; - struct Address rows[]; + struct Address *rows; }; struct Connection { @@ -48,11 +49,19 @@ void Address_print(struct Address *addr) void Database_load(struct Connection *conn) { - int rc = fread(conn->db, sizeof(struct Database), 1, conn->file); - if(rc != 1) die("Failed to load database.", conn); + rewind(conn->file); + + int rc = fread(&conn->db->max_rows, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to load database max_rows.", conn); + + rc = fread(&conn->db->max_data, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to load database max_data.", conn); + + rc = fread(conn->db->rows, sizeof(struct Address), conn->db->max_rows, conn->file); + if(rc != 1) die("Failed to load database rows.", conn); } -struct Connection* Database_open(const char *filename, char mode) +struct Connection* Database_open(const char *filename, char mode, int max_rows) { struct Connection *conn = malloc(sizeof(struct Connection)); if(!conn) die("Memory error", conn); @@ -60,6 +69,11 @@ struct Connection* Database_open(const char *filename, char mode) conn->db = malloc(sizeof(struct Database)); if(!conn->db) die("Memory error", conn); + size_t rowsize = max_rows * sizeof(struct Address); + conn->db->size = rowsize; + conn->db->rows = malloc(rowsize); + if(!conn->db->rows) die("Memory error", conn); + if(mode == 'c') { conn->file = fopen(filename, "w"); } else { @@ -88,8 +102,17 @@ void Database_write(struct Connection *conn) { rewind(conn->file); - int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file); - if(rc != 1) die("Failed to write database.", conn); + int rc = fwrite(&conn->db->size, sizeof(size_t), 1, conn->file); + if(rc != 1) die("Failed to write database size.", conn); + + rc = fwrite(&conn->db->max_rows, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to write database max_rows.", conn); + + rc = fwrite(&conn->db->max_data, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to write database max_data.", conn); + + rc = fwrite(conn->db->rows, conn->db->size, 1, conn->file); + if(rc != 1) die("Failed to write database rows.", conn); rc = fflush(conn->file); if(rc == -1) die("Cannot flush database.", conn); @@ -170,7 +193,7 @@ int main(int argc, char *argv[]) sscanf(argv[2], "%c:%d,%d", &action, &max_data, &max_rows); } - struct Connection *conn = Database_open(filename, action); + struct Connection *conn = Database_open(filename, action, max_rows); int id = 0; if(argc > 3) id = atoi(argv[3]); From 032fd49d5db4739b7932451358d3c7843318b565 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 23 Oct 2011 22:59:23 -0400 Subject: [PATCH 082/145] first working version of ex18.c --- ex18.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 ex18.c diff --git a/ex18.c b/ex18.c new file mode 100644 index 0000000..34bf3e1 --- /dev/null +++ b/ex18.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include + + +void die(const char *message) +{ + if(errno) { + perror(message); + } else { + printf("ERROR: %s\n", message); + } + + exit(1); +} + + +typedef int (*compare_cb)(int a, int b); + + +int *bubble_sort(int *numbers, int count, compare_cb cmp) +{ + int temp = 0; + int i = 0; + int j = 0; + int *target = malloc(count * sizeof(int)); + + if(!target) die("Memory error."); + + memcpy(target, numbers, count * sizeof(int)); + + for(i = 0; i < count; i++) { + for(j = 0; j < count - 1; j++) { + if(cmp(target[j], target[j+1]) > 0) { + temp = target[j+1]; + target[j+1] = target[j]; + target[j] = temp; + } + } + } + + return target; +} + + +int sorted_order(int a, int b) +{ + return a - b; +} + + +int reverse_order(int a, int b) +{ + return b - a; +} + + +int strange_order(int a, int b) +{ + if(a == 0 || b == 0) { + return 0; + } else { + return a % b; + } +} + + +void test_sorting(int *numbers, int count, compare_cb cmp) +{ + int i = 0; + int *sorted = bubble_sort(numbers, count, cmp); + + if(!sorted) die("Failed to sort as requested."); + + for(i = 0; i < count; i++) { + printf("%d ", sorted[i]); + } + printf("\n"); + + free(sorted); +} + + +int main(int argc, char *argv[]) +{ + if(argc < 2) die("USAGE: ex18 4 3 1 5 6"); + + int count = argc - 1; + int i = 0; + char **inputs = argv + 1; + + int *numbers = malloc(count * sizeof(int)); + if(!numbers) die("Memory error."); + + for(i = 0; i < count; i++) { + numbers[i] = atoi(inputs[i]); + } + + test_sorting(numbers, count, sorted_order); + test_sorting(numbers, count, reverse_order); + test_sorting(numbers, count, strange_order); + + free(numbers); + + return 0; +} From aab442042bba14c3e4e7675c04dbbfc32a079117 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 23 Oct 2011 23:07:53 -0400 Subject: [PATCH 083/145] adding the bit of tomfoolery which looks at the raw byte code of functions --- ex18.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ex18.c b/ex18.c index 34bf3e1..5a5a77a 100644 --- a/ex18.c +++ b/ex18.c @@ -80,6 +80,13 @@ void test_sorting(int *numbers, int count, compare_cb cmp) printf("\n"); free(sorted); + + unsigned char *data = (unsigned char *)cmp; + + for(i = 0; i < 25; i++) { + printf("%0x:", data[i]); + } + printf("\n"); } From 237f86c62eb10715e79eb0fdf6e04c27cd77b2de Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 25 Oct 2011 20:11:42 -0400 Subject: [PATCH 084/145] adding new object.h for ch.20 ex.19 --- .gitignore | 1 + object.h | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 object.h diff --git a/.gitignore b/.gitignore index 10d5414..86732f5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ !Makefile !README.md !*.py +!*.h diff --git a/object.h b/object.h new file mode 100644 index 0000000..65b5aca --- /dev/null +++ b/object.h @@ -0,0 +1,27 @@ +#ifndef _object_h +#define _object_h + +typedef enum { + NORTH, SOUTH, EAST, WEST +} Direction; + +typedef struct { + char *description; + int (*init)(void *self); + void (*describe)(void *self); + void (*destroy)(void *self); + void *(*move)(void *self, Direction direction); + int (*attack)(void *self, int damage); +} Object; + +int Object_init(void *self); +void Object_destroy(void *self); +void Object_describe(void *self); +void *Object_move(void *self, Direction direction); +int Object_attack(void *self, int damage); +void *Object_new(size_t size, Object proto, char *description); + +#define NEW(T, N) Object_new(sizeof(T), T##Proto, N) +#define _(N) proto.N + +#endif From 62dab95f9c44f1afb7a418a2292d31e2a1f9e8a0 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 25 Oct 2011 20:35:38 -0400 Subject: [PATCH 085/145] Adding first version of object.c for ch20 ex19 --- object.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 object.c diff --git a/object.c b/object.c new file mode 100644 index 0000000..5466ac3 --- /dev/null +++ b/object.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include "object.h" +#include + + +void Object_destroy(void *self) +{ + Object *obj = self; + + if(obj) { + if(obj->description) free(obj->description); + free(obj); + } +} + + +void Object_describe(void *self) +{ + Object *obj = self; + printf("%s\n", obj->description); +} + + +int Object_init(void *self) +{ + // do nothing really + return 1; +} + + +void *Object_move(void *self, Direction direction) +{ + printf("You can't go that direction.\n"); + return NULL; +} + + +int Object_attack(void *self, int damage) +{ + printf("You can't attack that.\n"); + return 0; +} + + +void *Object_new(size_t size, Object proto, char *description) +{ + // setup the default functions in case they aren't set + if(!proto.init) proto.init = Object_init; + if(!proto.describe) proto.describe = Object_describe; + if(!proto.destroy) proto.destroy = Object_destroy; + if(!proto.attack) proto.attack = Object_attack; + if(!proto.move) proto.move = Object_move; + + // this seems weird, but we can make a struct of one size, + // then point a different pointer at it to "cast" it + Object *el = calloc(size, 1); + *el = proto; + + // copy the description over + el->description = strdup(description); + + // initialize it with whatever init we were given + if(!el->init(el)) { + // looks like it didn't initialize properly + el->destroy(el); + return NULL; + } else { + // all done, we made an object of any type + return el; + } +} From ae4c0fdaa294245c851de1fb5525368df85774b0 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 25 Oct 2011 20:42:56 -0400 Subject: [PATCH 086/145] Adding the header file and separate makefile for ex19 --- .gitignore | 1 + Makefile | 3 ++- ex19.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ex19.mk | 8 ++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 ex19.h create mode 100644 ex19.mk diff --git a/.gitignore b/.gitignore index 86732f5..157050f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ !README.md !*.py !*.h +!*.mk diff --git a/Makefile b/Makefile index bf1e2c6..4db3ffc 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ CFLAGS=-Wall -g -EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c)) +EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | grep -v ex19)) all: $(EXERCISES) + $(MAKE) -f ex19.mk clean: diff --git a/ex19.h b/ex19.h new file mode 100644 index 0000000..0131465 --- /dev/null +++ b/ex19.h @@ -0,0 +1,54 @@ +#ifndef _ex19_h +#define _ex19_h + +#include "object.h" + + +struct Monster { + Object proto; + int hit_points; +}; + + +typedef struct Monster Monster; + + +int Monster_attack(void *self, int damage); +int Monster_init(void *self); + + +struct Room { + Object proto; + + Monster *bad_guy; + + struct Room *north; + struct Room *south; + struct Room *east; + struct Room *west; +}; + + +typedef struct Room Room; + + +void *Room_move(void *self, Direction direction); +int Room_attack(void *self, int damage); +int Room_init(void *self); + + +struct Map { + Object proto; + Room *start; + Room *location; +}; + + +typedef struct Map Map; + + +void *Map_move(void *self, Direction direction); +int Map_attack(void *self, int damage); +int Map_init(void *self); + +#endif diff --git a/ex19.mk b/ex19.mk new file mode 100644 index 0000000..aea800f --- /dev/null +++ b/ex19.mk @@ -0,0 +1,8 @@ +CFLAGS=-Wall -g + +all: ex19 + +ex19: object.o + +clean: + rm -f ex19 From 1695ec379691231b46ed72260efc856816affc61 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 25 Oct 2011 21:11:14 -0400 Subject: [PATCH 087/145] Adding the game implementation for ex19 --- ex19.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 ex19.c diff --git a/ex19.c b/ex19.c new file mode 100644 index 0000000..1d73d2f --- /dev/null +++ b/ex19.c @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include "ex19.h" + + +int Monster_attack(void *self, int damage) +{ + Monster *monster = self; + + printf("You attack %s!\n", monster->_(description)); + monster->hit_points -= damage; + + if(monster->hit_points > 0) { + printf("It is still alive.\n"); + return 0; + } else { + printf("It is dead!\n"); + return 1; + } +} + + +int Monster_init(void *self) +{ + Monster *monster = self; + monster->hit_points = 10; + return 1; +} + + +Object MonsterProto = { + .init = Monster_init, + .attack = Monster_attack +}; + + +void *Room_move(void *self, Direction direction) +{ + Room *room = self; + Room *next = NULL; + + if(direction == NORTH && room->north) { + printf("You go north, into:\n"); + next = room->north; + } else if(direction == SOUTH && room->south) { + printf("You go south, into:\n"); + next = room->south; + } else if(direction == EAST && room->east) { + printf("You go east, into:\n"); + next = room->east; + } else if(direction == WEST && room->west) { + printf("You go west, into:\n"); + next = room->west; + } else { + printf("You can't go that direction."); + next = NULL; + } + + if(next) { + next->_(describe)(next); + } + + return next; +} + + +int Room_attack(void *self, int damage) +{ + Room *room = self; + Monster *monster = room->bad_guy; + + if(monster) { + monster->_(attack)(monster, damage); + return 1; + } else { + printf("You flail in the air at nothing. Idiot.\n"); + return 0; + } +} + + +Object RoomProto = { + .move = Room_move, + .attack = Room_attack +}; + + +void *Map_move(void *self, Direction direction) +{ + Map *map = self; + Room *location = map->location; + Room *next = NULL; + + next = location->_(move)(location, direction); + + if(next) { + map->location = next; + } + + return next; +} + + +int Map_attack(void *self, int damage) +{ + Map *map = self; + Room *location = map->location; + + return location->_(attack)(location, damage); +} + + +int Map_init(void *self) +{ + Map *map = self; + + // make some rooms for a small map + Room *hall = NEW(Room, "The great Hall"); + Room *throne = NEW(Room, "The throne room"); + Room *arena = NEW(Room, "The arena, with the minotaur"); + Room *kitchen = NEW(Room, "Kitchen, you have the knife now"); + + // put the bad guy in the arena + arena->bad_guy = NEW(Monster, "The evil minotaur"); + + // setup the map rooms; + hall->north = throne; + + throne->west = arena; + throne->east = kitchen; + throne->south = hall; + + arena->east = throne; + kitchen->west = throne; + + // start the map and the character off in the hall + map->start = hall; + map->location = hall; + + return 1; +} + + +Object MapProto = { + .init = Map_init, + .move = Map_move, + .attack = Map_attack +}; + + +int process_input(Map *game) +{ + printf("\n> "); + + char ch = getchar(); + getchar(); // eat ENTER + + int damage = rand() % 4; + + switch(ch) { + case -1: + printf("Giving up? You suck.\n"); + return 0; + break; + + case 'n': + game->_(move)(game, NORTH); + break; + + case 's': + game->_(move)(game, SOUTH); + break; + + case 'e': + game->_(move)(game, EAST); + break; + + case 'w': + game->_(move)(game, WEST); + break; + + case 'a': + game->_(attack)(game, damage); + break; + + case 'l': + printf("You can go:\n"); + if(game->location->north) printf("NORTH\n"); + if(game->location->south) printf("SOUTH\n"); + if(game->location->east) printf("EAST\n"); + if(game->location->west) printf("WEST\n"); + break; + + default: + printf("What?: %d\n", ch); + } + + return 1; +} + + +int main(int argc, char *argv[]) +{ + // simple way to setup randomness + srand(time(NULL)); + + // make our map to work with + Map *game = NEW(Map, "The Hall of the Minotaur."); + + printf("You enter the "); + game->location->_(describe)(game->location); + + while(process_input(game)) { + } + + return 0; +} From 891013a781f22ea6d5bbcab0cd1425351bfadd66 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 25 Oct 2011 21:17:09 -0400 Subject: [PATCH 088/145] adding a few asserts for ex19 --- object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/object.c b/object.c index 5466ac3..07a5af5 100644 --- a/object.c +++ b/object.c @@ -46,6 +46,7 @@ int Object_attack(void *self, int damage) void *Object_new(size_t size, Object proto, char *description) { + assert(description != NULL); // setup the default functions in case they aren't set if(!proto.init) proto.init = Object_init; if(!proto.describe) proto.describe = Object_describe; @@ -56,6 +57,7 @@ void *Object_new(size_t size, Object proto, char *description) // this seems weird, but we can make a struct of one size, // then point a different pointer at it to "cast" it Object *el = calloc(size, 1); + assert(el != NULL); *el = proto; // copy the description over From 5bf9ce7c23fc280072e6cf564f6427949f3bad9c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 25 Oct 2011 21:19:49 -0400 Subject: [PATCH 089/145] Cleaning everything during make clean --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 4db3ffc..5d87ee0 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,8 @@ all: $(EXERCISES) clean: rm -f $(EXERCISES) + rm -f ex19 + rm -f object.o .PHONY: all clean From e69dc72f9c1f39a4de7aadad1b5d344e3aa1a3bd Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 25 Oct 2011 21:21:02 -0400 Subject: [PATCH 090/145] Moving the "clean" target for ex19 into the correct file --- Makefile | 3 +-- ex19.mk | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5d87ee0..091111c 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,7 @@ all: $(EXERCISES) clean: rm -f $(EXERCISES) - rm -f ex19 - rm -f object.o + $(MAKE) -f ex19.mk clean .PHONY: all clean diff --git a/ex19.mk b/ex19.mk index aea800f..96e5d90 100644 --- a/ex19.mk +++ b/ex19.mk @@ -6,3 +6,4 @@ ex19: object.o clean: rm -f ex19 + rm -f object.o From 874eb4f3a228ddebcbb70eb76bf69a9684b4bf73 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 26 Oct 2011 03:47:15 -0400 Subject: [PATCH 091/145] Adding a bunch of asserts --- ex19.c | 23 ++++++++++++++++++++++- object.c | 15 +++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/ex19.c b/ex19.c index 1d73d2f..5acd311 100644 --- a/ex19.c +++ b/ex19.c @@ -3,11 +3,15 @@ #include #include #include +#include #include "ex19.h" int Monster_attack(void *self, int damage) { + assert(self != NULL); + assert(damage > -1); + Monster *monster = self; printf("You attack %s!\n", monster->_(description)); @@ -25,6 +29,8 @@ int Monster_attack(void *self, int damage) int Monster_init(void *self) { + assert(self != NULL); + Monster *monster = self; monster->hit_points = 10; return 1; @@ -39,6 +45,9 @@ Object MonsterProto = { void *Room_move(void *self, Direction direction) { + assert(self != NULL); + assert(direction); + Room *room = self; Room *next = NULL; @@ -69,6 +78,9 @@ void *Room_move(void *self, Direction direction) int Room_attack(void *self, int damage) { + assert(self != NULL); + assert(damage > -1); + Room *room = self; Monster *monster = room->bad_guy; @@ -90,6 +102,9 @@ Object RoomProto = { void *Map_move(void *self, Direction direction) { + assert(self != NULL); + assert(direction); + Map *map = self; Room *location = map->location; Room *next = NULL; @@ -106,6 +121,9 @@ void *Map_move(void *self, Direction direction) int Map_attack(void *self, int damage) { + assert(self != NULL); + assert(damage > -1); + Map *map = self; Room *location = map->location; @@ -115,6 +133,8 @@ int Map_attack(void *self, int damage) int Map_init(void *self) { + assert(self != NULL); + Map *map = self; // make some rooms for a small map @@ -156,12 +176,13 @@ int process_input(Map *game) printf("\n> "); char ch = getchar(); + assert(ch != EOF); getchar(); // eat ENTER int damage = rand() % 4; switch(ch) { - case -1: + case EOF: printf("Giving up? You suck.\n"); return 0; break; diff --git a/object.c b/object.c index 07a5af5..268f169 100644 --- a/object.c +++ b/object.c @@ -7,6 +7,8 @@ void Object_destroy(void *self) { + assert(self != NULL); + Object *obj = self; if(obj) { @@ -18,6 +20,8 @@ void Object_destroy(void *self) void Object_describe(void *self) { + assert(self != NULL); + Object *obj = self; printf("%s\n", obj->description); } @@ -25,6 +29,8 @@ void Object_describe(void *self) int Object_init(void *self) { + assert(self != NULL); + // do nothing really return 1; } @@ -32,6 +38,9 @@ int Object_init(void *self) void *Object_move(void *self, Direction direction) { + assert(self != NULL); + assert(direction); + printf("You can't go that direction.\n"); return NULL; } @@ -39,6 +48,9 @@ void *Object_move(void *self, Direction direction) int Object_attack(void *self, int damage) { + assert(self != NULL); + assert(damage); + printf("You can't attack that.\n"); return 0; } @@ -46,7 +58,9 @@ int Object_attack(void *self, int damage) void *Object_new(size_t size, Object proto, char *description) { + assert(size); assert(description != NULL); + // setup the default functions in case they aren't set if(!proto.init) proto.init = Object_init; if(!proto.describe) proto.describe = Object_describe; @@ -62,6 +76,7 @@ void *Object_new(size_t size, Object proto, char *description) // copy the description over el->description = strdup(description); + assert(el->description != NULL); // initialize it with whatever init we were given if(!el->init(el)) { From 341d626870438ab85774e661bfb8e59f813fffd5 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 26 Oct 2011 04:21:16 -0400 Subject: [PATCH 092/145] Working through extra credit for ch20 ex19 --- .gitignore | 1 + Makefile | 6 +++- ex19.c | 10 +++---- ex19.mk | 12 ++++++-- object.c | 1 + test_ex19.sh | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 99 insertions(+), 8 deletions(-) create mode 100755 test_ex19.sh diff --git a/.gitignore b/.gitignore index 157050f..184c4f7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ !*.py !*.h !*.mk +!test_*.sh diff --git a/Makefile b/Makefile index 091111c..d060ed6 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,13 @@ all: $(EXERCISES) $(MAKE) -f ex19.mk +test: all + $(MAKE) -f ex19.mk test + + clean: rm -f $(EXERCISES) $(MAKE) -f ex19.mk clean -.PHONY: all clean +.PHONY: all test clean diff --git a/ex19.c b/ex19.c index 5acd311..1615261 100644 --- a/ex19.c +++ b/ex19.c @@ -46,7 +46,6 @@ Object MonsterProto = { void *Room_move(void *self, Direction direction) { assert(self != NULL); - assert(direction); Room *room = self; Room *next = NULL; @@ -70,6 +69,8 @@ void *Room_move(void *self, Direction direction) if(next) { next->_(describe)(next); + } else { + printf("mumble mumble.\n"); } return next; @@ -103,7 +104,6 @@ Object RoomProto = { void *Map_move(void *self, Direction direction) { assert(self != NULL); - assert(direction); Map *map = self; Room *location = map->location; @@ -113,6 +113,8 @@ void *Map_move(void *self, Direction direction) if(next) { map->location = next; + } else { + map->location = location; } return next; @@ -176,9 +178,6 @@ int process_input(Map *game) printf("\n> "); char ch = getchar(); - assert(ch != EOF); - getchar(); // eat ENTER - int damage = rand() % 4; switch(ch) { @@ -219,6 +218,7 @@ int process_input(Map *game) printf("What?: %d\n", ch); } + getchar(); // eat ENTER return 1; } diff --git a/ex19.mk b/ex19.mk index 96e5d90..ec75aa7 100644 --- a/ex19.mk +++ b/ex19.mk @@ -2,8 +2,16 @@ CFLAGS=-Wall -g all: ex19 + ex19: object.o + +test: + ./test_ex19.sh + + clean: - rm -f ex19 - rm -f object.o + rm -f ex19 object.o + + +.PHONY: all test clean diff --git a/object.c b/object.c index 268f169..63db33e 100644 --- a/object.c +++ b/object.c @@ -85,6 +85,7 @@ void *Object_new(size_t size, Object proto, char *description) return NULL; } else { // all done, we made an object of any type + assert(el != NULL); return el; } } diff --git a/test_ex19.sh b/test_ex19.sh new file mode 100755 index 0000000..6e2abb0 --- /dev/null +++ b/test_ex19.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +EXIT_CODE=0 + +run_test() +{ + echo -n " $1" + cat $2 | ./ex19 >/dev/null + if [[ $? -eq 0 ]] + then + echo " ... OK" + else + echo " ... FAIL" + EXIT_CODE=1 + fi + rm -f $2 +} + + +tmp_01=`mktemp` +cat > $tmp_01 < $tmp_02 < Date: Thu, 27 Oct 2011 21:14:28 -0400 Subject: [PATCH 093/145] Worked through ex20 --- Makefile | 2 +- dbg.h | 40 ++++++++++++++++++ ex19.mk | 2 +- ex20.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 dbg.h create mode 100644 ex20.c diff --git a/Makefile b/Makefile index d060ed6..8297ae6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-Wall -g +CFLAGS=-Wall -g -DNDEBUG EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | grep -v ex19)) diff --git a/dbg.h b/dbg.h new file mode 100644 index 0000000..e6edb38 --- /dev/null +++ b/dbg.h @@ -0,0 +1,40 @@ +#ifndef __dbg_h__ +#define __dbg_h__ + +#include +#include +#include + +#ifdef NDEBUG +#define debug(M, ...) +#else +#define debug(M, ...) \ + fprintf(stderr, "DEBUG %s:%d:[%s]: " M "\n", \ + __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) +#endif + +#define clean_errno() (errno == 0 ? "None" : strerror(errno)) + +#define log_err(M, ...) \ + fprintf(stderr, "[ERROR] (%s:%d:[%s]: errno: %s) " M "\n", \ + __FILE__, __LINE__, __FUNCTION__, clean_errno(), ##__VA_ARGS__) + +#define log_warn(M, ...) \ + fprintf(stderr, "[WARN] (%s:%d:[%s]: errno: %s) " M "\n", \ + __FILE__, __LINE__, __FUNCTION__, clean_errno(), ##__VA_ARGS__) + +#define log_info(M, ...) \ + fprintf(stderr, "[INFO] (%s:%d:[%s]: errno: %s) " M "\n", \ + __FILE__, __LINE__, __FUNCTION__, clean_errno(), ##__VA_ARGS__) + +#define check(A, M, ...) \ + if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; } + +#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); errno=0; goto error; } + +#define check_mem(A) check((A), "Out of memory.") + +#define check_debug(A, M, ...) \ + if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; } + +#endif diff --git a/ex19.mk b/ex19.mk index ec75aa7..edcde16 100644 --- a/ex19.mk +++ b/ex19.mk @@ -1,4 +1,4 @@ -CFLAGS=-Wall -g +CFLAGS := -Wall -g all: ex19 diff --git a/ex20.c b/ex20.c new file mode 100644 index 0000000..a89f6b6 --- /dev/null +++ b/ex20.c @@ -0,0 +1,125 @@ +#include "dbg.h" +#include +#include + + +void test_debug() +{ + // notice you don't need the \n + debug("I have Brown Hair."); + + // passing in arguments like printf + debug("I am %d years old.", 37); +} + + +void test_log_err() +{ + log_err("I believe everything is broken."); + log_err("There are %d problems in %s.", 0, "space"); +} + + +void test_log_warn() +{ + log_warn("You can safely ignore this."); + log_warn("Maybe consider looking at: %s", "/etc/passwd"); +} + + +void test_log_info() +{ + log_info("Well I did something mundane."); + log_info("It happened %f times today.", 1.3f); +} + + +int test_check(char *file_name) +{ + FILE *input = NULL; + char *block = NULL; + + block = malloc(100); + check_mem(block); // should work + + input = fopen(file_name, "r"); + check(input, "Failed to open %s.", file_name); + + free(block); + fclose(input); + return 0; + +error: + if(block) free(block); + if(input) fclose(input); + return -1; +} + + +int test_sentinel(int code) +{ + char *temp = malloc(100); + check_mem(temp); + + switch(code) { + case 1: + log_info("It worked."); + break; + default: + sentinel("I shouldn't run."); + } + + free(temp); + return 0; + +error: + if(temp) free(temp); + return -1; +} + + +int test_check_mem() +{ + char *test = NULL; + check_mem(test); + + free(test); + return 1; + +error: + return -1; +} + + +int test_check_debug() +{ + int i = 0; + check_debug(i != 0, "Oops, I was 0."); + + return 0; +error: + return -1; +} + + +int main(int argc, char *argv[]) +{ + check(argc == 2, "Need an argument."); + + test_debug(); + test_log_err(); + test_log_warn(); + test_log_info(); + + check(test_check("ex20.c") == 0, "failed with ex20.c"); + check(test_check(argv[1]) == -1, "failed with argv"); + check(test_sentinel(1) == 0, "test_sentinel failed."); + check(test_sentinel(100) == -1, "test_sentinel failed."); + check(test_check_mem() == -1, "test_check_mem failed."); + check(test_check_debug() == -1, "test_check_debug failed."); + + return 0; + +error: + return 1; +} From 991a9f26b49e9a163b90a2f2540a426e85eaa6e8 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 28 Oct 2011 08:23:31 -0400 Subject: [PATCH 094/145] Printing out some type sizes while working through ex21 --- ex21.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 ex21.c diff --git a/ex21.c b/ex21.c new file mode 100644 index 0000000..29baa51 --- /dev/null +++ b/ex21.c @@ -0,0 +1,18 @@ +#include +#include + + +int main(int argc, char *argv[]) +{ + printf("sizeof(int8_t) = %d\n", sizeof(int8_t)); + printf("sizeof(uint8_t) = %d\n", sizeof(uint8_t)); + printf("sizeof(int16_t) = %d\n", sizeof(int16_t)); + printf("sizeof(uint16_t) = %d\n", sizeof(uint16_t)); + printf("sizeof(int32_t) = %d\n", sizeof(int32_t)); + printf("sizeof(uint32_t) = %d\n", sizeof(uint32_t)); + printf("sizeof(int64_t) = %d\n", sizeof(int64_t)); + printf("sizeof(uint64_t) = %d\n", sizeof(uint64_t)); + + + return 0; +} From 59d68e04c8f09f5c3424c07ff549ff22ad994305 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 28 Oct 2011 08:28:12 -0400 Subject: [PATCH 095/145] Printing out more values defined in stdint.h --- ex21.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ex21.c b/ex21.c index 29baa51..cf032cb 100644 --- a/ex21.c +++ b/ex21.c @@ -10,9 +10,24 @@ int main(int argc, char *argv[]) printf("sizeof(uint16_t) = %d\n", sizeof(uint16_t)); printf("sizeof(int32_t) = %d\n", sizeof(int32_t)); printf("sizeof(uint32_t) = %d\n", sizeof(uint32_t)); +#if defined(_M_X64) || defined(__amd64__) printf("sizeof(int64_t) = %d\n", sizeof(int64_t)); printf("sizeof(uint64_t) = %d\n", sizeof(uint64_t)); +#endif + printf("INT8_MAX = %d\n", INT8_MAX); + printf("INT16_MAX = %d\n", INT16_MAX); + printf("INT32_MAX = %d\n", INT32_MAX); +#if defined(_M_X64) || defined(__amd64__) + printf("INT64_MAX = %d\n", INT64_MAX); +#endif + + printf("INT8_MIN = %d\n", INT8_MIN); + printf("INT16_MIN = %d\n", INT16_MIN); + printf("INT32_MIN = %d\n", INT32_MIN); +#if defined(_M_X64) || defined(__amd64__) + printf("INT64_MIN = %d\n", INT64_MIN); +#endif return 0; } From 418a1264c6f593516c2820033cf23baaf368fbd6 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 28 Oct 2011 08:34:28 -0400 Subject: [PATCH 096/145] Yet more printing of type sizes (no surprises yet). --- ex21.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ex21.c b/ex21.c index cf032cb..767bf2f 100644 --- a/ex21.c +++ b/ex21.c @@ -29,5 +29,19 @@ int main(int argc, char *argv[]) printf("INT64_MIN = %d\n", INT64_MIN); #endif + printf("sizeof(int_least8_t) = %d\n", sizeof(int_least8_t)); + printf("sizeof(int_least16_t) = %d\n", sizeof(int_least16_t)); + printf("sizeof(int_least32_t) = %d\n", sizeof(int_least32_t)); +#if defined(_M_X64) || defined(__amd64__) + printf("sizeof(int_least64_t) = %d\n", sizeof(int_least64_t)); +#endif + + printf("sizeof(uint_least8_t) = %d\n", sizeof(uint_least8_t)); + printf("sizeof(uint_least16_t) = %d\n", sizeof(uint_least16_t)); + printf("sizeof(uint_least32_t) = %d\n", sizeof(uint_least32_t)); +#if defined(_M_X64) || defined(__amd64__) + printf("sizeof(uint_least64_t) = %d\n", sizeof(uint_least64_t)); +#endif + return 0; } From 86d78ce3335fe66b39d4cd813f22688c44fd5c77 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 1 Nov 2011 08:03:40 -0400 Subject: [PATCH 097/145] Printing out a bunch more sizes for ex21. --- ex21.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/ex21.c b/ex21.c index 767bf2f..a170b9d 100644 --- a/ex21.c +++ b/ex21.c @@ -43,5 +43,82 @@ int main(int argc, char *argv[]) printf("sizeof(uint_least64_t) = %d\n", sizeof(uint_least64_t)); #endif + printf("INT_LEAST8_MAX = %d\n", INT_LEAST8_MAX); + printf("INT_LEAST16_MAX = %d\n", INT_LEAST16_MAX); + printf("INT_LEAST32_MAX = %d\n", INT_LEAST32_MAX); +#if defined(_M_X64) || defined(__amd64__) + printf("INT_LEAST64_MAX = %d\n", INT_LEAST64_MAX); +#endif + + printf("INT_LEAST8_MIN = %d\n", INT_LEAST8_MIN); + printf("INT_LEAST16_MIN = %d\n", INT_LEAST16_MIN); + printf("INT_LEAST32_MIN = %d\n", INT_LEAST32_MIN); +#if defined(_M_X64) || defined(__amd64__) + printf("INT_LEAST64_MIN = %d\n", INT_LEAST64_MIN); +#endif + + printf("UINT_LEAST8_MAX = %d\n", UINT_LEAST8_MAX); + printf("UINT_LEAST16_MAX = %d\n", UINT_LEAST16_MAX); + printf("UINT_LEAST32_MAX = %d\n", UINT_LEAST32_MAX); +#if defined(_M_X64) || defined(__amd64__) + printf("UINT_LEAST64_MAX = %d\n", UINT_LEAST64_MAX); +#endif + + printf("sizeof(int_fast8_t) = %d\n", sizeof(int_fast8_t)); + printf("sizeof(int_fast16_t) = %d\n", sizeof(int_fast16_t)); + printf("sizeof(int_fast32_t) = %d\n", sizeof(int_fast32_t)); +#if defined(_M_X64) || defined(__amd64__) + printf("sizeof(int_fast64_t) = %d\n", sizeof(int_fast64_t)); +#endif + + printf("sizeof(uint_fast8_t) = %d\n", sizeof(uint_fast8_t)); + printf("sizeof(uint_fast16_t) = %d\n", sizeof(uint_fast16_t)); + printf("sizeof(uint_fast32_t) = %d\n", sizeof(uint_fast32_t)); +#if defined(_M_X64) || defined(__amd64__) + printf("sizeof(uint_fast64_t) = %d\n", sizeof(uint_fast64_t)); +#endif + + printf("INT_FAST8_MAX = %d\n", INT_FAST8_MAX); + printf("INT_FAST16_MAX = %d\n", INT_FAST16_MAX); + printf("INT_FAST32_MAX = %d\n", INT_FAST32_MAX); +#if defined(_M_X64) || defined(__amd64__) + printf("INT_FAST64_MAX = %d\n", INT_FAST64_MAX); +#endif + + printf("INT_FAST8_MAX = %d\n", INT_FAST8_MAX); + printf("INT_FAST16_MAX = %d\n", INT_FAST16_MAX); + printf("INT_FAST32_MAX = %d\n", INT_FAST32_MAX); +#if defined(_M_X64) || defined(__amd64__) + printf("INT_FAST64_MAX = %d\n", INT_FAST64_MAX); +#endif + + printf("INT_FAST8_MIN = %d\n", INT_FAST8_MIN); + printf("INT_FAST16_MIN = %d\n", INT_FAST16_MIN); + printf("INT_FAST32_MIN = %d\n", INT_FAST32_MIN); +#if defined(_M_X64) || defined(__amd64__) + printf("INT_FAST64_MIN = %d\n", INT_FAST64_MIN); +#endif + + printf("UINT_FAST8_MAX = %d\n", UINT_FAST8_MAX); + printf("UINT_FAST16_MAX = %d\n", UINT_FAST16_MAX); + printf("UINT_FAST32_MAX = %d\n", UINT_FAST32_MAX); +#if defined(_M_X64) || defined(__amd64__) + printf("UINT_FAST64_MAX = %d\n", UINT_FAST64_MAX); +#endif + + printf("sizeof(intptr_t) = %d\n", sizeof(intptr_t)); + printf("sizeof(uintptr_t) = %d\n", sizeof(uintptr_t)); + printf("INTPTR_MAX = %d\n", INTPTR_MAX); + printf("INTPTR_MIN = %d\n", INTPTR_MIN); + printf("UINTPTR_MAX = %d\n", UINTPTR_MAX); + printf("sizeof(intmax_t) = %d\n", sizeof(intmax_t)); + printf("sizeof(uintmax_t) = %d\n", sizeof(uintmax_t)); + printf("INTMAX_MAX = %d\n", INTMAX_MAX); + printf("INTMAX_MIN = %d\n", INTMAX_MIN); + printf("UINTMAX_MAX = %d\n", UINTMAX_MAX); + printf("PTRDIFF_MIN = %d\n", PTRDIFF_MIN); + printf("PTRDIFF_MAX = %d\n", PTRDIFF_MAX); + printf("SIZE_MAX = %d\n", SIZE_MAX); + return 0; } From c2615babf7096a67590b1a72db88441aca7178f1 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 1 Nov 2011 08:06:00 -0400 Subject: [PATCH 098/145] Fixing some compiler warnings. --- ex21.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ex21.c b/ex21.c index a170b9d..695e1c4 100644 --- a/ex21.c +++ b/ex21.c @@ -113,9 +113,9 @@ int main(int argc, char *argv[]) printf("UINTPTR_MAX = %d\n", UINTPTR_MAX); printf("sizeof(intmax_t) = %d\n", sizeof(intmax_t)); printf("sizeof(uintmax_t) = %d\n", sizeof(uintmax_t)); - printf("INTMAX_MAX = %d\n", INTMAX_MAX); - printf("INTMAX_MIN = %d\n", INTMAX_MIN); - printf("UINTMAX_MAX = %d\n", UINTMAX_MAX); + printf("INTMAX_MAX = %lld\n", INTMAX_MAX); + printf("INTMAX_MIN = %lld\n", INTMAX_MIN); + printf("UINTMAX_MAX = %lld\n", UINTMAX_MAX); printf("PTRDIFF_MIN = %d\n", PTRDIFF_MIN); printf("PTRDIFF_MAX = %d\n", PTRDIFF_MAX); printf("SIZE_MAX = %d\n", SIZE_MAX); From 877763c15c021d6bf27404d1e61a1909d62eff59 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 1 Nov 2011 21:16:22 -0400 Subject: [PATCH 099/145] Starting to work through ch23 ex22 --- ex22.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 ex22.h diff --git a/ex22.h b/ex22.h new file mode 100644 index 0000000..bc894b0 --- /dev/null +++ b/ex22.h @@ -0,0 +1,16 @@ +#ifndef _ex22_h +#define _ex22_h + +// makes THE_SIZE in ex22.c available to other .c files +extern int THE_SIZE; + +// gets and sets an internal static variable in ex22.c +int get_age(); +void set_age(int age); + +// updates a static variable that's inside update_ratio +double update_ratio(double ratio); + +void print_size(); + +#endif From f2110a5d13f4f1819b7755d0ee79dd63d361f35c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 1 Nov 2011 21:56:34 -0400 Subject: [PATCH 100/145] Working version of ex22 --- Makefile | 9 +++++++-- ex22.c | 35 +++++++++++++++++++++++++++++++++ ex22.h | 2 +- ex22_main.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 ex22.c create mode 100644 ex22_main.c diff --git a/Makefile b/Makefile index 8297ae6..e690e0e 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,17 @@ CFLAGS=-Wall -g -DNDEBUG -EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | grep -v ex19)) +EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | egrep -v "ex(19|22)")) -all: $(EXERCISES) +all: $(EXERCISES) ex22_main $(MAKE) -f ex19.mk +ex22_main: ex22.c ex22_main.c ex22.h + $(CC) $(CFLAGS) -c -o ex22.o ex22.c + $(CC) $(CFLAGS) ex22_main.c ex22.o -o $@ + + test: all $(MAKE) -f ex19.mk test diff --git a/ex22.c b/ex22.c new file mode 100644 index 0000000..922ec89 --- /dev/null +++ b/ex22.c @@ -0,0 +1,35 @@ +#include +#include "ex22.h" +#include "dbg.h" + +int THE_SIZE = 1000; + +static int THE_AGE = 37; + + +int get_age() +{ + return THE_AGE; +} + + +void set_age(int age) +{ + THE_AGE = age; +} + + +double update_ratio(double new_ratio) +{ + static double ratio = 1.0; + + double old_ratio = ratio; + ratio = new_ratio; + + return old_ratio; +} + +void print_size() +{ + log_info("I think size is: %d", THE_SIZE); +} diff --git a/ex22.h b/ex22.h index bc894b0..01b93ff 100644 --- a/ex22.h +++ b/ex22.h @@ -2,7 +2,7 @@ #define _ex22_h // makes THE_SIZE in ex22.c available to other .c files -extern int THE_SIZE; +int THE_SIZE; // gets and sets an internal static variable in ex22.c int get_age(); diff --git a/ex22_main.c b/ex22_main.c new file mode 100644 index 0000000..39502e5 --- /dev/null +++ b/ex22_main.c @@ -0,0 +1,56 @@ +#include "ex22.h" +#include "dbg.h" + +const char *MY_NAME = "Zed A. Shaw"; + + +void scope_demo(int count) +{ + log_info("count is: %d", count); + + if(count > 10) { + int count = 100; // BAD! BUGS! + + log_info("count in this scope is %d", count); + } + + log_info("count is at exit: %d", count); + + count = 3000; + + log_info("count after assign: %d", count); +} + + +int main(int argc, char *argv[]) +{ + // test out THE_AGE accessors + log_info("My name: %s, age: %d", MY_NAME, get_age()); + + set_age(100); + + log_info("My age is now: %d", get_age()); + + // test out THE_SIZE extern + log_info("THE_SIZE is: %d", THE_SIZE); + print_size(); + + THE_SIZE = 9; + + log_info("THE_SIZE is now: %d", THE_SIZE); + print_size(); + + // test the ratio function static + log_info("Ratio at first: %f", update_ratio(2.0)); + log_info("Ratio again: %f", update_ratio(10.0)); + log_info("Ratio once more: %f", update_ratio(300.0)); + + // test the scope demo + int count = 4; + scope_demo(count); + scope_demo(count * 20); + + log_info("count after calling scope_demo: %d", count); + + return 0; +} From 316ce7f8bee2529fb3bb023104e44bb56dc3ee94 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 1 Nov 2011 22:05:27 -0400 Subject: [PATCH 101/145] cleaning up makefile stuff for ex22 --- Makefile | 9 +++------ ex22.mk | 10 ++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 ex22.mk diff --git a/Makefile b/Makefile index e690e0e..1ddb5c8 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,9 @@ CFLAGS=-Wall -g -DNDEBUG EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | egrep -v "ex(19|22)")) -all: $(EXERCISES) ex22_main +all: $(EXERCISES) $(MAKE) -f ex19.mk - - -ex22_main: ex22.c ex22_main.c ex22.h - $(CC) $(CFLAGS) -c -o ex22.o ex22.c - $(CC) $(CFLAGS) ex22_main.c ex22.o -o $@ + $(MAKE) -f ex22.mk test: all @@ -19,6 +15,7 @@ test: all clean: rm -f $(EXERCISES) $(MAKE) -f ex19.mk clean + $(MAKE) -f ex22.mk clean .PHONY: all test clean diff --git a/ex22.mk b/ex22.mk new file mode 100644 index 0000000..4f22c3b --- /dev/null +++ b/ex22.mk @@ -0,0 +1,10 @@ +all: ex22_main + + +ex22_main: ex22_main.o ex22.o + + +clean: + rm -f ex22_main ex22.o ex22_main.o + +.PHONY: all clean From 601f722221ad4e5bb81e86b0d33b700a46dd42bf Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 4 Nov 2011 00:01:16 -0400 Subject: [PATCH 102/145] doing extra credit for ch23 ex22 --- ex22.mk | 2 +- ex22_ec1.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 ex22_ec1.c diff --git a/ex22.mk b/ex22.mk index 4f22c3b..e726f51 100644 --- a/ex22.mk +++ b/ex22.mk @@ -1,4 +1,4 @@ -all: ex22_main +all: ex22_main ex22_ec1 ex22_main: ex22_main.o ex22.o diff --git a/ex22_ec1.c b/ex22_ec1.c new file mode 100644 index 0000000..995c23b --- /dev/null +++ b/ex22_ec1.c @@ -0,0 +1,28 @@ +#include +#include "dbg.h" + + +int pass_by_value(int n) +{ + n = n + 2; + return n; +} + + +int pass_by_reference(int *n) +{ + *n = *n + 8; + return *n; +} + + +int main(int argc, char *argv[]) +{ + int n = 2; + log_info("BEGIN: n = %d", n); + log_info("By value example: %d", pass_by_value(n)); + log_info("n = %d", n); + log_info("By reference example: %d", pass_by_reference(&n)); + log_info("n = %d", n); + return 0; +} From c8233ae231705756ca79c3ee00c7f3b3722660dc Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 4 Nov 2011 08:24:07 -0400 Subject: [PATCH 103/145] Minor (silly) change to output --- ex22_ec1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex22_ec1.c b/ex22_ec1.c index 995c23b..c86c33b 100644 --- a/ex22_ec1.c +++ b/ex22_ec1.c @@ -19,7 +19,7 @@ int pass_by_reference(int *n) int main(int argc, char *argv[]) { int n = 2; - log_info("BEGIN: n = %d", n); + log_info("n = %d", n); log_info("By value example: %d", pass_by_value(n)); log_info("n = %d", n); log_info("By reference example: %d", pass_by_reference(&n)); From 22c3d7369216b8478e2f664335e67302b07ee0f6 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 4 Nov 2011 08:43:16 -0400 Subject: [PATCH 104/145] Using pointers to access previously sheltered variables --- ex22.c | 17 +++++++++++++++++ ex22.h | 2 ++ ex22_main.c | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/ex22.c b/ex22.c index 922ec89..df5612c 100644 --- a/ex22.c +++ b/ex22.c @@ -13,12 +13,29 @@ int get_age() } +int *get_age_pointer() +{ + return &THE_AGE; +} + + void set_age(int age) { THE_AGE = age; } +double *get_function_static(double to_add) +{ + static double value = 1.0; + + double old = value; + value = value + to_add; + + return &value; +} + + double update_ratio(double new_ratio) { static double ratio = 1.0; diff --git a/ex22.h b/ex22.h index 01b93ff..c89665f 100644 --- a/ex22.h +++ b/ex22.h @@ -6,6 +6,8 @@ int THE_SIZE; // gets and sets an internal static variable in ex22.c int get_age(); +int * get_age_pointer(); +double * get_function_static(double); void set_age(int age); // updates a static variable that's inside update_ratio diff --git a/ex22_main.c b/ex22_main.c index 39502e5..7b608e2 100644 --- a/ex22_main.c +++ b/ex22_main.c @@ -31,6 +31,13 @@ int main(int argc, char *argv[]) log_info("My age is now: %d", get_age()); + int new_age = 44; + log_info("Setting age directly to %d", new_age); + int *age = get_age_pointer(); + *age = new_age; + + log_info("My age is now: %d", get_age()); + // test out THE_SIZE extern log_info("THE_SIZE is: %d", THE_SIZE); print_size(); @@ -45,6 +52,15 @@ int main(int argc, char *argv[]) log_info("Ratio again: %f", update_ratio(10.0)); log_info("Ratio once more: %f", update_ratio(300.0)); + // accessing a function static + double *func_static_value = get_function_static(4.0); + log_info("get_function_static(4.0) = %.1f", *func_static_value); + double new_func_static_value = 8.0; + log_info("Setting the function static var directly to %.1f", + new_func_static_value); + *func_static_value = new_func_static_value; + log_info("get_function_static(4.0) = %.1f", *get_function_static(4.0)); + // test the scope demo int count = 4; scope_demo(count); From 566a7584d728655a37c27d46449fc06544b6c74c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 4 Nov 2011 09:02:59 -0400 Subject: [PATCH 105/145] First version of ch24 ex23.c --- ex23.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 ex23.c diff --git a/ex23.c b/ex23.c new file mode 100644 index 0000000..a6f373a --- /dev/null +++ b/ex23.c @@ -0,0 +1,113 @@ +#include +#include +#include "dbg.h" + + +int normal_copy(char *from, char *to, int count) +{ + int i = 0; + + for(i = 0; i < count; i++) { + to[i] = from[i]; + } + + return i; +} + + +int duffs_device(char *from, char *to, int count) +{ + { + int n = (count + 7) / 8; + + switch(count % 8) { + case 0: do { *to++ = *from++; + case 7: *to++ = *from++; + case 6: *to++ = *from++; + case 5: *to++ = *from++; + case 4: *to++ = *from++; + case 3: *to++ = *from++; + case 2: *to++ = *from++; + case 1: *to++ = *from++; + } while(--n > 0); + } + } + + return count; +} + +int zeds_device(char *from, char *to, int count) +{ + { + int n = (count + 7) / 8; + + switch(count % 8) { + case 0: + again: *to++ = *from++; + case 7: *to++ = *from++; + case 6: *to++ = *from++; + case 5: *to++ = *from++; + case 4: *to++ = *from++; + case 3: *to++ = *from++; + case 2: *to++ = *from++; + case 1: *to++ = *from++; + if(--n > 0) goto again; + } + } + + return count; +} + + +int valid_copy(char *data, int count, char expects) +{ + int i = 0; + for(i = 0; i < count; i++) { + if(data[i] != expects) { + log_err("[%d] %c != %c", i, data[i], expects); + return 0; + } + } + + return 1; +} + + +int main(int argc, char *argv[]) +{ + char from[1000] = {'a'}; + char to[1000] = {'c'}; + int rc = 0; + + // setup the from to have some stuff + memset(from, 'x', 1000); + // set it to a failure mode + memset(to, 'y', 1000); + check(valid_copy(to, 1000, 'y'), "Not initialized right."); + + // use normal copy to + rc = normal_copy(from, to, 1000); + check(rc == 1000, "Normal copy failed: %d", rc); + check(valid_copy(to, 1000, 'x'), "Normal copy failed"); + + // reset + memset(to, 'y', 1000); + + // duffs version + rc = duffs_device(from, to, 1000); + check(rc == 1000, "Duff's device failed: %d", rc); + check(valid_copy(to, 1000, 'x'), "Duff's device failed copy."); + + // reset + memset(to, 'y', 1000); + + // my version + rc = zeds_device(from, to, 1000); + check(rc == 1000, "Zed's device failed: %d", rc); + check(valid_copy(to, 1000, 'x'), "Zed's device failed copy."); + + log_info("DING!"); + return 0; +error: + return 1; +} From 0a6404f838bd9e72d68dc8962f9e9af3c28fa089 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 6 Nov 2011 08:12:39 -0500 Subject: [PATCH 106/145] First working version of ch25 ex24.c --- ex24.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 ex24.c diff --git a/ex24.c b/ex24.c new file mode 100644 index 0000000..5f4033d --- /dev/null +++ b/ex24.c @@ -0,0 +1,66 @@ +#include +#include "dbg.h" + +#define MAX_DATA 100 + +typedef enum EyeColor { + BLUE_EYES, GREEN_EYES, BROWN_EYES, + BLACK_EYES, OTHER_EYES +} EyeColor; + +const char *EYE_COLOR_NAMES[] = { + "Blue", "Green", "Brown", "Black", "Other" +}; + +typedef struct Person { + int age; + char first_name[MAX_DATA]; + char last_name[MAX_DATA]; + EyeColor eyes; + float income; +} Person; + + +int main(int argc, char *argv[]) +{ + Person you = {.age = 0}; + int i = 0; + char *in = NULL; + + printf("What's your First Name? "); + in = fgets(you.first_name, MAX_DATA-1, stdin); + check(in != NULL, "Failed to read first name."); + + printf("What's your Last Name? "); + in = fgets(you.last_name, MAX_DATA-1, stdin); + check(in != NULL, "Failed to read last name."); + + printf("How old are you? "); + fscanf(stdin, "%d", &you.age); + + printf("What color are your eyes:\n"); + for(i = 0; i <= OTHER_EYES; i++) { + printf("%d) %s\n", i+1, EYE_COLOR_NAMES[i]); + } + printf("> "); + + int eyes = -1; + fscanf(stdin, "%d", &eyes); + check(eyes <= OTHER_EYES && eyes > 0, "Do it right, that's not an option."); + you.eyes = eyes - 1; + + printf("How much do you make an hour? "); + fscanf(stdin, "%f", &you.income); + + printf("----- RESULTS -----\n"); + printf("First Name: %s", you.first_name); + printf("Last Name: %s", you.last_name); + printf("Age: %d\n", you.age); + printf("Eyes: %s\n", EYE_COLOR_NAMES[you.eyes]); + printf("Income: %f\n", you.income); + + return 0; +error: + + return -1; +} From afc7edba4059848ed4504c177ca84b9718f03852 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 6 Nov 2011 08:15:32 -0500 Subject: [PATCH 107/145] Busted version of ex24.c with fscanf instead of fgets --- ex24.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex24.c b/ex24.c index 5f4033d..a36fc97 100644 --- a/ex24.c +++ b/ex24.c @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) char *in = NULL; printf("What's your First Name? "); - in = fgets(you.first_name, MAX_DATA-1, stdin); + in = fscanf(stdin, "%50s", you.first_name); check(in != NULL, "Failed to read first name."); printf("What's your Last Name? "); From a0ebd0b5879956eaa8eb8694419a5f8a4a66cfd7 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 6 Nov 2011 09:16:12 -0500 Subject: [PATCH 108/145] Setting back to proper version of ex24.c --- ex24.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex24.c b/ex24.c index a36fc97..5f4033d 100644 --- a/ex24.c +++ b/ex24.c @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) char *in = NULL; printf("What's your First Name? "); - in = fscanf(stdin, "%50s", you.first_name); + in = fgets(you.first_name, MAX_DATA-1, stdin); check(in != NULL, "Failed to read first name."); printf("What's your Last Name? "); From 6f8c69f763e9a08bf42672d944df24c759d0966c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 6 Nov 2011 09:19:25 -0500 Subject: [PATCH 109/145] Crappy version using gets instead of fgets --- ex24.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ex24.c b/ex24.c index 5f4033d..3d7f4a8 100644 --- a/ex24.c +++ b/ex24.c @@ -28,11 +28,11 @@ int main(int argc, char *argv[]) char *in = NULL; printf("What's your First Name? "); - in = fgets(you.first_name, MAX_DATA-1, stdin); + in = gets(you.first_name); check(in != NULL, "Failed to read first name."); printf("What's your Last Name? "); - in = fgets(you.last_name, MAX_DATA-1, stdin); + in = gets(you.last_name); check(in != NULL, "Failed to read last name."); printf("How old are you? "); From 74e3d00e4450c77a9fe4c82e659ee5a901fa4976 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 6 Nov 2011 09:23:44 -0500 Subject: [PATCH 110/145] Setting back to correct version using fgets --- ex24.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ex24.c b/ex24.c index 3d7f4a8..5f4033d 100644 --- a/ex24.c +++ b/ex24.c @@ -28,11 +28,11 @@ int main(int argc, char *argv[]) char *in = NULL; printf("What's your First Name? "); - in = gets(you.first_name); + in = fgets(you.first_name, MAX_DATA-1, stdin); check(in != NULL, "Failed to read first name."); printf("What's your Last Name? "); - in = gets(you.last_name); + in = fgets(you.last_name, MAX_DATA-1, stdin); check(in != NULL, "Failed to read last name."); printf("How old are you? "); From 340b1f207d9d20602e2f59dad70db90ebad8bdf7 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 6 Nov 2011 17:04:46 -0500 Subject: [PATCH 111/145] Using atoi and strtod instead of fscanf --- ex24.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ex24.c b/ex24.c index 5f4033d..67b4dd6 100644 --- a/ex24.c +++ b/ex24.c @@ -1,3 +1,4 @@ +#include #include #include "dbg.h" @@ -26,6 +27,7 @@ int main(int argc, char *argv[]) Person you = {.age = 0}; int i = 0; char *in = NULL; + char tmp[MAX_DATA]; printf("What's your First Name? "); in = fgets(you.first_name, MAX_DATA-1, stdin); @@ -36,7 +38,10 @@ int main(int argc, char *argv[]) check(in != NULL, "Failed to read last name."); printf("How old are you? "); - fscanf(stdin, "%d", &you.age); + in = fgets(tmp, MAX_DATA-1, stdin); + check(in != NULL, "Failed to read age."); + you.age = atoi(tmp); + check(you.age != -1, "Failed to convert age to int."); printf("What color are your eyes:\n"); for(i = 0; i <= OTHER_EYES; i++) { @@ -45,12 +50,17 @@ int main(int argc, char *argv[]) printf("> "); int eyes = -1; - fscanf(stdin, "%d", &eyes); + in = fgets(tmp, MAX_DATA-1, stdin); + check(in != NULL, "Failed to read eye color selection."); + eyes = atoi(tmp); check(eyes <= OTHER_EYES && eyes > 0, "Do it right, that's not an option."); you.eyes = eyes - 1; printf("How much do you make an hour? "); - fscanf(stdin, "%f", &you.income); + in = fgets(tmp, MAX_DATA-1, stdin); + check(in != NULL, "Failed to read income."); + you.income = strtod(tmp, NULL); + check(you.income != -1, "Failed to convert income."); printf("----- RESULTS -----\n"); printf("First Name: %s", you.first_name); From 912eb6a143c81dd26c13abd17846cefeea814d84 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 8 Nov 2011 08:21:40 -0500 Subject: [PATCH 112/145] Working through usages of all I/O functions whil in chapter 25 --- ex24_iofunctions.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 ex24_iofunctions.c diff --git a/ex24_iofunctions.c b/ex24_iofunctions.c new file mode 100644 index 0000000..c20a7a7 --- /dev/null +++ b/ex24_iofunctions.c @@ -0,0 +1,19 @@ +#include +#include "dbg.h" + + +int main(int argc, char *argv[]) +{ + printf("Reading from stdin: \n"); + int a, b, rc; + char c; + rc = fscanf(stdin, "%d %d %c", &a, &b, &c); + check(rc == 3, "Failed to read from stdin."); + + printf("Read in: a=%d b=%d c=%c\n", a, b, c); + + return 0; + +error: + return 1; +} From b5b0213c5d42ec55b6b8e903bd350654f3f02643 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 10 Nov 2011 19:56:32 -0500 Subject: [PATCH 113/145] Working on more example usages of io functions for ch25 --- ex24_iofunctions.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/ex24_iofunctions.c b/ex24_iofunctions.c index c20a7a7..0cd249c 100644 --- a/ex24_iofunctions.c +++ b/ex24_iofunctions.c @@ -2,16 +2,56 @@ #include "dbg.h" -int main(int argc, char *argv[]) +int fscanf_example01() { - printf("Reading from stdin: \n"); int a, b, rc; char c; + printf("Reading from stdin: \n> "); rc = fscanf(stdin, "%d %d %c", &a, &b, &c); check(rc == 3, "Failed to read from stdin."); printf("Read in: a=%d b=%d c=%c\n", a, b, c); + return 1; + +error: + return 0; +} + + +int fscanf_example02() +{ + int a, b, rc; + char c; + char filename[1024]; + FILE *fp; + + printf("Provide filename from which to inputs\n> "); + rc = fscanf(stdin, "%s", filename); + check(rc == 1, "Failed to read filename"); + fp = fopen(filename, "r"); + check(fp != NULL, "Failed to open file %s", filename); + + printf("Reading from \"%s\": \n", filename); + rc = fscanf(fp, "%d %d %c", &a, &b, &c); + check(rc == 3, "Failed to read from \"%s\".", filename); + + printf("Read in: a=%d b=%d c=%c\n", a, b, c); + rc = fclose(fp); + check(rc != EOF, "Failed to close file \"%s\"", filename); + + return 1; + +error: + return 0; +} + + +int main(int argc, char *argv[]) +{ + check(fscanf_example01() == 1, "Fail!"); + check(fscanf_example02() == 1, "Fail!"); + return 0; error: From 2e0a5d5c993a1ae53b003dda0a04a5f464eefd39 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 11 Nov 2011 08:22:26 -0500 Subject: [PATCH 114/145] Breaking out ex24 iofunctions files and writing a shell-based test thingy --- .gitignore | 1 + Makefile | 1 + ex24_iofunctions01.c | 19 ++++++++ ex24_iofunctions.c => ex24_iofunctions02.c | 35 ++------------ test_ex19.sh | 18 +++---- test_ex24_iofunctions.sh | 56 ++++++++++++++++++++++ 6 files changed, 89 insertions(+), 41 deletions(-) create mode 100644 ex24_iofunctions01.c rename ex24_iofunctions.c => ex24_iofunctions02.c (52%) create mode 100755 test_ex24_iofunctions.sh diff --git a/.gitignore b/.gitignore index 184c4f7..5ba293d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ !*.h !*.mk !test_*.sh +!*-input diff --git a/Makefile b/Makefile index 1ddb5c8..03350c8 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ all: $(EXERCISES) test: all $(MAKE) -f ex19.mk test + ./test_ex24_iofunctions.sh clean: diff --git a/ex24_iofunctions01.c b/ex24_iofunctions01.c new file mode 100644 index 0000000..3de50fa --- /dev/null +++ b/ex24_iofunctions01.c @@ -0,0 +1,19 @@ +#include +#include "dbg.h" + + +int main(int argc, char *argv[]) +{ + int a, b, rc; + char c; + printf("Reading from stdin: \n> "); + rc = fscanf(stdin, "%d %d %c", &a, &b, &c); + check(rc == 3, "Failed to read from stdin."); + + printf("Read in: a=%d b=%d c=%c\n", a, b, c); + + return 0; + +error: + return 1; +} diff --git a/ex24_iofunctions.c b/ex24_iofunctions02.c similarity index 52% rename from ex24_iofunctions.c rename to ex24_iofunctions02.c index 0cd249c..e1e21db 100644 --- a/ex24_iofunctions.c +++ b/ex24_iofunctions02.c @@ -2,28 +2,11 @@ #include "dbg.h" -int fscanf_example01() +int main(int argc, char *argv[]) { int a, b, rc; char c; - printf("Reading from stdin: \n> "); - rc = fscanf(stdin, "%d %d %c", &a, &b, &c); - check(rc == 3, "Failed to read from stdin."); - - printf("Read in: a=%d b=%d c=%c\n", a, b, c); - - return 1; - -error: - return 0; -} - - -int fscanf_example02() -{ - int a, b, rc; - char c; - char filename[1024]; + char filename[1024 * 2]; FILE *fp; printf("Provide filename from which to inputs\n> "); @@ -32,7 +15,7 @@ int fscanf_example02() fp = fopen(filename, "r"); check(fp != NULL, "Failed to open file %s", filename); - printf("Reading from \"%s\": \n", filename); + printf("Reading from file: \n"); rc = fscanf(fp, "%d %d %c", &a, &b, &c); check(rc == 3, "Failed to read from \"%s\".", filename); @@ -40,18 +23,6 @@ int fscanf_example02() rc = fclose(fp); check(rc != EOF, "Failed to close file \"%s\"", filename); - return 1; - -error: - return 0; -} - - -int main(int argc, char *argv[]) -{ - check(fscanf_example01() == 1, "Fail!"); - check(fscanf_example02() == 1, "Fail!"); - return 0; error: diff --git a/test_ex19.sh b/test_ex19.sh index 6e2abb0..0455133 100755 --- a/test_ex19.sh +++ b/test_ex19.sh @@ -5,20 +5,20 @@ EXIT_CODE=0 run_test() { echo -n " $1" - cat $2 | ./ex19 >/dev/null - if [[ $? -eq 0 ]] + cat "$2" | ./ex19 >/dev/null + if [[ "$?" -eq "0" ]] then echo " ... OK" else echo " ... FAIL" EXIT_CODE=1 fi - rm -f $2 + rm -f "$2" } -tmp_01=`mktemp` -cat > $tmp_01 < "$tmp_01" < $tmp_02 < "$tmp_02" < "$out_tmp" + diff_out="$(mktemp)" + diff -u "$3" "$out_tmp" > "$diff_out" + diff_count="$(cat "$diff_out" | wc -l)" + if [[ "$?" == "0" ]] && [[ "$diff_count" == "0" ]] + then + echo " ... OK" + else + echo " ... FAIL" + echo " diff count => $diff_count" + cat "$diff_out" + EXIT_CODE=1 + fi + rm -f "$2" "$out_tmp" "$diff_out" +} + + +tmp_01="$(mktemp)" +cat > "$tmp_01" < "$expected_01" < +> Read in: a=2 b=8 c=n +EOF + +tmp_02="$(mktemp)" +tmp_02in="$(mktemp)" +cat > "$tmp_02in" < "$tmp_02" < "$expected_02" < Reading from file: +Read in: a=1 b=4 c=a +EOF + + +run_test '01' "$tmp_01" "$expected_01" +run_test '02' "$tmp_02" "$expected_02" + + +exit $EXIT_CODE From 11139d2f67e6362fe1ed51d8991ed3bc702b5a15 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 11 Nov 2011 08:58:43 -0500 Subject: [PATCH 115/145] Adding another io functions exercise for ch25 --- ex24_iofunctions03.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 ex24_iofunctions03.c diff --git a/ex24_iofunctions03.c b/ex24_iofunctions03.c new file mode 100644 index 0000000..6413fc4 --- /dev/null +++ b/ex24_iofunctions03.c @@ -0,0 +1,59 @@ +#include +#include "dbg.h" + +#define MAX_FILENAME 2048 + + +int main(int argc, char *argv[]) +{ + int rc = -1; + char *filename; + int nchars = 0; + int nlines = 0; + int i; + long seekpos; + char c; + FILE *fp; + + check(argc > 1, "You must provide a filename as arg 1"); + filename = argv[1]; + + fp = fopen(filename, "r"); + check(fp != NULL, "Failed to open \"%s\".", filename); + + while((c = fgetc(fp)) != EOF) { + nchars++; + if (c == '\n') { + nlines++; + if (nlines % 10 == 0) { + printf("At line %d of \"%s\"\n", nlines, filename); + } + } + } + + printf("\"%s\" contains %d chars\n", filename, nchars); + + printf("Current position of \"%s\" is %ld\n", filename, ftell(fp)); + printf("Writing out \"%s\" in reverse:\n", filename); + + for (i = 0; i < nchars; i++) { + seekpos = (long)nchars - (i + 1); + rc = fseek(fp, seekpos, SEEK_SET); + check(rc != -1, "Failed to seek to %ld", seekpos); + c = fgetc(fp); + check(c != EOF, "Failed to read char at %ld", seekpos); + putc(c, stdout); + } + + rewind(fp); + printf("\n\nRewound \"%s\" to position %ld\n", filename, ftell(fp)); + + rc = fclose(fp); + check(rc != -1, "Failed to close \"%s\".", filename); + + + return 1; + +error: + return 0; +} From 3b738faa655d8b62ef0d9336cc3f297cddcd372a Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 12 Nov 2011 10:35:59 -0500 Subject: [PATCH 116/145] Trying and failing to use `fcloseall`. --- ex24_iofunctions04.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 ex24_iofunctions04.c diff --git a/ex24_iofunctions04.c b/ex24_iofunctions04.c new file mode 100644 index 0000000..15e4608 --- /dev/null +++ b/ex24_iofunctions04.c @@ -0,0 +1,27 @@ +#define _GNU_SOURCE +#include +#include "dbg.h" + + +int main(int argc, char *argv[]) +{ + int rc = -1; + printf("This should be visible, I think.\n"); + + rc = fcloseall(); + check(rc == 0, "Failed to close all io streams."); + printf("I've used `fcloseall`, so this should not be visible, right?\n"); + + rc = fflush(stdout); + check(rc != EOF, "Failed to flush stdout."); + printf("Maybe we won't see anything after I explicitly `fflush(stdout)`?\n"); + + rc = fclose(stdout); + check(rc != EOF, "Failed to explicitly close stdout."); + printf("This had better not show up, right?\n"); + + return 0; + +error: + return 1; +} From b1260e7f5c172d5cf1fc4e5946560aab7a645f40 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 12 Nov 2011 10:40:00 -0500 Subject: [PATCH 117/145] adding a script to help me check for my uses of the io functions --- .gitignore | 3 ++- check-for-iofunctions.sh | 6 ++++++ iofunctions.txt | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100755 check-for-iofunctions.sh create mode 100644 iofunctions.txt diff --git a/.gitignore b/.gitignore index 5ba293d..d8e72e9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ !*.py !*.h !*.mk -!test_*.sh +!*.sh !*-input +!*.txt diff --git a/check-for-iofunctions.sh b/check-for-iofunctions.sh new file mode 100755 index 0000000..59d5f3e --- /dev/null +++ b/check-for-iofunctions.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for func in $(cat iofunctions.txt) +do + echo "$func: $(grep "$func" *.c | wc -l)" +done diff --git a/iofunctions.txt b/iofunctions.txt new file mode 100644 index 0000000..e9c7947 --- /dev/null +++ b/iofunctions.txt @@ -0,0 +1,14 @@ +fscanf +fgets +fopen +freopen +fdopen +fclose +fcloseall +fgetpos +fseek +ftell +rewind +fprintf +fwrite +fread From 1789da0d748475194859ece61699dfb5bc8d90d3 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 12 Nov 2011 11:05:16 -0500 Subject: [PATCH 118/145] Playing with freopen to redirect stdout. --- ex24_iofunctions05.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 ex24_iofunctions05.c diff --git a/ex24_iofunctions05.c b/ex24_iofunctions05.c new file mode 100644 index 0000000..d733709 --- /dev/null +++ b/ex24_iofunctions05.c @@ -0,0 +1,22 @@ +#include +#include "dbg.h" + + +int main(int argc, char *argv[]) +{ + FILE *fp; + char *filename; + check(argc == 2, "You must provide a filename for redirecting stdout."); + + filename = argv[1]; + fp = freopen(filename, "w", stdout); + check(fp != NULL, "Failed to reopen stdout as \"%s\"", filename); + + printf("This should be written to the file you specified!\n"); + + + return 0; + +error: + return 1; +} From e1a390dd081a83524e736d565818ae7401fcbbef Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 12 Nov 2011 13:43:44 -0500 Subject: [PATCH 119/145] One more exercise with IO functions. --- ex24_iofunctions06.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 ex24_iofunctions06.c diff --git a/ex24_iofunctions06.c b/ex24_iofunctions06.c new file mode 100644 index 0000000..3ae3cc7 --- /dev/null +++ b/ex24_iofunctions06.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "dbg.h" + + +int main(int argc, char *argv[]) +{ + int fd; + int rc; + long lrc; + char *out; + char buffer[1024]; + fpos_t pos; + FILE *instream; + FILE *outstream; + + check(argc == 2, "You must provide a filename."); + + fd = open(argv[1], O_RDWR | O_CREAT); + check(fd != -1, "Unable to open \"%s\" for reading and writing.", argv[1]); + + rc = fchmod(fd, 0644); + check(rc != -1, "Failed to chmod \"%s\"", argv[1]); + + outstream = fdopen(fd, "w"); + check(outstream != NULL, "Unable to open an outstream."); + + rc = fgetpos(outstream, &pos); + check(rc != -1, "Failed to get position of outstream."); + + rc = fprintf(outstream, "It was written."); + check(rc > 0, "Failed to write to outstream."); + + rc = fflush(outstream); + check(rc != EOF, "Failed to flush outstream."); + + rc = fsetpos(outstream, &pos); + check(rc != -1, "Failed to set outstream back to old position."); + + instream = fdopen(fd, "r"); + check(instream != NULL, "Unable to open an instream."); + + rewind(instream); + lrc = ftell(instream); + check(lrc == 0, "Failed to rewind instream."); + + out = fgets(buffer, 1023, instream); + check(buffer != NULL, "Failed to read from instream."); + + printf("Read this from instream: \"%s\"\n", buffer); + + return 0; +error: + return 1; +} From 21ecef64a6c8b2b0c5f1b802bbbc9b2693e15243 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 12 Nov 2011 20:20:28 -0500 Subject: [PATCH 120/145] First working version of ch26 ex25 --- ex25.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 ex25.c diff --git a/ex25.c b/ex25.c new file mode 100644 index 0000000..d940368 --- /dev/null +++ b/ex25.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include "dbg.h" + +#define MAX_DATA 100 + + +int read_string(char **out_string, int max_buffer) +{ + *out_string = calloc(1, max_buffer + 1); + check_mem(*out_string); + + char *result = fgets(*out_string, max_buffer, stdin); + check(result != NULL, "Input error."); + + return 0; + +error: + if(*out_string) free(*out_string); + *out_string = NULL; + return -1; +} + + +int read_int(int *out_int) +{ + char *input = NULL; + int rc = read_string(&input, MAX_DATA); + check(rc == 0, "Failed to read number."); + + *out_int = atoi(input); + + free(input); + return 0; + +error: + if(input) free(input); + return -1; +} + + +int read_scan(const char *fmt, ...) +{ + int i = 0; + int rc = 0; + int *out_int = NULL; + char *out_char = NULL; + char **out_string = NULL; + int max_buffer = 0; + + va_list argp; + va_start(argp, fmt); + + for(i = 0; fmt[i] != '\0'; i++) { + if(fmt[i] == '%') { + i++; + switch(fmt[i]) { + case '\0': + sentinel("Invalid format, you ended with %%."); + break; + + case 'd': + out_int = va_arg(argp, int *); + rc = read_int(out_int); + check(rc == 0, "Failed to read int."); + break; + + case 'c': + out_char = va_arg(argp, char *); + *out_char = fgetc(stdin); + break; + + case 's': + max_buffer = va_arg(argp, int); + out_string = va_arg(argp, char**); + rc = read_string(out_string, max_buffer); + check(rc == 0, "Failed to read string."); + break; + + default: + sentinel("Invalid format."); + } + } else { + fgetc(stdin); + } + + check(!feof(stdin) && !ferror(stdin), "Input error."); + } + + va_end(argp); + return 0; + +error: + va_end(argp); + return -1; +} + + +int main(int argc, char *argv[]) +{ + char *first_name = NULL; + char initial = ' '; + char *last_name = NULL; + int age = 0; + + printf("What's your first name? "); + int rc = read_scan("%s", MAX_DATA, &first_name); + check(rc == 0, "Failed first name."); + + printf("What's your initial? "); + rc = read_scan("%c\n", &initial); + check(rc == 0, "Failed initial."); + + printf("What's your last name? "); + rc = read_scan("%s", MAX_DATA, &last_name); + check(rc == 0, "Failed last name."); + + printf("How old are you? "); + rc = read_scan("%d", &age); + check(rc == 0, "Failed age."); + + printf("---- RESULTS ----\n"); + printf("First Name: %s", first_name); + printf("Initial: '%c'\n", initial); + printf("Last Name: %s", last_name); + printf("Age: %d\n", age); + + free(first_name); + free(last_name); + return 0; + +error: + return -1; +} From 499f82221a709f14fe983390e87b7c2cf6a42280 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 13 Nov 2011 09:40:48 -0500 Subject: [PATCH 121/145] Adding some fuzzing input for doing mem check stuff in ex25 --- ex25-fuzz-input | 1 + 1 file changed, 1 insertion(+) create mode 100644 ex25-fuzz-input diff --git a/ex25-fuzz-input b/ex25-fuzz-input new file mode 100644 index 0000000..8ae8399 --- /dev/null +++ b/ex25-fuzz-input @@ -0,0 +1 @@ +909 6LeaPin LizarDs1 170 202 SnArF61 LeaPin LizarDs 7LeaPin LizarDs2 39LeaPin LizarDs 710 6LeaPin LizarDs0 SnArF6LeaPin LizarDs 757 116 20 LeaPin LizarDs26 LeaPin LizarDsSnArF9 921 912 131 717 SnArF5SnArF 312 LeaPin LizarDsLeaPin LizarDs9 6LeaPin LizarDs7 731 9LeaPin LizarDs6 527 333 LeaPin LizarDsSnArFSnArF 77 LeaPin LizarDs3LeaPin LizarDs LeaPin LizarDsLeaPin LizarDs6 593 350 36 6SnArF 510 SnArF32 760 379 373 575 523 SnArF22 766 SnArF77 265 SnArF1SnArF SnArF27 6SnArF1 2SnArF6 557 67SnArF 590 69SnArF 235 976 67 9SnArFSnArF 156 SnArF07 673 1SnArF1 102 216 507 302 27LeaPin LizarDs 110 605 737 520 290 269 351 750 555 1LeaPin LizarDs2 33 SnArF31 691 SnArF10 73SnArF 22SnArF 1 SnArF69 275 LeaPin LizarDsLeaPin LizarDsLeaPin LizarDs 55SnArF 227 7SnArF3 3SnArFLeaPin LizarDs 975 907 99 255 SnArF90 LeaPin LizarDs07 7SnArF7 SnArF0LeaPin LizarDs 939 71 LeaPin LizarDs9 LeaPin LizarDs70 LeaPin LizarDs67 SnArF5LeaPin LizarDs 33LeaPin LizarDs SnArFLeaPin LizarDs2 359 299 31LeaPin LizarDs 5SnArF1 LeaPin LizarDs12 32LeaPin LizarDs 367 767 712 206 SnArFSnArF9 120 99LeaPin LizarDs 3LeaPin LizarDs5 SnArF99 32SnArF 9LeaPin LizarDs9 SnArF13 915 60LeaPin LizarDs 123 166 91 SnArF01 5SnArF7 151 9SnArF1 101 SnArF03 9LeaPin LizarDs2 60 306 SnArF51 715 9SnArF3 3SnArF1 532 277 LeaPin LizarDs9SnArF 36SnArF 576 266 122 LeaPin LizarDs77 716 SnArF59 97 675 9SnArF 7LeaPin LizarDs 732 9LeaPin LizarDs3 7LeaPin LizarDs0 75LeaPin LizarDs 723 796 619 27 17LeaPin LizarDs 90LeaPin LizarDs 6LeaPin LizarDs3 573 229 97SnArF 720 626 LeaPin LizarDs92 39 577 7SnArF2 LeaPin LizarDs09 739 551 56SnArF SnArF33 LeaPin LizarDs63 262 1LeaPin LizarDs 779 270 SnArF95 562 61 936 7SnArF0 15LeaPin LizarDs 251 670 LeaPin LizarDs50 191 129 1SnArF SnArF76 LeaPin LizarDs21 79 63LeaPin LizarDs 205 509 793 21LeaPin LizarDs 513 2LeaPin LizarDsSnArF 6LeaPin LizarDs9 5SnArF 506 26 20LeaPin LizarDs SnArF6SnArF 620 SnArF50 132 77LeaPin LizarDs 571 11LeaPin LizarDs LeaPin LizarDsSnArF6 LeaPin LizarDs19 556 135 LeaPin LizarDs20 319 953 12SnArF 5SnArF6 773 167 16LeaPin LizarDs 126 7LeaPin LizarDsLeaPin LizarDs 951 599 663 11SnArF LeaPin LizarDs11 703 5LeaPin LizarDs0 SnArF02 726 7SnArFSnArF 97LeaPin LizarDs 933 2LeaPin LizarDs0 1SnArF0 90SnArF 220 112 501 SnArF53 62SnArF 655 735 711 372 676 771 130 535 1LeaPin LizarDs3 903 SnArF70 35SnArF 6LeaPin LizarDs5 9LeaPin LizarDs 6SnArF3 652 633 56LeaPin LizarDs SnArFLeaPin LizarDs5 195 600 113 92LeaPin LizarDs 51SnArF 6 529 967 669 2LeaPin LizarDs2 991 273 521 37LeaPin LizarDs 332 300 SnArF60 76 932 677 LeaPin LizarDs00 5LeaPin LizarDsSnArF 539 3SnArF5 15SnArF LeaPin LizarDs27 923 707 72 5SnArF0 SnArF65 763 550 2SnArFLeaPin LizarDs 671 11 25 252 7LeaPin LizarDs9 237 396 LeaPin LizarDsLeaPin LizarDs 622 LeaPin LizarDs23 LeaPin LizarDs91 LeaPin LizarDs53 SnArF11 977 1LeaPin LizarDs7 1000 5LeaPin LizarDs1 597 52 LeaPin LizarDsSnArF1 LeaPin LizarDs90 SnArF6 665 616 LeaPin LizarDsSnArF 656 650 165 327 SnArF67 19 192 500 755 LeaPin LizarDsLeaPin LizarDs1 SnArF91 LeaPin LizarDs32 55LeaPin LizarDs LeaPin LizarDs35 95SnArF 7SnArF 609 377 37SnArF 659 1SnArF5 60SnArF 5 SnArFLeaPin LizarDs6 316 79SnArF SnArF16 SnArFSnArF1 2SnArF 50SnArF SnArF9 762 9LeaPin LizarDs7 9SnArFLeaPin LizarDs 35LeaPin LizarDs 959 31SnArF 317 993 SnArF3SnArF LeaPin LizarDs2SnArF SnArF23 LeaPin LizarDsLeaPin LizarDs2 13SnArF 3LeaPin LizarDsSnArF 5SnArF5 661 SnArF9LeaPin LizarDs 3SnArF9 2SnArF5 LeaPin LizarDs99 922 515 962 153 SnArF05 905 566 256 9SnArF2 LeaPin LizarDs31 LeaPin LizarDs10 775 LeaPin LizarDs30 137 70SnArF 261 3LeaPin LizarDs1 LeaPin LizarDs36 271 736 900 LeaPin LizarDs60 30LeaPin LizarDs 197 769 LeaPin LizarDs13 SnArFSnArF 7LeaPin LizarDsSnArF 2SnArFSnArF 9LeaPin LizarDsLeaPin LizarDs 92 292 719 76LeaPin LizarDs 207 2 355 567 9LeaPin LizarDs0 601 93 362 26SnArF SnArF3 3SnArF3 960 91LeaPin LizarDs 356 210 LeaPin LizarDs59 65LeaPin LizarDs 997 307 70LeaPin LizarDs 5LeaPin LizarDs6 236 331 LeaPin LizarDs7 23LeaPin LizarDs LeaPin LizarDs3 961 SnArFLeaPin LizarDsLeaPin LizarDs 10 761 696 13LeaPin LizarDs 7LeaPin LizarDs5 6SnArF6 627 106 1SnArF6 SnArFSnArFLeaPin LizarDs LeaPin LizarDs71 259 79LeaPin LizarDs 175 5SnArF9 27SnArF 179 12 LeaPin LizarDs69 9SnArF9 3LeaPin LizarDs6 SnArF92 371 12LeaPin LizarDs SnArF21 LeaPin LizarDs0 530 337 LeaPin LizarDs01 67LeaPin LizarDs 701 225 69LeaPin LizarDs 3LeaPin LizarDs3 3SnArF7 309 6LeaPin LizarDsLeaPin LizarDs LeaPin LizarDs93 SnArFSnArFSnArF 9SnArF7 LeaPin LizarDs76 322 533 320 19SnArF 76SnArF LeaPin LizarDs39 631 552 591 399 926 911 365 51 169 636 791 2SnArF0 3LeaPin LizarDs9 200 LeaPin LizarDs0SnArF SnArF0SnArF 5LeaPin LizarDs2 272 72SnArF LeaPin LizarDs6LeaPin LizarDs 2LeaPin LizarDs1 150 LeaPin LizarDs55 361 SnArFSnArF6 325 71SnArF 910 1LeaPin LizarDs1 LeaPin LizarDsLeaPin LizarDs5 73 LeaPin LizarDs29 516 931 956 LeaPin LizarDs72 59 3SnArF2 2SnArF7 336 565 LeaPin LizarDsSnArFLeaPin LizarDs LeaPin LizarDs17 666 19LeaPin LizarDs 792 639 SnArFLeaPin LizarDs 13 752 16SnArF LeaPin LizarDs22 37 970 305 7LeaPin LizarDs3 SnArFLeaPin LizarDs1 257 5LeaPin LizarDs5 390 296 1LeaPin LizarDs0 375 56 53LeaPin LizarDs 303 75SnArF LeaPin LizarDs15 770 725 759 729 3SnArF 155 6SnArFSnArF 610 511 293 95LeaPin LizarDs 66LeaPin LizarDs LeaPin LizarDs02 63 657 579 LeaPin LizarDsSnArF0 LeaPin LizarDs97 62 66SnArF 9 2SnArF1 LeaPin LizarDs9LeaPin LizarDs 5LeaPin LizarDsLeaPin LizarDs 517 223 6LeaPin LizarDs 795 6SnArF0 930 250 9SnArF6 635 136 SnArF30 995 5SnArF3 502 5SnArFLeaPin LizarDs LeaPin LizarDsLeaPin LizarDs0 7LeaPin LizarDs6 105 SnArF71 531 519 190 9LeaPin LizarDsSnArF 65 797 706 201 301 31 695 LeaPin LizarDs61 1SnArFSnArF 66 776 SnArF39 SnArF15 21SnArF 963 SnArFSnArF3 6SnArF7 57SnArF 662 6SnArFLeaPin LizarDs 751 702 212 107 10LeaPin LizarDs 5SnArFSnArF 1LeaPin LizarDsSnArF LeaPin LizarDs79 71LeaPin LizarDs SnArF29 721 73LeaPin LizarDs 2SnArF2 SnArF56 SnArFSnArF5 16 1LeaPin LizarDs9 30 2LeaPin LizarDs6 LeaPin LizarDsLeaPin LizarDs3 LeaPin LizarDs5 353 3SnArFSnArF 92SnArF LeaPin LizarDs1SnArF 6LeaPin LizarDsSnArF 20SnArF 6SnArF2 3SnArF6 335 SnArF63 176 9SnArF5 111 919 SnArF06 17SnArF 2LeaPin LizarDs 22 2LeaPin LizarDs5 629 990 196 SnArF3LeaPin LizarDs 52LeaPin LizarDs LeaPin LizarDs65 709 LeaPin LizarDsLeaPin LizarDsSnArF 906 LeaPin LizarDs03 172 SnArF09 LeaPin LizarDs2 109 321 5LeaPin LizarDs7 525 LeaPin LizarDs16 1SnArF2 1LeaPin LizarDs6 53SnArF 36LeaPin LizarDs 603 159 360 6LeaPin LizarDs6 2SnArF3 522 263 1SnArF7 93SnArF 1LeaPin LizarDs5 213 215 637 LeaPin LizarDsSnArF3 6SnArF5 222 3 311 1SnArF3 209 1LeaPin LizarDsLeaPin LizarDs LeaPin LizarDs62 LeaPin LizarDsSnArF2 LeaPin LizarDs6SnArF 7LeaPin LizarDs1 526 326 LeaPin LizarDsSnArF7 LeaPin LizarDs06 3LeaPin LizarDs2 LeaPin LizarDs66 SnArF57 75 119 SnArF1 LeaPin LizarDs96 29SnArF 230 SnArF2LeaPin LizarDs 91SnArF 700 29LeaPin LizarDs LeaPin LizarDs95 667 171 125 920 570 SnArF19 705 LeaPin LizarDs51 569 SnArF7 592 39SnArF 25SnArF 607 7LeaPin LizarDs7 276 279 231 100 3LeaPin LizarDs LeaPin LizarDs75 SnArF1LeaPin LizarDs 177 96SnArF LeaPin LizarDs0LeaPin LizarDs SnArF5 163 226 611 23 59LeaPin LizarDs SnArF9SnArF 203 660 560 727 25LeaPin LizarDs 952 239 51LeaPin LizarDs 7SnArF6 SnArF35 173 SnArF55 2LeaPin LizarDs3 3LeaPin LizarDs7 SnArFLeaPin LizarDs0 SnArF97 615 SnArF96 697 291 972 LeaPin LizarDs7LeaPin LizarDs 61LeaPin LizarDs 29 SnArF7LeaPin LizarDs 376 32 162 5SnArF2 1SnArF9 15 9SnArF0 LeaPin LizarDs57 672 297 SnArF 971 SnArF62 772 157 553 357 902 211 692 SnArF12 2SnArF9 2LeaPin LizarDsLeaPin LizarDs 267 121 33SnArF 370 330 9LeaPin LizarDs1 26LeaPin LizarDs 973 50LeaPin LizarDs SnArFLeaPin LizarDs3 SnArF2SnArF SnArF26 7SnArF5 965 217 SnArFLeaPin LizarDsSnArF LeaPin LizarDs05 563 612 SnArF17 SnArF72 95 LeaPin LizarDs33 777 329 722 559 96LeaPin LizarDs 7SnArF9 133 621 SnArF93 3SnArF0 651 606 339 9LeaPin LizarDs5 21 950 160 935 937 93LeaPin LizarDs 127 117 LeaPin LizarDs5LeaPin LizarDs 653 916 10SnArF 221 23SnArF 6LeaPin LizarDs2 SnArF00 969 7SnArF1 SnArF52 901 90 LeaPin LizarDs7SnArF 537 602 392 996 3LeaPin LizarDs0 65SnArF 219 161 756 369 925 505 397 SnArF0 623 LeaPin LizarDs3SnArF 313 17 7 2LeaPin LizarDs9 693 595 966 103 630 SnArF75 503 52SnArF SnArF20 7SnArFLeaPin LizarDs 115 955 53 713 391 625 LeaPin LizarDs2LeaPin LizarDs SnArF36 5LeaPin LizarDs3 310 69 SnArF73 62LeaPin LizarDs 753 99SnArF 512 999 536 SnArF7SnArF 30SnArF 561 72LeaPin LizarDs LeaPin LizarDs25 63SnArF SnArFLeaPin LizarDs9 929 917 LeaPin LizarDs56 193 SnArFLeaPin LizarDs7 979 LeaPin LizarDs73 LeaPin LizarDs6 57 613 SnArFSnArF7 2LeaPin LizarDs7 232 SnArF37 260 LeaPin LizarDsLeaPin LizarDs7 55 913 799 315 57LeaPin LizarDs 199 957 SnArF79 LeaPin LizarDs37 366 50 70 596 SnArFSnArF0 152 SnArF66 295 690 679 139 5LeaPin LizarDs 96 SnArF25 233 LeaPin LizarDs5SnArF 3LeaPin LizarDsLeaPin LizarDs 992 LeaPin LizarDsSnArF5 617 363 35 253 LeaPin LizarDs1 SnArF2 323 395 632 765 393 SnArFSnArF2 77SnArF 790 1SnArFLeaPin LizarDs 927 699 5LeaPin LizarDs9 22LeaPin LizarDs 352 733 572 LeaPin LizarDs1LeaPin LizarDs 59SnArF 6SnArF9 730 LeaPin LizarDs52 61SnArF From ee0d1a431907654b8ad738443134e53bb74d8b47 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 15 Nov 2011 19:09:23 -0500 Subject: [PATCH 122/145] Shell script to install the APR stuff that will be used while making devpkg in ch27 ex26 --- apr-install-script.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100755 apr-install-script.sh diff --git a/apr-install-script.sh b/apr-install-script.sh new file mode 100755 index 0000000..f7a202e --- /dev/null +++ b/apr-install-script.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -e + +# go somewhere safe +cd /tmp + +# get the source to base APR 1.4.5 +curl -L -O http://download.nextag.com/apache/apr/apr-1.4.5.tar.gz + +# extract it and go into the source +tar -xzvf apr-1.4.5.tar.gz +cd apr-1.4.5 + +# configure, make, make install +./configure +make +sudo make install + +# reset and cleanup +cd /tmp +rm -rf apr-1.4.5 apr-1.4.5.tar.gz + +# do the same with apr-util +curl -L -O http://download.nextag.com/apache/apr/apr-util-1.3.12.tar.gz + +# extract +tar -xzvf apr-util-1.3.12.tar.gz +cd apr-util-1.3.12 + +# configure, make, make install +./configure --with-apr=/usr/local/apr +# you need that extra parameter to configure because +# apr-util can't really find it because... who knows. + +make +sudo make install + +# cleanup +cd /tmp +rm -rf apr-util-1.3.12* apr-1.4.5* From fcef08e87ecf5152b59d18ff036970849dcc1b4b Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 15 Nov 2011 19:15:43 -0500 Subject: [PATCH 123/145] Stubbing in layout for devpkg --- .gitignore | 45 +- break-ex25.rb | 11 + devpkg/Makefile | 0 devpkg/README | 0 devpkg/bstrlib.c | 2979 ++++++++++++++++++++++++++++++++++++++++++++++ devpkg/bstrlib.h | 304 +++++ devpkg/dbg.h | 1 + 7 files changed, 3329 insertions(+), 11 deletions(-) create mode 100644 break-ex25.rb create mode 100644 devpkg/Makefile create mode 100644 devpkg/README create mode 100644 devpkg/bstrlib.c create mode 100644 devpkg/bstrlib.h create mode 120000 devpkg/dbg.h diff --git a/.gitignore b/.gitignore index d8e72e9..fd6da7c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,34 @@ -* - -!*.c -!Makefile -!README.md -!*.py -!*.h -!*.mk -!*.sh -!*-input -!*.txt +*.dat +ex1 +ex10 +ex11 +ex12 +ex13 +ex14 +ex15 +ex16 +ex17 +ex18 +ex19 +ex20 +ex21 +ex22_ec1 +ex22_main +ex23 +ex24 +ex24_iofunctions01 +ex24_iofunctions02 +ex24_iofunctions03 +ex24_iofunctions04 +ex24_iofunctions05 +ex24_iofunctions06 +ex25 +ex3 +ex4 +ex5 +ex6 +ex7 +ex8 +ex9 +.exrc +.rvmrc diff --git a/break-ex25.rb b/break-ex25.rb new file mode 100644 index 0000000..2d729e0 --- /dev/null +++ b/break-ex25.rb @@ -0,0 +1,11 @@ +def main + ex25 = IO.popen("./ex25", "w+") + ex25.write("z" * 10000) + ex25.flush + puts ex25.readlines.join("\n") +end + + +if $0 == __FILE__ + main +end diff --git a/devpkg/Makefile b/devpkg/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/devpkg/README b/devpkg/README new file mode 100644 index 0000000..e69de29 diff --git a/devpkg/bstrlib.c b/devpkg/bstrlib.c new file mode 100644 index 0000000..c6294f1 --- /dev/null +++ b/devpkg/bstrlib.c @@ -0,0 +1,2979 @@ +/* + * This source file is part of the bstring string library. This code was + * written by Paul Hsieh in 2002-2010, and is covered by either the 3-clause + * BSD open source license or GPL v2.0. Refer to the accompanying documentation + * for details on usage and license. + */ + +/* + * bstrlib.c + * + * This file is the core module for implementing the bstring functions. + */ + +#if defined (_MSC_VER) +/* These warnings from MSVC++ are totally pointless. */ +# define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include +#include "bstrlib.h" + +/* Optionally include a mechanism for debugging memory */ + +#if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG) +#include "memdbg.h" +#endif + +#ifndef bstr__alloc +#define bstr__alloc(x) malloc (x) +#endif + +#ifndef bstr__free +#define bstr__free(p) free (p) +#endif + +#ifndef bstr__realloc +#define bstr__realloc(p,x) realloc ((p), (x)) +#endif + +#ifndef bstr__memcpy +#define bstr__memcpy(d,s,l) memcpy ((d), (s), (l)) +#endif + +#ifndef bstr__memmove +#define bstr__memmove(d,s,l) memmove ((d), (s), (l)) +#endif + +#ifndef bstr__memset +#define bstr__memset(d,c,l) memset ((d), (c), (l)) +#endif + +#ifndef bstr__memcmp +#define bstr__memcmp(d,c,l) memcmp ((d), (c), (l)) +#endif + +#ifndef bstr__memchr +#define bstr__memchr(s,c,l) memchr ((s), (c), (l)) +#endif + +/* Just a length safe wrapper for memmove. */ + +#define bBlockCopy(D,S,L) { if ((L) > 0) bstr__memmove ((D),(S),(L)); } + +/* Compute the snapped size for a given requested size. By snapping to powers + of 2 like this, repeated reallocations are avoided. */ +static int snapUpSize (int i) { + if (i < 8) { + i = 8; + } else { + unsigned int j; + j = (unsigned int) i; + + j |= (j >> 1); + j |= (j >> 2); + j |= (j >> 4); + j |= (j >> 8); /* Ok, since int >= 16 bits */ +#if (UINT_MAX != 0xffff) + j |= (j >> 16); /* For 32 bit int systems */ +#if (UINT_MAX > 0xffffffffUL) + j |= (j >> 32); /* For 64 bit int systems */ +#endif +#endif + /* Least power of two greater than i */ + j++; + if ((int) j >= i) i = (int) j; + } + return i; +} + +/* int balloc (bstring b, int len) + * + * Increase the size of the memory backing the bstring b to at least len. + */ +int balloc (bstring b, int olen) { + int len; + if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen <= 0 || + b->mlen < b->slen || olen <= 0) { + return BSTR_ERR; + } + + if (olen >= b->mlen) { + unsigned char * x; + + if ((len = snapUpSize (olen)) <= b->mlen) return BSTR_OK; + + /* Assume probability of a non-moving realloc is 0.125 */ + if (7 * b->mlen < 8 * b->slen) { + + /* If slen is close to mlen in size then use realloc to reduce + the memory defragmentation */ + + reallocStrategy:; + + x = (unsigned char *) bstr__realloc (b->data, (size_t) len); + if (x == NULL) { + + /* Since we failed, try allocating the tighest possible + allocation */ + + if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) { + return BSTR_ERR; + } + } + } else { + + /* If slen is not close to mlen then avoid the penalty of copying + the extra bytes that are allocated, but not considered part of + the string */ + + if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) { + + /* Perhaps there is no available memory for the two + allocations to be in memory at once */ + + goto reallocStrategy; + + } else { + if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen); + bstr__free (b->data); + } + } + b->data = x; + b->mlen = len; + b->data[b->slen] = (unsigned char) '\0'; + } + + return BSTR_OK; +} + +/* int ballocmin (bstring b, int len) + * + * Set the size of the memory backing the bstring b to len or b->slen+1, + * whichever is larger. Note that repeated use of this function can degrade + * performance. + */ +int ballocmin (bstring b, int len) { + unsigned char * s; + + if (b == NULL || b->data == NULL || (b->slen+1) < 0 || b->mlen <= 0 || + b->mlen < b->slen || len <= 0) { + return BSTR_ERR; + } + + if (len < b->slen + 1) len = b->slen + 1; + + if (len != b->mlen) { + s = (unsigned char *) bstr__realloc (b->data, (size_t) len); + if (NULL == s) return BSTR_ERR; + s[b->slen] = (unsigned char) '\0'; + b->data = s; + b->mlen = len; + } + + return BSTR_OK; +} + +/* bstring bfromcstr (const char * str) + * + * Create a bstring which contains the contents of the '\0' terminated char * + * buffer str. + */ +bstring bfromcstr (const char * str) { +bstring b; +int i; +size_t j; + + if (str == NULL) return NULL; + j = (strlen) (str); + i = snapUpSize ((int) (j + (2 - (j != 0)))); + if (i <= (int) j) return NULL; + + b = (bstring) bstr__alloc (sizeof (struct tagbstring)); + if (NULL == b) return NULL; + b->slen = (int) j; + if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) { + bstr__free (b); + return NULL; + } + + bstr__memcpy (b->data, str, j+1); + return b; +} + +/* bstring bfromcstralloc (int mlen, const char * str) + * + * Create a bstring which contains the contents of the '\0' terminated char * + * buffer str. The memory buffer backing the string is at least len + * characters in length. + */ +bstring bfromcstralloc (int mlen, const char * str) { +bstring b; +int i; +size_t j; + + if (str == NULL) return NULL; + j = (strlen) (str); + i = snapUpSize ((int) (j + (2 - (j != 0)))); + if (i <= (int) j) return NULL; + + b = (bstring) bstr__alloc (sizeof (struct tagbstring)); + if (b == NULL) return NULL; + b->slen = (int) j; + if (i < mlen) i = mlen; + + if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) { + bstr__free (b); + return NULL; + } + + bstr__memcpy (b->data, str, j+1); + return b; +} + +/* bstring blk2bstr (const void * blk, int len) + * + * Create a bstring which contains the content of the block blk of length + * len. + */ +bstring blk2bstr (const void * blk, int len) { +bstring b; +int i; + + if (blk == NULL || len < 0) return NULL; + b = (bstring) bstr__alloc (sizeof (struct tagbstring)); + if (b == NULL) return NULL; + b->slen = len; + + i = len + (2 - (len != 0)); + i = snapUpSize (i); + + b->mlen = i; + + b->data = (unsigned char *) bstr__alloc ((size_t) b->mlen); + if (b->data == NULL) { + bstr__free (b); + return NULL; + } + + if (len > 0) bstr__memcpy (b->data, blk, (size_t) len); + b->data[len] = (unsigned char) '\0'; + + return b; +} + +/* char * bstr2cstr (const_bstring s, char z) + * + * Create a '\0' terminated char * buffer which is equal to the contents of + * the bstring s, except that any contained '\0' characters are converted + * to the character in z. This returned value should be freed with a + * bcstrfree () call, by the calling application. + */ +char * bstr2cstr (const_bstring b, char z) { +int i, l; +char * r; + + if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; + l = b->slen; + r = (char *) bstr__alloc ((size_t) (l + 1)); + if (r == NULL) return r; + + for (i=0; i < l; i ++) { + r[i] = (char) ((b->data[i] == '\0') ? z : (char) (b->data[i])); + } + + r[l] = (unsigned char) '\0'; + + return r; +} + +/* int bcstrfree (char * s) + * + * Frees a C-string generated by bstr2cstr (). This is normally unnecessary + * since it just wraps a call to bstr__free (), however, if bstr__alloc () + * and bstr__free () have been redefined as a macros within the bstrlib + * module (via defining them in memdbg.h after defining + * BSTRLIB_MEMORY_DEBUG) with some difference in behaviour from the std + * library functions, then this allows a correct way of freeing the memory + * that allows higher level code to be independent from these macro + * redefinitions. + */ +int bcstrfree (char * s) { + if (s) { + bstr__free (s); + return BSTR_OK; + } + return BSTR_ERR; +} + +/* int bconcat (bstring b0, const_bstring b1) + * + * Concatenate the bstring b1 to the bstring b0. + */ +int bconcat (bstring b0, const_bstring b1) { +int len, d; +bstring aux = (bstring) b1; + + if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return BSTR_ERR; + + d = b0->slen; + len = b1->slen; + if ((d | (b0->mlen - d) | len | (d + len)) < 0) return BSTR_ERR; + + if (b0->mlen <= d + len + 1) { + ptrdiff_t pd = b1->data - b0->data; + if (0 <= pd && pd < b0->mlen) { + if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR; + } + if (balloc (b0, d + len + 1) != BSTR_OK) { + if (aux != b1) bdestroy (aux); + return BSTR_ERR; + } + } + + bBlockCopy (&b0->data[d], &aux->data[0], (size_t) len); + b0->data[d + len] = (unsigned char) '\0'; + b0->slen = d + len; + if (aux != b1) bdestroy (aux); + return BSTR_OK; +} + +/* int bconchar (bstring b, char c) +/ * + * Concatenate the single character c to the bstring b. + */ +int bconchar (bstring b, char c) { +int d; + + if (b == NULL) return BSTR_ERR; + d = b->slen; + if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) return BSTR_ERR; + b->data[d] = (unsigned char) c; + b->data[d + 1] = (unsigned char) '\0'; + b->slen++; + return BSTR_OK; +} + +/* int bcatcstr (bstring b, const char * s) + * + * Concatenate a char * string to a bstring. + */ +int bcatcstr (bstring b, const char * s) { +char * d; +int i, l; + + if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen + || b->mlen <= 0 || s == NULL) return BSTR_ERR; + + /* Optimistically concatenate directly */ + l = b->mlen - b->slen; + d = (char *) &b->data[b->slen]; + for (i=0; i < l; i++) { + if ((*d++ = *s++) == '\0') { + b->slen += i; + return BSTR_OK; + } + } + b->slen += i; + + /* Need to explicitely resize and concatenate tail */ + return bcatblk (b, (const void *) s, (int) strlen (s)); +} + +/* int bcatblk (bstring b, const void * s, int len) + * + * Concatenate a fixed length buffer to a bstring. + */ +int bcatblk (bstring b, const void * s, int len) { +int nl; + + if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen + || b->mlen <= 0 || s == NULL || len < 0) return BSTR_ERR; + + if (0 > (nl = b->slen + len)) return BSTR_ERR; /* Overflow? */ + if (b->mlen <= nl && 0 > balloc (b, nl + 1)) return BSTR_ERR; + + bBlockCopy (&b->data[b->slen], s, (size_t) len); + b->slen = nl; + b->data[nl] = (unsigned char) '\0'; + return BSTR_OK; +} + +/* bstring bstrcpy (const_bstring b) + * + * Create a copy of the bstring b. + */ +bstring bstrcpy (const_bstring b) { +bstring b0; +int i,j; + + /* Attempted to copy an invalid string? */ + if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; + + b0 = (bstring) bstr__alloc (sizeof (struct tagbstring)); + if (b0 == NULL) { + /* Unable to allocate memory for string header */ + return NULL; + } + + i = b->slen; + j = snapUpSize (i + 1); + + b0->data = (unsigned char *) bstr__alloc (j); + if (b0->data == NULL) { + j = i + 1; + b0->data = (unsigned char *) bstr__alloc (j); + if (b0->data == NULL) { + /* Unable to allocate memory for string data */ + bstr__free (b0); + return NULL; + } + } + + b0->mlen = j; + b0->slen = i; + + if (i) bstr__memcpy ((char *) b0->data, (char *) b->data, i); + b0->data[b0->slen] = (unsigned char) '\0'; + + return b0; +} + +/* int bassign (bstring a, const_bstring b) + * + * Overwrite the string a with the contents of string b. + */ +int bassign (bstring a, const_bstring b) { + if (b == NULL || b->data == NULL || b->slen < 0) + return BSTR_ERR; + if (b->slen != 0) { + if (balloc (a, b->slen) != BSTR_OK) return BSTR_ERR; + bstr__memmove (a->data, b->data, b->slen); + } else { + if (a == NULL || a->data == NULL || a->mlen < a->slen || + a->slen < 0 || a->mlen == 0) + return BSTR_ERR; + } + a->data[b->slen] = (unsigned char) '\0'; + a->slen = b->slen; + return BSTR_OK; +} + +/* int bassignmidstr (bstring a, const_bstring b, int left, int len) + * + * Overwrite the string a with the middle of contents of string b + * starting from position left and running for a length len. left and + * len are clamped to the ends of b as with the function bmidstr. + */ +int bassignmidstr (bstring a, const_bstring b, int left, int len) { + if (b == NULL || b->data == NULL || b->slen < 0) + return BSTR_ERR; + + if (left < 0) { + len += left; + left = 0; + } + + if (len > b->slen - left) len = b->slen - left; + + if (a == NULL || a->data == NULL || a->mlen < a->slen || + a->slen < 0 || a->mlen == 0) + return BSTR_ERR; + + if (len > 0) { + if (balloc (a, len) != BSTR_OK) return BSTR_ERR; + bstr__memmove (a->data, b->data + left, len); + a->slen = len; + } else { + a->slen = 0; + } + a->data[a->slen] = (unsigned char) '\0'; + return BSTR_OK; +} + +/* int bassigncstr (bstring a, const char * str) + * + * Overwrite the string a with the contents of char * string str. Note that + * the bstring a must be a well defined and writable bstring. If an error + * occurs BSTR_ERR is returned however a may be partially overwritten. + */ +int bassigncstr (bstring a, const char * str) { +int i; +size_t len; + if (a == NULL || a->data == NULL || a->mlen < a->slen || + a->slen < 0 || a->mlen == 0 || NULL == str) + return BSTR_ERR; + + for (i=0; i < a->mlen; i++) { + if ('\0' == (a->data[i] = str[i])) { + a->slen = i; + return BSTR_OK; + } + } + + a->slen = i; + len = strlen (str + i); + if (len > INT_MAX || i + len + 1 > INT_MAX || + 0 > balloc (a, (int) (i + len + 1))) return BSTR_ERR; + bBlockCopy (a->data + i, str + i, (size_t) len + 1); + a->slen += (int) len; + return BSTR_OK; +} + +/* int bassignblk (bstring a, const void * s, int len) + * + * Overwrite the string a with the contents of the block (s, len). Note that + * the bstring a must be a well defined and writable bstring. If an error + * occurs BSTR_ERR is returned and a is not overwritten. + */ +int bassignblk (bstring a, const void * s, int len) { + if (a == NULL || a->data == NULL || a->mlen < a->slen || + a->slen < 0 || a->mlen == 0 || NULL == s || len + 1 < 1) + return BSTR_ERR; + if (len + 1 > a->mlen && 0 > balloc (a, len + 1)) return BSTR_ERR; + bBlockCopy (a->data, s, (size_t) len); + a->data[len] = (unsigned char) '\0'; + a->slen = len; + return BSTR_OK; +} + +/* int btrunc (bstring b, int n) + * + * Truncate the bstring to at most n characters. + */ +int btrunc (bstring b, int n) { + if (n < 0 || b == NULL || b->data == NULL || b->mlen < b->slen || + b->slen < 0 || b->mlen <= 0) return BSTR_ERR; + if (b->slen > n) { + b->slen = n; + b->data[n] = (unsigned char) '\0'; + } + return BSTR_OK; +} + +#define upcase(c) (toupper ((unsigned char) c)) +#define downcase(c) (tolower ((unsigned char) c)) +#define wspace(c) (isspace ((unsigned char) c)) + +/* int btoupper (bstring b) + * + * Convert contents of bstring to upper case. + */ +int btoupper (bstring b) { +int i, len; + if (b == NULL || b->data == NULL || b->mlen < b->slen || + b->slen < 0 || b->mlen <= 0) return BSTR_ERR; + for (i=0, len = b->slen; i < len; i++) { + b->data[i] = (unsigned char) upcase (b->data[i]); + } + return BSTR_OK; +} + +/* int btolower (bstring b) + * + * Convert contents of bstring to lower case. + */ +int btolower (bstring b) { +int i, len; + if (b == NULL || b->data == NULL || b->mlen < b->slen || + b->slen < 0 || b->mlen <= 0) return BSTR_ERR; + for (i=0, len = b->slen; i < len; i++) { + b->data[i] = (unsigned char) downcase (b->data[i]); + } + return BSTR_OK; +} + +/* int bstricmp (const_bstring b0, const_bstring b1) + * + * Compare two strings without differentiating between case. The return + * value is the difference of the values of the characters where the two + * strings first differ after lower case transformation, otherwise 0 is + * returned indicating that the strings are equal. If the lengths are + * different, then a difference from 0 is given, but if the first extra + * character is '\0', then it is taken to be the value UCHAR_MAX+1. + */ +int bstricmp (const_bstring b0, const_bstring b1) { +int i, v, n; + + if (bdata (b0) == NULL || b0->slen < 0 || + bdata (b1) == NULL || b1->slen < 0) return SHRT_MIN; + if ((n = b0->slen) > b1->slen) n = b1->slen; + else if (b0->slen == b1->slen && b0->data == b1->data) return BSTR_OK; + + for (i = 0; i < n; i ++) { + v = (char) downcase (b0->data[i]) + - (char) downcase (b1->data[i]); + if (0 != v) return v; + } + + if (b0->slen > n) { + v = (char) downcase (b0->data[n]); + if (v) return v; + return UCHAR_MAX + 1; + } + if (b1->slen > n) { + v = - (char) downcase (b1->data[n]); + if (v) return v; + return - (int) (UCHAR_MAX + 1); + } + return BSTR_OK; +} + +/* int bstrnicmp (const_bstring b0, const_bstring b1, int n) + * + * Compare two strings without differentiating between case for at most n + * characters. If the position where the two strings first differ is + * before the nth position, the return value is the difference of the values + * of the characters, otherwise 0 is returned. If the lengths are different + * and less than n characters, then a difference from 0 is given, but if the + * first extra character is '\0', then it is taken to be the value + * UCHAR_MAX+1. + */ +int bstrnicmp (const_bstring b0, const_bstring b1, int n) { +int i, v, m; + + if (bdata (b0) == NULL || b0->slen < 0 || + bdata (b1) == NULL || b1->slen < 0 || n < 0) return SHRT_MIN; + m = n; + if (m > b0->slen) m = b0->slen; + if (m > b1->slen) m = b1->slen; + + if (b0->data != b1->data) { + for (i = 0; i < m; i ++) { + v = (char) downcase (b0->data[i]); + v -= (char) downcase (b1->data[i]); + if (v != 0) return b0->data[i] - b1->data[i]; + } + } + + if (n == m || b0->slen == b1->slen) return BSTR_OK; + + if (b0->slen > m) { + v = (char) downcase (b0->data[m]); + if (v) return v; + return UCHAR_MAX + 1; + } + + v = - (char) downcase (b1->data[m]); + if (v) return v; + return - (int) (UCHAR_MAX + 1); +} + +/* int biseqcaseless (const_bstring b0, const_bstring b1) + * + * Compare two strings for equality without differentiating between case. + * If the strings differ other than in case, 0 is returned, if the strings + * are the same, 1 is returned, if there is an error, -1 is returned. If + * the length of the strings are different, this function is O(1). '\0' + * termination characters are not treated in any special way. + */ +int biseqcaseless (const_bstring b0, const_bstring b1) { +int i, n; + + if (bdata (b0) == NULL || b0->slen < 0 || + bdata (b1) == NULL || b1->slen < 0) return BSTR_ERR; + if (b0->slen != b1->slen) return BSTR_OK; + if (b0->data == b1->data || b0->slen == 0) return 1; + for (i=0, n=b0->slen; i < n; i++) { + if (b0->data[i] != b1->data[i]) { + unsigned char c = (unsigned char) downcase (b0->data[i]); + if (c != (unsigned char) downcase (b1->data[i])) return 0; + } + } + return 1; +} + +/* int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) + * + * Compare beginning of string b0 with a block of memory of length len + * without differentiating between case for equality. If the beginning of b0 + * differs from the memory block other than in case (or if b0 is too short), + * 0 is returned, if the strings are the same, 1 is returned, if there is an + * error, -1 is returned. '\0' characters are not treated in any special + * way. + */ +int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) { +int i; + + if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0) + return BSTR_ERR; + if (b0->slen < len) return BSTR_OK; + if (b0->data == (const unsigned char *) blk || len == 0) return 1; + + for (i = 0; i < len; i ++) { + if (b0->data[i] != ((const unsigned char *) blk)[i]) { + if (downcase (b0->data[i]) != + downcase (((const unsigned char *) blk)[i])) return 0; + } + } + return 1; +} + +/* + * int bltrimws (bstring b) + * + * Delete whitespace contiguous from the left end of the string. + */ +int bltrimws (bstring b) { +int i, len; + + if (b == NULL || b->data == NULL || b->mlen < b->slen || + b->slen < 0 || b->mlen <= 0) return BSTR_ERR; + + for (len = b->slen, i = 0; i < len; i++) { + if (!wspace (b->data[i])) { + return bdelete (b, 0, i); + } + } + + b->data[0] = (unsigned char) '\0'; + b->slen = 0; + return BSTR_OK; +} + +/* + * int brtrimws (bstring b) + * + * Delete whitespace contiguous from the right end of the string. + */ +int brtrimws (bstring b) { +int i; + + if (b == NULL || b->data == NULL || b->mlen < b->slen || + b->slen < 0 || b->mlen <= 0) return BSTR_ERR; + + for (i = b->slen - 1; i >= 0; i--) { + if (!wspace (b->data[i])) { + if (b->mlen > i) b->data[i+1] = (unsigned char) '\0'; + b->slen = i + 1; + return BSTR_OK; + } + } + + b->data[0] = (unsigned char) '\0'; + b->slen = 0; + return BSTR_OK; +} + +/* + * int btrimws (bstring b) + * + * Delete whitespace contiguous from both ends of the string. + */ +int btrimws (bstring b) { +int i, j; + + if (b == NULL || b->data == NULL || b->mlen < b->slen || + b->slen < 0 || b->mlen <= 0) return BSTR_ERR; + + for (i = b->slen - 1; i >= 0; i--) { + if (!wspace (b->data[i])) { + if (b->mlen > i) b->data[i+1] = (unsigned char) '\0'; + b->slen = i + 1; + for (j = 0; wspace (b->data[j]); j++) {} + return bdelete (b, 0, j); + } + } + + b->data[0] = (unsigned char) '\0'; + b->slen = 0; + return BSTR_OK; +} + +/* int biseq (const_bstring b0, const_bstring b1) + * + * Compare the string b0 and b1. If the strings differ, 0 is returned, if + * the strings are the same, 1 is returned, if there is an error, -1 is + * returned. If the length of the strings are different, this function is + * O(1). '\0' termination characters are not treated in any special way. + */ +int biseq (const_bstring b0, const_bstring b1) { + if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL || + b0->slen < 0 || b1->slen < 0) return BSTR_ERR; + if (b0->slen != b1->slen) return BSTR_OK; + if (b0->data == b1->data || b0->slen == 0) return 1; + return !bstr__memcmp (b0->data, b1->data, b0->slen); +} + +/* int bisstemeqblk (const_bstring b0, const void * blk, int len) + * + * Compare beginning of string b0 with a block of memory of length len for + * equality. If the beginning of b0 differs from the memory block (or if b0 + * is too short), 0 is returned, if the strings are the same, 1 is returned, + * if there is an error, -1 is returned. '\0' characters are not treated in + * any special way. + */ +int bisstemeqblk (const_bstring b0, const void * blk, int len) { +int i; + + if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0) + return BSTR_ERR; + if (b0->slen < len) return BSTR_OK; + if (b0->data == (const unsigned char *) blk || len == 0) return 1; + + for (i = 0; i < len; i ++) { + if (b0->data[i] != ((const unsigned char *) blk)[i]) return BSTR_OK; + } + return 1; +} + +/* int biseqcstr (const_bstring b, const char *s) + * + * Compare the bstring b and char * string s. The C string s must be '\0' + * terminated at exactly the length of the bstring b, and the contents + * between the two must be identical with the bstring b with no '\0' + * characters for the two contents to be considered equal. This is + * equivalent to the condition that their current contents will be always be + * equal when comparing them in the same format after converting one or the + * other. If the strings are equal 1 is returned, if they are unequal 0 is + * returned and if there is a detectable error BSTR_ERR is returned. + */ +int biseqcstr (const_bstring b, const char * s) { +int i; + if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR; + for (i=0; i < b->slen; i++) { + if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return BSTR_OK; + } + return s[i] == '\0'; +} + +/* int biseqcstrcaseless (const_bstring b, const char *s) + * + * Compare the bstring b and char * string s. The C string s must be '\0' + * terminated at exactly the length of the bstring b, and the contents + * between the two must be identical except for case with the bstring b with + * no '\0' characters for the two contents to be considered equal. This is + * equivalent to the condition that their current contents will be always be + * equal ignoring case when comparing them in the same format after + * converting one or the other. If the strings are equal, except for case, + * 1 is returned, if they are unequal regardless of case 0 is returned and + * if there is a detectable error BSTR_ERR is returned. + */ +int biseqcstrcaseless (const_bstring b, const char * s) { +int i; + if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR; + for (i=0; i < b->slen; i++) { + if (s[i] == '\0' || + (b->data[i] != (unsigned char) s[i] && + downcase (b->data[i]) != (unsigned char) downcase (s[i]))) + return BSTR_OK; + } + return s[i] == '\0'; +} + +/* int bstrcmp (const_bstring b0, const_bstring b1) + * + * Compare the string b0 and b1. If there is an error, SHRT_MIN is returned, + * otherwise a value less than or greater than zero, indicating that the + * string pointed to by b0 is lexicographically less than or greater than + * the string pointed to by b1 is returned. If the the string lengths are + * unequal but the characters up until the length of the shorter are equal + * then a value less than, or greater than zero, indicating that the string + * pointed to by b0 is shorter or longer than the string pointed to by b1 is + * returned. 0 is returned if and only if the two strings are the same. If + * the length of the strings are different, this function is O(n). Like its + * standard C library counter part strcmp, the comparison does not proceed + * past any '\0' termination characters encountered. + */ +int bstrcmp (const_bstring b0, const_bstring b1) { +int i, v, n; + + if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL || + b0->slen < 0 || b1->slen < 0) return SHRT_MIN; + n = b0->slen; if (n > b1->slen) n = b1->slen; + if (b0->slen == b1->slen && (b0->data == b1->data || b0->slen == 0)) + return BSTR_OK; + + for (i = 0; i < n; i ++) { + v = ((char) b0->data[i]) - ((char) b1->data[i]); + if (v != 0) return v; + if (b0->data[i] == (unsigned char) '\0') return BSTR_OK; + } + + if (b0->slen > n) return 1; + if (b1->slen > n) return -1; + return BSTR_OK; +} + +/* int bstrncmp (const_bstring b0, const_bstring b1, int n) + * + * Compare the string b0 and b1 for at most n characters. If there is an + * error, SHRT_MIN is returned, otherwise a value is returned as if b0 and + * b1 were first truncated to at most n characters then bstrcmp was called + * with these new strings are paremeters. If the length of the strings are + * different, this function is O(n). Like its standard C library counter + * part strcmp, the comparison does not proceed past any '\0' termination + * characters encountered. + */ +int bstrncmp (const_bstring b0, const_bstring b1, int n) { +int i, v, m; + + if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL || + b0->slen < 0 || b1->slen < 0) return SHRT_MIN; + m = n; + if (m > b0->slen) m = b0->slen; + if (m > b1->slen) m = b1->slen; + + if (b0->data != b1->data) { + for (i = 0; i < m; i ++) { + v = ((char) b0->data[i]) - ((char) b1->data[i]); + if (v != 0) return v; + if (b0->data[i] == (unsigned char) '\0') return BSTR_OK; + } + } + + if (n == m || b0->slen == b1->slen) return BSTR_OK; + + if (b0->slen > m) return 1; + return -1; +} + +/* bstring bmidstr (const_bstring b, int left, int len) + * + * Create a bstring which is the substring of b starting from position left + * and running for a length len (clamped by the end of the bstring b.) If + * b is detectably invalid, then NULL is returned. The section described + * by (left, len) is clamped to the boundaries of b. + */ +bstring bmidstr (const_bstring b, int left, int len) { + + if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; + + if (left < 0) { + len += left; + left = 0; + } + + if (len > b->slen - left) len = b->slen - left; + + if (len <= 0) return bfromcstr (""); + return blk2bstr (b->data + left, len); +} + +/* int bdelete (bstring b, int pos, int len) + * + * Removes characters from pos to pos+len-1 inclusive and shifts the tail of + * the bstring starting from pos+len to pos. len must be positive for this + * call to have any effect. The section of the string described by (pos, + * len) is clamped to boundaries of the bstring b. + */ +int bdelete (bstring b, int pos, int len) { + /* Clamp to left side of bstring */ + if (pos < 0) { + len += pos; + pos = 0; + } + + if (len < 0 || b == NULL || b->data == NULL || b->slen < 0 || + b->mlen < b->slen || b->mlen <= 0) + return BSTR_ERR; + if (len > 0 && pos < b->slen) { + if (pos + len >= b->slen) { + b->slen = pos; + } else { + bBlockCopy ((char *) (b->data + pos), + (char *) (b->data + pos + len), + b->slen - (pos+len)); + b->slen -= len; + } + b->data[b->slen] = (unsigned char) '\0'; + } + return BSTR_OK; +} + +/* int bdestroy (bstring b) + * + * Free up the bstring. Note that if b is detectably invalid or not writable + * then no action is performed and BSTR_ERR is returned. Like a freed memory + * allocation, dereferences, writes or any other action on b after it has + * been bdestroyed is undefined. + */ +int bdestroy (bstring b) { + if (b == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen || + b->data == NULL) + return BSTR_ERR; + + bstr__free (b->data); + + /* In case there is any stale usage, there is one more chance to + notice this error. */ + + b->slen = -1; + b->mlen = -__LINE__; + b->data = NULL; + + bstr__free (b); + return BSTR_OK; +} + +/* int binstr (const_bstring b1, int pos, const_bstring b2) + * + * Search for the bstring b2 in b1 starting from position pos, and searching + * forward. If it is found then return with the first position where it is + * found, otherwise return BSTR_ERR. Note that this is just a brute force + * string searcher that does not attempt clever things like the Boyer-Moore + * search algorithm. Because of this there are many degenerate cases where + * this can take much longer than it needs to. + */ +int binstr (const_bstring b1, int pos, const_bstring b2) { +int j, ii, ll, lf; +unsigned char * d0; +unsigned char c0; +register unsigned char * d1; +register unsigned char c1; +register int i; + + if (b1 == NULL || b1->data == NULL || b1->slen < 0 || + b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR; + if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR; + if (b1->slen < pos || pos < 0) return BSTR_ERR; + if (b2->slen == 0) return pos; + + /* No space to find such a string? */ + if ((lf = b1->slen - b2->slen + 1) <= pos) return BSTR_ERR; + + /* An obvious alias case */ + if (b1->data == b2->data && pos == 0) return 0; + + i = pos; + + d0 = b2->data; + d1 = b1->data; + ll = b2->slen; + + /* Peel off the b2->slen == 1 case */ + c0 = d0[0]; + if (1 == ll) { + for (;i < lf; i++) if (c0 == d1[i]) return i; + return BSTR_ERR; + } + + c1 = c0; + j = 0; + lf = b1->slen - 1; + + ii = -1; + if (i < lf) do { + /* Unrolled current character test */ + if (c1 != d1[i]) { + if (c1 != d1[1+i]) { + i += 2; + continue; + } + i++; + } + + /* Take note if this is the start of a potential match */ + if (0 == j) ii = i; + + /* Shift the test character down by one */ + j++; + i++; + + /* If this isn't past the last character continue */ + if (j < ll) { + c1 = d0[j]; + continue; + } + + N0:; + + /* If no characters mismatched, then we matched */ + if (i == ii+j) return ii; + + /* Shift back to the beginning */ + i -= j; + j = 0; + c1 = c0; + } while (i < lf); + + /* Deal with last case if unrolling caused a misalignment */ + if (i == lf && ll == j+1 && c1 == d1[i]) goto N0; + + return BSTR_ERR; +} + +/* int binstrr (const_bstring b1, int pos, const_bstring b2) + * + * Search for the bstring b2 in b1 starting from position pos, and searching + * backward. If it is found then return with the first position where it is + * found, otherwise return BSTR_ERR. Note that this is just a brute force + * string searcher that does not attempt clever things like the Boyer-Moore + * search algorithm. Because of this there are many degenerate cases where + * this can take much longer than it needs to. + */ +int binstrr (const_bstring b1, int pos, const_bstring b2) { +int j, i, l; +unsigned char * d0, * d1; + + if (b1 == NULL || b1->data == NULL || b1->slen < 0 || + b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR; + if (b1->slen == pos && b2->slen == 0) return pos; + if (b1->slen < pos || pos < 0) return BSTR_ERR; + if (b2->slen == 0) return pos; + + /* Obvious alias case */ + if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return 0; + + i = pos; + if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR; + + /* If no space to find such a string then snap back */ + if (l + 1 <= i) i = l; + j = 0; + + d0 = b2->data; + d1 = b1->data; + l = b2->slen; + + for (;;) { + if (d0[j] == d1[i + j]) { + j ++; + if (j >= l) return i; + } else { + i --; + if (i < 0) break; + j=0; + } + } + + return BSTR_ERR; +} + +/* int binstrcaseless (const_bstring b1, int pos, const_bstring b2) + * + * Search for the bstring b2 in b1 starting from position pos, and searching + * forward but without regard to case. If it is found then return with the + * first position where it is found, otherwise return BSTR_ERR. Note that + * this is just a brute force string searcher that does not attempt clever + * things like the Boyer-Moore search algorithm. Because of this there are + * many degenerate cases where this can take much longer than it needs to. + */ +int binstrcaseless (const_bstring b1, int pos, const_bstring b2) { +int j, i, l, ll; +unsigned char * d0, * d1; + + if (b1 == NULL || b1->data == NULL || b1->slen < 0 || + b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR; + if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR; + if (b1->slen < pos || pos < 0) return BSTR_ERR; + if (b2->slen == 0) return pos; + + l = b1->slen - b2->slen + 1; + + /* No space to find such a string? */ + if (l <= pos) return BSTR_ERR; + + /* An obvious alias case */ + if (b1->data == b2->data && pos == 0) return BSTR_OK; + + i = pos; + j = 0; + + d0 = b2->data; + d1 = b1->data; + ll = b2->slen; + + for (;;) { + if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) { + j ++; + if (j >= ll) return i; + } else { + i ++; + if (i >= l) break; + j=0; + } + } + + return BSTR_ERR; +} + +/* int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) + * + * Search for the bstring b2 in b1 starting from position pos, and searching + * backward but without regard to case. If it is found then return with the + * first position where it is found, otherwise return BSTR_ERR. Note that + * this is just a brute force string searcher that does not attempt clever + * things like the Boyer-Moore search algorithm. Because of this there are + * many degenerate cases where this can take much longer than it needs to. + */ +int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) { +int j, i, l; +unsigned char * d0, * d1; + + if (b1 == NULL || b1->data == NULL || b1->slen < 0 || + b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR; + if (b1->slen == pos && b2->slen == 0) return pos; + if (b1->slen < pos || pos < 0) return BSTR_ERR; + if (b2->slen == 0) return pos; + + /* Obvious alias case */ + if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return BSTR_OK; + + i = pos; + if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR; + + /* If no space to find such a string then snap back */ + if (l + 1 <= i) i = l; + j = 0; + + d0 = b2->data; + d1 = b1->data; + l = b2->slen; + + for (;;) { + if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) { + j ++; + if (j >= l) return i; + } else { + i --; + if (i < 0) break; + j=0; + } + } + + return BSTR_ERR; +} + + +/* int bstrchrp (const_bstring b, int c, int pos) + * + * Search for the character c in b forwards from the position pos + * (inclusive). + */ +int bstrchrp (const_bstring b, int c, int pos) { +unsigned char * p; + + if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR; + p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos)); + if (p) return (int) (p - b->data); + return BSTR_ERR; +} + +/* int bstrrchrp (const_bstring b, int c, int pos) + * + * Search for the character c in b backwards from the position pos in string + * (inclusive). + */ +int bstrrchrp (const_bstring b, int c, int pos) { +int i; + + if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR; + for (i=pos; i >= 0; i--) { + if (b->data[i] == (unsigned char) c) return i; + } + return BSTR_ERR; +} + +#if !defined (BSTRLIB_AGGRESSIVE_MEMORY_FOR_SPEED_TRADEOFF) +#define LONG_LOG_BITS_QTY (3) +#define LONG_BITS_QTY (1 << LONG_LOG_BITS_QTY) +#define LONG_TYPE unsigned char + +#define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY) +struct charField { LONG_TYPE content[CFCLEN]; }; +#define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1)))) +#define setInCharField(cf,idx) { \ + unsigned int c = (unsigned int) (idx); \ + (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \ +} + +#else + +#define CFCLEN (1 << CHAR_BIT) +struct charField { unsigned char content[CFCLEN]; }; +#define testInCharField(cf,c) ((cf)->content[(unsigned char) (c)]) +#define setInCharField(cf,idx) (cf)->content[(unsigned int) (idx)] = ~0 + +#endif + +/* Convert a bstring to charField */ +static int buildCharField (struct charField * cf, const_bstring b) { +int i; + if (b == NULL || b->data == NULL || b->slen <= 0) return BSTR_ERR; + memset ((void *) cf->content, 0, sizeof (struct charField)); + for (i=0; i < b->slen; i++) { + setInCharField (cf, b->data[i]); + } + return BSTR_OK; +} + +static void invertCharField (struct charField * cf) { +int i; + for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i]; +} + +/* Inner engine for binchr */ +static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) { +int i; + for (i=pos; i < len; i++) { + unsigned char c = (unsigned char) data[i]; + if (testInCharField (cf, c)) return i; + } + return BSTR_ERR; +} + +/* int binchr (const_bstring b0, int pos, const_bstring b1); + * + * Search for the first position in b0 starting from pos or after, in which + * one of the characters in b1 is found and return it. If such a position + * does not exist in b0, then BSTR_ERR is returned. + */ +int binchr (const_bstring b0, int pos, const_bstring b1) { +struct charField chrs; + if (pos < 0 || b0 == NULL || b0->data == NULL || + b0->slen <= pos) return BSTR_ERR; + if (1 == b1->slen) return bstrchrp (b0, b1->data[0], pos); + if (0 > buildCharField (&chrs, b1)) return BSTR_ERR; + return binchrCF (b0->data, b0->slen, pos, &chrs); +} + +/* Inner engine for binchrr */ +static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) { +int i; + for (i=pos; i >= 0; i--) { + unsigned int c = (unsigned int) data[i]; + if (testInCharField (cf, c)) return i; + } + return BSTR_ERR; +} + +/* int binchrr (const_bstring b0, int pos, const_bstring b1); + * + * Search for the last position in b0 no greater than pos, in which one of + * the characters in b1 is found and return it. If such a position does not + * exist in b0, then BSTR_ERR is returned. + */ +int binchrr (const_bstring b0, int pos, const_bstring b1) { +struct charField chrs; + if (pos < 0 || b0 == NULL || b0->data == NULL || b1 == NULL || + b0->slen < pos) return BSTR_ERR; + if (pos == b0->slen) pos--; + if (1 == b1->slen) return bstrrchrp (b0, b1->data[0], pos); + if (0 > buildCharField (&chrs, b1)) return BSTR_ERR; + return binchrrCF (b0->data, pos, &chrs); +} + +/* int bninchr (const_bstring b0, int pos, const_bstring b1); + * + * Search for the first position in b0 starting from pos or after, in which + * none of the characters in b1 is found and return it. If such a position + * does not exist in b0, then BSTR_ERR is returned. + */ +int bninchr (const_bstring b0, int pos, const_bstring b1) { +struct charField chrs; + if (pos < 0 || b0 == NULL || b0->data == NULL || + b0->slen <= pos) return BSTR_ERR; + if (buildCharField (&chrs, b1) < 0) return BSTR_ERR; + invertCharField (&chrs); + return binchrCF (b0->data, b0->slen, pos, &chrs); +} + +/* int bninchrr (const_bstring b0, int pos, const_bstring b1); + * + * Search for the last position in b0 no greater than pos, in which none of + * the characters in b1 is found and return it. If such a position does not + * exist in b0, then BSTR_ERR is returned. + */ +int bninchrr (const_bstring b0, int pos, const_bstring b1) { +struct charField chrs; + if (pos < 0 || b0 == NULL || b0->data == NULL || + b0->slen < pos) return BSTR_ERR; + if (pos == b0->slen) pos--; + if (buildCharField (&chrs, b1) < 0) return BSTR_ERR; + invertCharField (&chrs); + return binchrrCF (b0->data, pos, &chrs); +} + +/* int bsetstr (bstring b0, int pos, bstring b1, unsigned char fill) + * + * Overwrite the string b0 starting at position pos with the string b1. If + * the position pos is past the end of b0, then the character "fill" is + * appended as necessary to make up the gap between the end of b0 and pos. + * If b1 is NULL, it behaves as if it were a 0-length string. + */ +int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill) { +int d, newlen; +ptrdiff_t pd; +bstring aux = (bstring) b1; + + if (pos < 0 || b0 == NULL || b0->slen < 0 || NULL == b0->data || + b0->mlen < b0->slen || b0->mlen <= 0) return BSTR_ERR; + if (b1 != NULL && (b1->slen < 0 || b1->data == NULL)) return BSTR_ERR; + + d = pos; + + /* Aliasing case */ + if (NULL != aux) { + if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) { + if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR; + } + d += aux->slen; + } + + /* Increase memory size if necessary */ + if (balloc (b0, d + 1) != BSTR_OK) { + if (aux != b1) bdestroy (aux); + return BSTR_ERR; + } + + newlen = b0->slen; + + /* Fill in "fill" character as necessary */ + if (pos > newlen) { + bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen)); + newlen = pos; + } + + /* Copy b1 to position pos in b0. */ + if (aux != NULL) { + bBlockCopy ((char *) (b0->data + pos), (char *) aux->data, aux->slen); + if (aux != b1) bdestroy (aux); + } + + /* Indicate the potentially increased size of b0 */ + if (d > newlen) newlen = d; + + b0->slen = newlen; + b0->data[newlen] = (unsigned char) '\0'; + + return BSTR_OK; +} + +/* int binsert (bstring b1, int pos, bstring b2, unsigned char fill) + * + * Inserts the string b2 into b1 at position pos. If the position pos is + * past the end of b1, then the character "fill" is appended as necessary to + * make up the gap between the end of b1 and pos. Unlike bsetstr, binsert + * does not allow b2 to be NULL. + */ +int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) { +int d, l; +ptrdiff_t pd; +bstring aux = (bstring) b2; + + if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 || + b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return BSTR_ERR; + + /* Aliasing case */ + if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) { + if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR; + } + + /* Compute the two possible end pointers */ + d = b1->slen + aux->slen; + l = pos + aux->slen; + if ((d|l) < 0) return BSTR_ERR; + + if (l > d) { + /* Inserting past the end of the string */ + if (balloc (b1, l + 1) != BSTR_OK) { + if (aux != b2) bdestroy (aux); + return BSTR_ERR; + } + bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen)); + b1->slen = l; + } else { + /* Inserting in the middle of the string */ + if (balloc (b1, d + 1) != BSTR_OK) { + if (aux != b2) bdestroy (aux); + return BSTR_ERR; + } + bBlockCopy (b1->data + l, b1->data + pos, d - l); + b1->slen = d; + } + bBlockCopy (b1->data + pos, aux->data, aux->slen); + b1->data[b1->slen] = (unsigned char) '\0'; + if (aux != b2) bdestroy (aux); + return BSTR_OK; +} + +/* int breplace (bstring b1, int pos, int len, bstring b2, + * unsigned char fill) + * + * Replace a section of a string from pos for a length len with the string b2. + * fill is used is pos > b1->slen. + */ +int breplace (bstring b1, int pos, int len, const_bstring b2, + unsigned char fill) { +int pl, ret; +ptrdiff_t pd; +bstring aux = (bstring) b2; + + if (pos < 0 || len < 0 || (pl = pos + len) < 0 || b1 == NULL || + b2 == NULL || b1->data == NULL || b2->data == NULL || + b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen || + b1->mlen <= 0) return BSTR_ERR; + + /* Straddles the end? */ + if (pl >= b1->slen) { + if ((ret = bsetstr (b1, pos, b2, fill)) < 0) return ret; + if (pos + b2->slen < b1->slen) { + b1->slen = pos + b2->slen; + b1->data[b1->slen] = (unsigned char) '\0'; + } + return ret; + } + + /* Aliasing case */ + if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) { + if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR; + } + + if (aux->slen > len) { + if (balloc (b1, b1->slen + aux->slen - len) != BSTR_OK) { + if (aux != b2) bdestroy (aux); + return BSTR_ERR; + } + } + + if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len)); + bstr__memcpy (b1->data + pos, aux->data, aux->slen); + b1->slen += aux->slen - len; + b1->data[b1->slen] = (unsigned char) '\0'; + if (aux != b2) bdestroy (aux); + return BSTR_OK; +} + +/* + * findreplaceengine is used to implement bfindreplace and + * bfindreplacecaseless. It works by breaking the three cases of + * expansion, reduction and replacement, and solving each of these + * in the most efficient way possible. + */ + +typedef int (*instr_fnptr) (const_bstring s1, int pos, const_bstring s2); + +#define INITIAL_STATIC_FIND_INDEX_COUNT 32 + +static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) { +int i, ret, slen, mlen, delta, acc; +int * d; +int static_d[INITIAL_STATIC_FIND_INDEX_COUNT+1]; /* This +1 is unnecessary, but it shuts up LINT. */ +ptrdiff_t pd; +bstring auxf = (bstring) find; +bstring auxr = (bstring) repl; + + if (b == NULL || b->data == NULL || find == NULL || + find->data == NULL || repl == NULL || repl->data == NULL || + pos < 0 || find->slen <= 0 || b->mlen < 0 || b->slen > b->mlen || + b->mlen <= 0 || b->slen < 0 || repl->slen < 0) return BSTR_ERR; + if (pos > b->slen - find->slen) return BSTR_OK; + + /* Alias with find string */ + pd = (ptrdiff_t) (find->data - b->data); + if ((ptrdiff_t) (pos - find->slen) < pd && pd < (ptrdiff_t) b->slen) { + if (NULL == (auxf = bstrcpy (find))) return BSTR_ERR; + } + + /* Alias with repl string */ + pd = (ptrdiff_t) (repl->data - b->data); + if ((ptrdiff_t) (pos - repl->slen) < pd && pd < (ptrdiff_t) b->slen) { + if (NULL == (auxr = bstrcpy (repl))) { + if (auxf != find) bdestroy (auxf); + return BSTR_ERR; + } + } + + delta = auxf->slen - auxr->slen; + + /* in-place replacement since find and replace strings are of equal + length */ + if (delta == 0) { + while ((pos = instr (b, pos, auxf)) >= 0) { + bstr__memcpy (b->data + pos, auxr->data, auxr->slen); + pos += auxf->slen; + } + if (auxf != find) bdestroy (auxf); + if (auxr != repl) bdestroy (auxr); + return BSTR_OK; + } + + /* shrinking replacement since auxf->slen > auxr->slen */ + if (delta > 0) { + acc = 0; + + while ((i = instr (b, pos, auxf)) >= 0) { + if (acc && i > pos) + bstr__memmove (b->data + pos - acc, b->data + pos, i - pos); + if (auxr->slen) + bstr__memcpy (b->data + i - acc, auxr->data, auxr->slen); + acc += delta; + pos = i + auxf->slen; + } + + if (acc) { + i = b->slen; + if (i > pos) + bstr__memmove (b->data + pos - acc, b->data + pos, i - pos); + b->slen -= acc; + b->data[b->slen] = (unsigned char) '\0'; + } + + if (auxf != find) bdestroy (auxf); + if (auxr != repl) bdestroy (auxr); + return BSTR_OK; + } + + /* expanding replacement since find->slen < repl->slen. Its a lot + more complicated. This works by first finding all the matches and + storing them to a growable array, then doing at most one resize of + the destination bstring and then performing the direct memory transfers + of the string segment pieces to form the final result. The growable + array of matches uses a deferred doubling reallocing strategy. What + this means is that it starts as a reasonably fixed sized auto array in + the hopes that many if not most cases will never need to grow this + array. But it switches as soon as the bounds of the array will be + exceeded. An extra find result is always appended to this array that + corresponds to the end of the destination string, so slen is checked + against mlen - 1 rather than mlen before resizing. + */ + + mlen = INITIAL_STATIC_FIND_INDEX_COUNT; + d = (int *) static_d; /* Avoid malloc for trivial/initial cases */ + acc = slen = 0; + + while ((pos = instr (b, pos, auxf)) >= 0) { + if (slen >= mlen - 1) { + int sl, *t; + + mlen += mlen; + sl = sizeof (int *) * mlen; + if (static_d == d) d = NULL; /* static_d cannot be realloced */ + if (mlen <= 0 || sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) { + ret = BSTR_ERR; + goto done; + } + if (NULL == d) bstr__memcpy (t, static_d, sizeof (static_d)); + d = t; + } + d[slen] = pos; + slen++; + acc -= delta; + pos += auxf->slen; + if (pos < 0 || acc < 0) { + ret = BSTR_ERR; + goto done; + } + } + + /* slen <= INITIAL_STATIC_INDEX_COUNT-1 or mlen-1 here. */ + d[slen] = b->slen; + + if (BSTR_OK == (ret = balloc (b, b->slen + acc + 1))) { + b->slen += acc; + for (i = slen-1; i >= 0; i--) { + int s, l; + s = d[i] + auxf->slen; + l = d[i+1] - s; /* d[slen] may be accessed here. */ + if (l) { + bstr__memmove (b->data + s + acc, b->data + s, l); + } + if (auxr->slen) { + bstr__memmove (b->data + s + acc - auxr->slen, + auxr->data, auxr->slen); + } + acc += delta; + } + b->data[b->slen] = (unsigned char) '\0'; + } + + done:; + if (static_d == d) d = NULL; + bstr__free (d); + if (auxf != find) bdestroy (auxf); + if (auxr != repl) bdestroy (auxr); + return ret; +} + +/* int bfindreplace (bstring b, const_bstring find, const_bstring repl, + * int pos) + * + * Replace all occurrences of a find string with a replace string after a + * given point in a bstring. + */ +int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos) { + return findreplaceengine (b, find, repl, pos, binstr); +} + +/* int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, + * int pos) + * + * Replace all occurrences of a find string, ignoring case, with a replace + * string after a given point in a bstring. + */ +int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos) { + return findreplaceengine (b, find, repl, pos, binstrcaseless); +} + +/* int binsertch (bstring b, int pos, int len, unsigned char fill) + * + * Inserts the character fill repeatedly into b at position pos for a + * length len. If the position pos is past the end of b, then the + * character "fill" is appended as necessary to make up the gap between the + * end of b and the position pos + len. + */ +int binsertch (bstring b, int pos, int len, unsigned char fill) { +int d, l, i; + + if (pos < 0 || b == NULL || b->slen < 0 || b->mlen < b->slen || + b->mlen <= 0 || len < 0) return BSTR_ERR; + + /* Compute the two possible end pointers */ + d = b->slen + len; + l = pos + len; + if ((d|l) < 0) return BSTR_ERR; + + if (l > d) { + /* Inserting past the end of the string */ + if (balloc (b, l + 1) != BSTR_OK) return BSTR_ERR; + pos = b->slen; + b->slen = l; + } else { + /* Inserting in the middle of the string */ + if (balloc (b, d + 1) != BSTR_OK) return BSTR_ERR; + for (i = d - 1; i >= l; i--) { + b->data[i] = b->data[i - len]; + } + b->slen = d; + } + + for (i=pos; i < l; i++) b->data[i] = fill; + b->data[b->slen] = (unsigned char) '\0'; + return BSTR_OK; +} + +/* int bpattern (bstring b, int len) + * + * Replicate the bstring, b in place, end to end repeatedly until it + * surpasses len characters, then chop the result to exactly len characters. + * This function operates in-place. The function will return with BSTR_ERR + * if b is NULL or of length 0, otherwise BSTR_OK is returned. + */ +int bpattern (bstring b, int len) { +int i, d; + + d = blength (b); + if (d <= 0 || len < 0 || balloc (b, len + 1) != BSTR_OK) return BSTR_ERR; + if (len > 0) { + if (d == 1) return bsetstr (b, len, NULL, b->data[0]); + for (i = d; i < len; i++) b->data[i] = b->data[i - d]; + } + b->data[len] = (unsigned char) '\0'; + b->slen = len; + return BSTR_OK; +} + +#define BS_BUFF_SZ (1024) + +/* int breada (bstring b, bNread readPtr, void * parm) + * + * Use a finite buffer fread-like function readPtr to concatenate to the + * bstring b the entire contents of file-like source data in a roughly + * efficient way. + */ +int breada (bstring b, bNread readPtr, void * parm) { +int i, l, n; + + if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen || + b->mlen <= 0 || readPtr == NULL) return BSTR_ERR; + + i = b->slen; + for (n=i+16; ; n += ((n < BS_BUFF_SZ) ? n : BS_BUFF_SZ)) { + if (BSTR_OK != balloc (b, n + 1)) return BSTR_ERR; + l = (int) readPtr ((void *) (b->data + i), 1, n - i, parm); + i += l; + b->slen = i; + if (i < n) break; + } + + b->data[i] = (unsigned char) '\0'; + return BSTR_OK; +} + +/* bstring bread (bNread readPtr, void * parm) + * + * Use a finite buffer fread-like function readPtr to create a bstring + * filled with the entire contents of file-like source data in a roughly + * efficient way. + */ +bstring bread (bNread readPtr, void * parm) { +bstring buff; + + if (0 > breada (buff = bfromcstr (""), readPtr, parm)) { + bdestroy (buff); + return NULL; + } + return buff; +} + +/* int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) + * + * Use an fgetc-like single character stream reading function (getcPtr) to + * obtain a sequence of characters which are concatenated to the end of the + * bstring b. The stream read is terminated by the passed in terminator + * parameter. + * + * If getcPtr returns with a negative number, or the terminator character + * (which is appended) is read, then the stream reading is halted and the + * function returns with a partial result in b. If there is an empty partial + * result, 1 is returned. If no characters are read, or there is some other + * detectable error, BSTR_ERR is returned. + */ +int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) { +int c, d, e; + + if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen || + b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR; + d = 0; + e = b->mlen - 2; + + while ((c = getcPtr (parm)) >= 0) { + if (d > e) { + b->slen = d; + if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR; + e = b->mlen - 2; + } + b->data[d] = (unsigned char) c; + d++; + if (c == terminator) break; + } + + b->data[d] = (unsigned char) '\0'; + b->slen = d; + + return d == 0 && c < 0; +} + +/* int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) + * + * Use an fgetc-like single character stream reading function (getcPtr) to + * obtain a sequence of characters which are concatenated to the end of the + * bstring b. The stream read is terminated by the passed in terminator + * parameter. + * + * If getcPtr returns with a negative number, or the terminator character + * (which is appended) is read, then the stream reading is halted and the + * function returns with a partial result concatentated to b. If there is + * an empty partial result, 1 is returned. If no characters are read, or + * there is some other detectable error, BSTR_ERR is returned. + */ +int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) { +int c, d, e; + + if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen || + b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR; + d = b->slen; + e = b->mlen - 2; + + while ((c = getcPtr (parm)) >= 0) { + if (d > e) { + b->slen = d; + if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR; + e = b->mlen - 2; + } + b->data[d] = (unsigned char) c; + d++; + if (c == terminator) break; + } + + b->data[d] = (unsigned char) '\0'; + b->slen = d; + + return d == 0 && c < 0; +} + +/* bstring bgets (bNgetc getcPtr, void * parm, char terminator) + * + * Use an fgetc-like single character stream reading function (getcPtr) to + * obtain a sequence of characters which are concatenated into a bstring. + * The stream read is terminated by the passed in terminator function. + * + * If getcPtr returns with a negative number, or the terminator character + * (which is appended) is read, then the stream reading is halted and the + * result obtained thus far is returned. If no characters are read, or + * there is some other detectable error, NULL is returned. + */ +bstring bgets (bNgetc getcPtr, void * parm, char terminator) { +bstring buff; + + if (0 > bgetsa (buff = bfromcstr (""), getcPtr, parm, terminator) || 0 >= buff->slen) { + bdestroy (buff); + buff = NULL; + } + return buff; +} + +struct bStream { + bstring buff; /* Buffer for over-reads */ + void * parm; /* The stream handle for core stream */ + bNread readFnPtr; /* fread compatible fnptr for core stream */ + int isEOF; /* track file's EOF state */ + int maxBuffSz; +}; + +/* struct bStream * bsopen (bNread readPtr, void * parm) + * + * Wrap a given open stream (described by a fread compatible function + * pointer and stream handle) into an open bStream suitable for the bstring + * library streaming functions. + */ +struct bStream * bsopen (bNread readPtr, void * parm) { +struct bStream * s; + + if (readPtr == NULL) return NULL; + s = (struct bStream *) bstr__alloc (sizeof (struct bStream)); + if (s == NULL) return NULL; + s->parm = parm; + s->buff = bfromcstr (""); + s->readFnPtr = readPtr; + s->maxBuffSz = BS_BUFF_SZ; + s->isEOF = 0; + return s; +} + +/* int bsbufflength (struct bStream * s, int sz) + * + * Set the length of the buffer used by the bStream. If sz is zero, the + * length is not set. This function returns with the previous length. + */ +int bsbufflength (struct bStream * s, int sz) { +int oldSz; + if (s == NULL || sz < 0) return BSTR_ERR; + oldSz = s->maxBuffSz; + if (sz > 0) s->maxBuffSz = sz; + return oldSz; +} + +int bseof (const struct bStream * s) { + if (s == NULL || s->readFnPtr == NULL) return BSTR_ERR; + return s->isEOF && (s->buff->slen == 0); +} + +/* void * bsclose (struct bStream * s) + * + * Close the bStream, and return the handle to the stream that was originally + * used to open the given stream. + */ +void * bsclose (struct bStream * s) { +void * parm; + if (s == NULL) return NULL; + s->readFnPtr = NULL; + if (s->buff) bdestroy (s->buff); + s->buff = NULL; + parm = s->parm; + s->parm = NULL; + s->isEOF = 1; + bstr__free (s); + return parm; +} + +/* int bsreadlna (bstring r, struct bStream * s, char terminator) + * + * Read a bstring terminated by the terminator character or the end of the + * stream from the bStream (s) and return it into the parameter r. This + * function may read additional characters from the core stream that are not + * returned, but will be retained for subsequent read operations. + */ +int bsreadlna (bstring r, struct bStream * s, char terminator) { +int i, l, ret, rlo; +char * b; +struct tagbstring x; + + if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 || + r->slen < 0 || r->mlen < r->slen) return BSTR_ERR; + l = s->buff->slen; + if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR; + b = (char *) s->buff->data; + x.data = (unsigned char *) b; + + /* First check if the current buffer holds the terminator */ + b[l] = terminator; /* Set sentinel */ + for (i=0; b[i] != terminator; i++) ; + if (i < l) { + x.slen = i + 1; + ret = bconcat (r, &x); + s->buff->slen = l; + if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1); + return BSTR_OK; + } + + rlo = r->slen; + + /* If not then just concatenate the entire buffer to the output */ + x.slen = l; + if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR; + + /* Perform direct in-place reads into the destination to allow for + the minimum of data-copies */ + for (;;) { + if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR; + b = (char *) (r->data + r->slen); + l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm); + if (l <= 0) { + r->data[r->slen] = (unsigned char) '\0'; + s->buff->slen = 0; + s->isEOF = 1; + /* If nothing was read return with an error message */ + return BSTR_ERR & -(r->slen == rlo); + } + b[l] = terminator; /* Set sentinel */ + for (i=0; b[i] != terminator; i++) ; + if (i < l) break; + r->slen += l; + } + + /* Terminator found, push over-read back to buffer */ + i++; + r->slen += i; + s->buff->slen = l - i; + bstr__memcpy (s->buff->data, b + i, l - i); + r->data[r->slen] = (unsigned char) '\0'; + return BSTR_OK; +} + +/* int bsreadlnsa (bstring r, struct bStream * s, bstring term) + * + * Read a bstring terminated by any character in the term string or the end + * of the stream from the bStream (s) and return it into the parameter r. + * This function may read additional characters from the core stream that + * are not returned, but will be retained for subsequent read operations. + */ +int bsreadlnsa (bstring r, struct bStream * s, const_bstring term) { +int i, l, ret, rlo; +unsigned char * b; +struct tagbstring x; +struct charField cf; + + if (s == NULL || s->buff == NULL || r == NULL || term == NULL || + term->data == NULL || r->mlen <= 0 || r->slen < 0 || + r->mlen < r->slen) return BSTR_ERR; + if (term->slen == 1) return bsreadlna (r, s, term->data[0]); + if (term->slen < 1 || buildCharField (&cf, term)) return BSTR_ERR; + + l = s->buff->slen; + if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR; + b = (unsigned char *) s->buff->data; + x.data = b; + + /* First check if the current buffer holds the terminator */ + b[l] = term->data[0]; /* Set sentinel */ + for (i=0; !testInCharField (&cf, b[i]); i++) ; + if (i < l) { + x.slen = i + 1; + ret = bconcat (r, &x); + s->buff->slen = l; + if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1); + return BSTR_OK; + } + + rlo = r->slen; + + /* If not then just concatenate the entire buffer to the output */ + x.slen = l; + if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR; + + /* Perform direct in-place reads into the destination to allow for + the minimum of data-copies */ + for (;;) { + if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR; + b = (unsigned char *) (r->data + r->slen); + l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm); + if (l <= 0) { + r->data[r->slen] = (unsigned char) '\0'; + s->buff->slen = 0; + s->isEOF = 1; + /* If nothing was read return with an error message */ + return BSTR_ERR & -(r->slen == rlo); + } + + b[l] = term->data[0]; /* Set sentinel */ + for (i=0; !testInCharField (&cf, b[i]); i++) ; + if (i < l) break; + r->slen += l; + } + + /* Terminator found, push over-read back to buffer */ + i++; + r->slen += i; + s->buff->slen = l - i; + bstr__memcpy (s->buff->data, b + i, l - i); + r->data[r->slen] = (unsigned char) '\0'; + return BSTR_OK; +} + +/* int bsreada (bstring r, struct bStream * s, int n) + * + * Read a bstring of length n (or, if it is fewer, as many bytes as is + * remaining) from the bStream. This function may read additional + * characters from the core stream that are not returned, but will be + * retained for subsequent read operations. This function will not read + * additional characters from the core stream beyond virtual stream pointer. + */ +int bsreada (bstring r, struct bStream * s, int n) { +int l, ret, orslen; +char * b; +struct tagbstring x; + + if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 + || r->slen < 0 || r->mlen < r->slen || n <= 0) return BSTR_ERR; + + n += r->slen; + if (n <= 0) return BSTR_ERR; + + l = s->buff->slen; + + orslen = r->slen; + + if (0 == l) { + if (s->isEOF) return BSTR_ERR; + if (r->mlen > n) { + l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm); + if (0 >= l || l > n - r->slen) { + s->isEOF = 1; + return BSTR_ERR; + } + r->slen += l; + r->data[r->slen] = (unsigned char) '\0'; + return 0; + } + } + + if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR; + b = (char *) s->buff->data; + x.data = (unsigned char *) b; + + do { + if (l + r->slen >= n) { + x.slen = n - r->slen; + ret = bconcat (r, &x); + s->buff->slen = l; + if (BSTR_OK == ret) bdelete (s->buff, 0, x.slen); + return BSTR_ERR & -(r->slen == orslen); + } + + x.slen = l; + if (BSTR_OK != bconcat (r, &x)) break; + + l = n - r->slen; + if (l > s->maxBuffSz) l = s->maxBuffSz; + + l = (int) s->readFnPtr (b, 1, l, s->parm); + + } while (l > 0); + if (l < 0) l = 0; + if (l == 0) s->isEOF = 1; + s->buff->slen = l; + return BSTR_ERR & -(r->slen == orslen); +} + +/* int bsreadln (bstring r, struct bStream * s, char terminator) + * + * Read a bstring terminated by the terminator character or the end of the + * stream from the bStream (s) and return it into the parameter r. This + * function may read additional characters from the core stream that are not + * returned, but will be retained for subsequent read operations. + */ +int bsreadln (bstring r, struct bStream * s, char terminator) { + if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0) + return BSTR_ERR; + if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR; + r->slen = 0; + return bsreadlna (r, s, terminator); +} + +/* int bsreadlns (bstring r, struct bStream * s, bstring term) + * + * Read a bstring terminated by any character in the term string or the end + * of the stream from the bStream (s) and return it into the parameter r. + * This function may read additional characters from the core stream that + * are not returned, but will be retained for subsequent read operations. + */ +int bsreadlns (bstring r, struct bStream * s, const_bstring term) { + if (s == NULL || s->buff == NULL || r == NULL || term == NULL + || term->data == NULL || r->mlen <= 0) return BSTR_ERR; + if (term->slen == 1) return bsreadln (r, s, term->data[0]); + if (term->slen < 1) return BSTR_ERR; + if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR; + r->slen = 0; + return bsreadlnsa (r, s, term); +} + +/* int bsread (bstring r, struct bStream * s, int n) + * + * Read a bstring of length n (or, if it is fewer, as many bytes as is + * remaining) from the bStream. This function may read additional + * characters from the core stream that are not returned, but will be + * retained for subsequent read operations. This function will not read + * additional characters from the core stream beyond virtual stream pointer. + */ +int bsread (bstring r, struct bStream * s, int n) { + if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 + || n <= 0) return BSTR_ERR; + if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR; + r->slen = 0; + return bsreada (r, s, n); +} + +/* int bsunread (struct bStream * s, const_bstring b) + * + * Insert a bstring into the bStream at the current position. These + * characters will be read prior to those that actually come from the core + * stream. + */ +int bsunread (struct bStream * s, const_bstring b) { + if (s == NULL || s->buff == NULL) return BSTR_ERR; + return binsert (s->buff, 0, b, (unsigned char) '?'); +} + +/* int bspeek (bstring r, const struct bStream * s) + * + * Return the currently buffered characters from the bStream that will be + * read prior to reads from the core stream. + */ +int bspeek (bstring r, const struct bStream * s) { + if (s == NULL || s->buff == NULL) return BSTR_ERR; + return bassign (r, s->buff); +} + +/* bstring bjoin (const struct bstrList * bl, const_bstring sep); + * + * Join the entries of a bstrList into one bstring by sequentially + * concatenating them with the sep string in between. If there is an error + * NULL is returned, otherwise a bstring with the correct result is returned. + */ +bstring bjoin (const struct bstrList * bl, const_bstring sep) { +bstring b; +int i, c, v; + + if (bl == NULL || bl->qty < 0) return NULL; + if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL; + + for (i = 0, c = 1; i < bl->qty; i++) { + v = bl->entry[i]->slen; + if (v < 0) return NULL; /* Invalid input */ + c += v; + if (c < 0) return NULL; /* Wrap around ?? */ + } + + if (sep != NULL) c += (bl->qty - 1) * sep->slen; + + b = (bstring) bstr__alloc (sizeof (struct tagbstring)); + if (NULL == b) return NULL; /* Out of memory */ + b->data = (unsigned char *) bstr__alloc (c); + if (b->data == NULL) { + bstr__free (b); + return NULL; + } + + b->mlen = c; + b->slen = c-1; + + for (i = 0, c = 0; i < bl->qty; i++) { + if (i > 0 && sep != NULL) { + bstr__memcpy (b->data + c, sep->data, sep->slen); + c += sep->slen; + } + v = bl->entry[i]->slen; + bstr__memcpy (b->data + c, bl->entry[i]->data, v); + c += v; + } + b->data[c] = (unsigned char) '\0'; + return b; +} + +#define BSSSC_BUFF_LEN (256) + +/* int bssplitscb (struct bStream * s, const_bstring splitStr, + * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) + * + * Iterate the set of disjoint sequential substrings read from a stream + * divided by any of the characters in splitStr. An empty splitStr causes + * the whole stream to be iterated once. + * + * Note: At the point of calling the cb function, the bStream pointer is + * pointed exactly at the position right after having read the split + * character. The cb function can act on the stream by causing the bStream + * pointer to move, and bssplitscb will continue by starting the next split + * at the position of the pointer after the return from cb. + * + * However, if the cb causes the bStream s to be destroyed then the cb must + * return with a negative value, otherwise bssplitscb will continue in an + * undefined manner. + */ +int bssplitscb (struct bStream * s, const_bstring splitStr, + int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) { +struct charField chrs; +bstring buff; +int i, p, ret; + + if (cb == NULL || s == NULL || s->readFnPtr == NULL + || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR; + + if (NULL == (buff = bfromcstr (""))) return BSTR_ERR; + + if (splitStr->slen == 0) { + while (bsreada (buff, s, BSSSC_BUFF_LEN) >= 0) ; + if ((ret = cb (parm, 0, buff)) > 0) + ret = 0; + } else { + buildCharField (&chrs, splitStr); + ret = p = i = 0; + for (;;) { + if (i >= buff->slen) { + bsreada (buff, s, BSSSC_BUFF_LEN); + if (i >= buff->slen) { + if (0 < (ret = cb (parm, p, buff))) ret = 0; + break; + } + } + if (testInCharField (&chrs, buff->data[i])) { + struct tagbstring t; + unsigned char c; + + blk2tbstr (t, buff->data + i + 1, buff->slen - (i + 1)); + if ((ret = bsunread (s, &t)) < 0) break; + buff->slen = i; + c = buff->data[i]; + buff->data[i] = (unsigned char) '\0'; + if ((ret = cb (parm, p, buff)) < 0) break; + buff->data[i] = c; + buff->slen = 0; + p += i + 1; + i = -1; + } + i++; + } + } + + bdestroy (buff); + return ret; +} + +/* int bssplitstrcb (struct bStream * s, const_bstring splitStr, + * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) + * + * Iterate the set of disjoint sequential substrings read from a stream + * divided by the entire substring splitStr. An empty splitStr causes + * each character of the stream to be iterated. + * + * Note: At the point of calling the cb function, the bStream pointer is + * pointed exactly at the position right after having read the split + * character. The cb function can act on the stream by causing the bStream + * pointer to move, and bssplitscb will continue by starting the next split + * at the position of the pointer after the return from cb. + * + * However, if the cb causes the bStream s to be destroyed then the cb must + * return with a negative value, otherwise bssplitscb will continue in an + * undefined manner. + */ +int bssplitstrcb (struct bStream * s, const_bstring splitStr, + int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) { +bstring buff; +int i, p, ret; + + if (cb == NULL || s == NULL || s->readFnPtr == NULL + || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR; + + if (splitStr->slen == 1) return bssplitscb (s, splitStr, cb, parm); + + if (NULL == (buff = bfromcstr (""))) return BSTR_ERR; + + if (splitStr->slen == 0) { + for (i=0; bsreada (buff, s, BSSSC_BUFF_LEN) >= 0; i++) { + if ((ret = cb (parm, 0, buff)) < 0) { + bdestroy (buff); + return ret; + } + buff->slen = 0; + } + return BSTR_OK; + } else { + ret = p = i = 0; + for (i=p=0;;) { + if ((ret = binstr (buff, 0, splitStr)) >= 0) { + struct tagbstring t; + blk2tbstr (t, buff->data, ret); + i = ret + splitStr->slen; + if ((ret = cb (parm, p, &t)) < 0) break; + p += i; + bdelete (buff, 0, i); + } else { + bsreada (buff, s, BSSSC_BUFF_LEN); + if (bseof (s)) { + if ((ret = cb (parm, p, buff)) > 0) ret = 0; + break; + } + } + } + } + + bdestroy (buff); + return ret; +} + +/* int bstrListCreate (void) + * + * Create a bstrList. + */ +struct bstrList * bstrListCreate (void) { +struct bstrList * sl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList)); + if (sl) { + sl->entry = (bstring *) bstr__alloc (1*sizeof (bstring)); + if (!sl->entry) { + bstr__free (sl); + sl = NULL; + } else { + sl->qty = 0; + sl->mlen = 1; + } + } + return sl; +} + +/* int bstrListDestroy (struct bstrList * sl) + * + * Destroy a bstrList that has been created by bsplit, bsplits or bstrListCreate. + */ +int bstrListDestroy (struct bstrList * sl) { +int i; + if (sl == NULL || sl->qty < 0) return BSTR_ERR; + for (i=0; i < sl->qty; i++) { + if (sl->entry[i]) { + bdestroy (sl->entry[i]); + sl->entry[i] = NULL; + } + } + sl->qty = -1; + sl->mlen = -1; + bstr__free (sl->entry); + sl->entry = NULL; + bstr__free (sl); + return BSTR_OK; +} + +/* int bstrListAlloc (struct bstrList * sl, int msz) + * + * Ensure that there is memory for at least msz number of entries for the + * list. + */ +int bstrListAlloc (struct bstrList * sl, int msz) { +bstring * l; +int smsz; +size_t nsz; + if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR; + if (sl->mlen >= msz) return BSTR_OK; + smsz = snapUpSize (msz); + nsz = ((size_t) smsz) * sizeof (bstring); + if (nsz < (size_t) smsz) return BSTR_ERR; + l = (bstring *) bstr__realloc (sl->entry, nsz); + if (!l) { + smsz = msz; + nsz = ((size_t) smsz) * sizeof (bstring); + l = (bstring *) bstr__realloc (sl->entry, nsz); + if (!l) return BSTR_ERR; + } + sl->mlen = smsz; + sl->entry = l; + return BSTR_OK; +} + +/* int bstrListAllocMin (struct bstrList * sl, int msz) + * + * Try to allocate the minimum amount of memory for the list to include at + * least msz entries or sl->qty whichever is greater. + */ +int bstrListAllocMin (struct bstrList * sl, int msz) { +bstring * l; +size_t nsz; + if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR; + if (msz < sl->qty) msz = sl->qty; + if (sl->mlen == msz) return BSTR_OK; + nsz = ((size_t) msz) * sizeof (bstring); + if (nsz < (size_t) msz) return BSTR_ERR; + l = (bstring *) bstr__realloc (sl->entry, nsz); + if (!l) return BSTR_ERR; + sl->mlen = msz; + sl->entry = l; + return BSTR_OK; +} + +/* int bsplitcb (const_bstring str, unsigned char splitChar, int pos, + * int (* cb) (void * parm, int ofs, int len), void * parm) + * + * Iterate the set of disjoint sequential substrings over str divided by the + * character in splitChar. + * + * Note: Non-destructive modification of str from within the cb function + * while performing this split is not undefined. bsplitcb behaves in + * sequential lock step with calls to cb. I.e., after returning from a cb + * that return a non-negative integer, bsplitcb continues from the position + * 1 character after the last detected split character and it will halt + * immediately if the length of str falls below this point. However, if the + * cb function destroys str, then it *must* return with a negative value, + * otherwise bsplitcb will continue in an undefined manner. + */ +int bsplitcb (const_bstring str, unsigned char splitChar, int pos, + int (* cb) (void * parm, int ofs, int len), void * parm) { +int i, p, ret; + + if (cb == NULL || str == NULL || pos < 0 || pos > str->slen) + return BSTR_ERR; + + p = pos; + do { + for (i=p; i < str->slen; i++) { + if (str->data[i] == splitChar) break; + } + if ((ret = cb (parm, p, i - p)) < 0) return ret; + p = i + 1; + } while (p <= str->slen); + return BSTR_OK; +} + +/* int bsplitscb (const_bstring str, const_bstring splitStr, int pos, + * int (* cb) (void * parm, int ofs, int len), void * parm) + * + * Iterate the set of disjoint sequential substrings over str divided by any + * of the characters in splitStr. An empty splitStr causes the whole str to + * be iterated once. + * + * Note: Non-destructive modification of str from within the cb function + * while performing this split is not undefined. bsplitscb behaves in + * sequential lock step with calls to cb. I.e., after returning from a cb + * that return a non-negative integer, bsplitscb continues from the position + * 1 character after the last detected split character and it will halt + * immediately if the length of str falls below this point. However, if the + * cb function destroys str, then it *must* return with a negative value, + * otherwise bsplitscb will continue in an undefined manner. + */ +int bsplitscb (const_bstring str, const_bstring splitStr, int pos, + int (* cb) (void * parm, int ofs, int len), void * parm) { +struct charField chrs; +int i, p, ret; + + if (cb == NULL || str == NULL || pos < 0 || pos > str->slen + || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR; + if (splitStr->slen == 0) { + if ((ret = cb (parm, 0, str->slen)) > 0) ret = 0; + return ret; + } + + if (splitStr->slen == 1) + return bsplitcb (str, splitStr->data[0], pos, cb, parm); + + buildCharField (&chrs, splitStr); + + p = pos; + do { + for (i=p; i < str->slen; i++) { + if (testInCharField (&chrs, str->data[i])) break; + } + if ((ret = cb (parm, p, i - p)) < 0) return ret; + p = i + 1; + } while (p <= str->slen); + return BSTR_OK; +} + +/* int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos, + * int (* cb) (void * parm, int ofs, int len), void * parm) + * + * Iterate the set of disjoint sequential substrings over str divided by the + * substring splitStr. An empty splitStr causes the whole str to be + * iterated once. + * + * Note: Non-destructive modification of str from within the cb function + * while performing this split is not undefined. bsplitstrcb behaves in + * sequential lock step with calls to cb. I.e., after returning from a cb + * that return a non-negative integer, bsplitscb continues from the position + * 1 character after the last detected split character and it will halt + * immediately if the length of str falls below this point. However, if the + * cb function destroys str, then it *must* return with a negative value, + * otherwise bsplitscb will continue in an undefined manner. + */ +int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos, + int (* cb) (void * parm, int ofs, int len), void * parm) { +int i, p, ret; + + if (cb == NULL || str == NULL || pos < 0 || pos > str->slen + || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR; + + if (0 == splitStr->slen) { + for (i=pos; i < str->slen; i++) { + if ((ret = cb (parm, i, 1)) < 0) return ret; + } + return BSTR_OK; + } + + if (splitStr->slen == 1) + return bsplitcb (str, splitStr->data[0], pos, cb, parm); + + for (i=p=pos; i <= str->slen - splitStr->slen; i++) { + if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) { + if ((ret = cb (parm, p, i - p)) < 0) return ret; + i += splitStr->slen; + p = i; + } + } + if ((ret = cb (parm, p, str->slen - p)) < 0) return ret; + return BSTR_OK; +} + +struct genBstrList { + bstring b; + struct bstrList * bl; +}; + +static int bscb (void * parm, int ofs, int len) { +struct genBstrList * g = (struct genBstrList *) parm; + if (g->bl->qty >= g->bl->mlen) { + int mlen = g->bl->mlen * 2; + bstring * tbl; + + while (g->bl->qty >= mlen) { + if (mlen < g->bl->mlen) return BSTR_ERR; + mlen += mlen; + } + + tbl = (bstring *) bstr__realloc (g->bl->entry, sizeof (bstring) * mlen); + if (tbl == NULL) return BSTR_ERR; + + g->bl->entry = tbl; + g->bl->mlen = mlen; + } + + g->bl->entry[g->bl->qty] = bmidstr (g->b, ofs, len); + g->bl->qty++; + return BSTR_OK; +} + +/* struct bstrList * bsplit (const_bstring str, unsigned char splitChar) + * + * Create an array of sequential substrings from str divided by the character + * splitChar. + */ +struct bstrList * bsplit (const_bstring str, unsigned char splitChar) { +struct genBstrList g; + + if (str == NULL || str->data == NULL || str->slen < 0) return NULL; + + g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList)); + if (g.bl == NULL) return NULL; + g.bl->mlen = 4; + g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring)); + if (NULL == g.bl->entry) { + bstr__free (g.bl); + return NULL; + } + + g.b = (bstring) str; + g.bl->qty = 0; + if (bsplitcb (str, splitChar, 0, bscb, &g) < 0) { + bstrListDestroy (g.bl); + return NULL; + } + return g.bl; +} + +/* struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) + * + * Create an array of sequential substrings from str divided by the entire + * substring splitStr. + */ +struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) { +struct genBstrList g; + + if (str == NULL || str->data == NULL || str->slen < 0) return NULL; + + g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList)); + if (g.bl == NULL) return NULL; + g.bl->mlen = 4; + g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring)); + if (NULL == g.bl->entry) { + bstr__free (g.bl); + return NULL; + } + + g.b = (bstring) str; + g.bl->qty = 0; + if (bsplitstrcb (str, splitStr, 0, bscb, &g) < 0) { + bstrListDestroy (g.bl); + return NULL; + } + return g.bl; +} + +/* struct bstrList * bsplits (const_bstring str, bstring splitStr) + * + * Create an array of sequential substrings from str divided by any of the + * characters in splitStr. An empty splitStr causes a single entry bstrList + * containing a copy of str to be returned. + */ +struct bstrList * bsplits (const_bstring str, const_bstring splitStr) { +struct genBstrList g; + + if ( str == NULL || str->slen < 0 || str->data == NULL || + splitStr == NULL || splitStr->slen < 0 || splitStr->data == NULL) + return NULL; + + g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList)); + if (g.bl == NULL) return NULL; + g.bl->mlen = 4; + g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring)); + if (NULL == g.bl->entry) { + bstr__free (g.bl); + return NULL; + } + g.b = (bstring) str; + g.bl->qty = 0; + + if (bsplitscb (str, splitStr, 0, bscb, &g) < 0) { + bstrListDestroy (g.bl); + return NULL; + } + return g.bl; +} + +#if defined (__TURBOC__) && !defined (__BORLANDC__) +# ifndef BSTRLIB_NOVSNP +# define BSTRLIB_NOVSNP +# endif +#endif + +/* Give WATCOM C/C++, MSVC some latitude for their non-support of vsnprintf */ +#if defined(__WATCOMC__) || defined(_MSC_VER) +#define exvsnprintf(r,b,n,f,a) {r = _vsnprintf (b,n,f,a);} +#else +#ifdef BSTRLIB_NOVSNP +/* This is just a hack. If you are using a system without a vsnprintf, it is + not recommended that bformat be used at all. */ +#define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;} +#define START_VSNBUFF (256) +#else + +#ifdef __GNUC__ +/* Something is making gcc complain about this prototype not being here, so + I've just gone ahead and put it in. */ +extern int vsnprintf (char *buf, size_t count, const char *format, va_list arg); +#endif + +#define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);} +#endif +#endif + +#if !defined (BSTRLIB_NOVSNP) + +#ifndef START_VSNBUFF +#define START_VSNBUFF (16) +#endif + +/* On IRIX vsnprintf returns n-1 when the operation would overflow the target + buffer, WATCOM and MSVC both return -1, while C99 requires that the + returned value be exactly what the length would be if the buffer would be + large enough. This leads to the idea that if the return value is larger + than n, then changing n to the return value will reduce the number of + iterations required. */ + +/* int bformata (bstring b, const char * fmt, ...) + * + * After the first parameter, it takes the same parameters as printf (), but + * rather than outputting results to stdio, it appends the results to + * a bstring which contains what would have been output. Note that if there + * is an early generation of a '\0' character, the bstring will be truncated + * to this end point. + */ +int bformata (bstring b, const char * fmt, ...) { +va_list arglist; +bstring buff; +int n, r; + + if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 + || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR; + + /* Since the length is not determinable beforehand, a search is + performed using the truncating "vsnprintf" call (to avoid buffer + overflows) on increasing potential sizes for the output result. */ + + if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF; + if (NULL == (buff = bfromcstralloc (n + 2, ""))) { + n = 1; + if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR; + } + + for (;;) { + va_start (arglist, fmt); + exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist); + va_end (arglist); + + buff->data[n] = (unsigned char) '\0'; + buff->slen = (int) (strlen) ((char *) buff->data); + + if (buff->slen < n) break; + + if (r > n) n = r; else n += n; + + if (BSTR_OK != balloc (buff, n + 2)) { + bdestroy (buff); + return BSTR_ERR; + } + } + + r = bconcat (b, buff); + bdestroy (buff); + return r; +} + +/* int bassignformat (bstring b, const char * fmt, ...) + * + * After the first parameter, it takes the same parameters as printf (), but + * rather than outputting results to stdio, it outputs the results to + * the bstring parameter b. Note that if there is an early generation of a + * '\0' character, the bstring will be truncated to this end point. + */ +int bassignformat (bstring b, const char * fmt, ...) { +va_list arglist; +bstring buff; +int n, r; + + if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 + || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR; + + /* Since the length is not determinable beforehand, a search is + performed using the truncating "vsnprintf" call (to avoid buffer + overflows) on increasing potential sizes for the output result. */ + + if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF; + if (NULL == (buff = bfromcstralloc (n + 2, ""))) { + n = 1; + if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR; + } + + for (;;) { + va_start (arglist, fmt); + exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist); + va_end (arglist); + + buff->data[n] = (unsigned char) '\0'; + buff->slen = (int) (strlen) ((char *) buff->data); + + if (buff->slen < n) break; + + if (r > n) n = r; else n += n; + + if (BSTR_OK != balloc (buff, n + 2)) { + bdestroy (buff); + return BSTR_ERR; + } + } + + r = bassign (b, buff); + bdestroy (buff); + return r; +} + +/* bstring bformat (const char * fmt, ...) + * + * Takes the same parameters as printf (), but rather than outputting results + * to stdio, it forms a bstring which contains what would have been output. + * Note that if there is an early generation of a '\0' character, the + * bstring will be truncated to this end point. + */ +bstring bformat (const char * fmt, ...) { +va_list arglist; +bstring buff; +int n, r; + + if (fmt == NULL) return NULL; + + /* Since the length is not determinable beforehand, a search is + performed using the truncating "vsnprintf" call (to avoid buffer + overflows) on increasing potential sizes for the output result. */ + + if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF; + if (NULL == (buff = bfromcstralloc (n + 2, ""))) { + n = 1; + if (NULL == (buff = bfromcstralloc (n + 2, ""))) return NULL; + } + + for (;;) { + va_start (arglist, fmt); + exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist); + va_end (arglist); + + buff->data[n] = (unsigned char) '\0'; + buff->slen = (int) (strlen) ((char *) buff->data); + + if (buff->slen < n) break; + + if (r > n) n = r; else n += n; + + if (BSTR_OK != balloc (buff, n + 2)) { + bdestroy (buff); + return NULL; + } + } + + return buff; +} + +/* int bvcformata (bstring b, int count, const char * fmt, va_list arglist) + * + * The bvcformata function formats data under control of the format control + * string fmt and attempts to append the result to b. The fmt parameter is + * the same as that of the printf function. The variable argument list is + * replaced with arglist, which has been initialized by the va_start macro. + * The size of the appended output is upper bounded by count. If the + * required output exceeds count, the string b is not augmented with any + * contents and a value below BSTR_ERR is returned. If a value below -count + * is returned then it is recommended that the negative of this value be + * used as an update to the count in a subsequent pass. On other errors, + * such as running out of memory, parameter errors or numeric wrap around + * BSTR_ERR is returned. BSTR_OK is returned when the output is successfully + * generated and appended to b. + * + * Note: There is no sanity checking of arglist, and this function is + * destructive of the contents of b from the b->slen point onward. If there + * is an early generation of a '\0' character, the bstring will be truncated + * to this end point. + */ +int bvcformata (bstring b, int count, const char * fmt, va_list arg) { +int n, r, l; + + if (b == NULL || fmt == NULL || count <= 0 || b->data == NULL + || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR; + + if (count > (n = b->slen + count) + 2) return BSTR_ERR; + if (BSTR_OK != balloc (b, n + 2)) return BSTR_ERR; + + exvsnprintf (r, (char *) b->data + b->slen, count + 2, fmt, arg); + + /* Did the operation complete successfully within bounds? */ + for (l = b->slen; l <= n; l++) { + if ('\0' == b->data[l]) { + b->slen = l; + return BSTR_OK; + } + } + + /* Abort, since the buffer was not large enough. The return value + tries to help set what the retry length should be. */ + + b->data[b->slen] = '\0'; + if (r > count + 1) { /* Does r specify a particular target length? */ + n = r; + } else { + n = count + count; /* If not, just double the size of count */ + if (count > n) n = INT_MAX; + } + n = -n; + + if (n > BSTR_ERR-1) n = BSTR_ERR-1; + return n; +} + +#endif diff --git a/devpkg/bstrlib.h b/devpkg/bstrlib.h new file mode 100644 index 0000000..c8fa694 --- /dev/null +++ b/devpkg/bstrlib.h @@ -0,0 +1,304 @@ +/* + * This source file is part of the bstring string library. This code was + * written by Paul Hsieh in 2002-2010, and is covered by either the 3-clause + * BSD open source license or GPL v2.0. Refer to the accompanying documentation + * for details on usage and license. + */ + +/* + * bstrlib.h + * + * This file is the header file for the core module for implementing the + * bstring functions. + */ + +#ifndef BSTRLIB_INCLUDE +#define BSTRLIB_INCLUDE + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#if !defined (BSTRLIB_VSNP_OK) && !defined (BSTRLIB_NOVSNP) +# if defined (__TURBOC__) && !defined (__BORLANDC__) +# define BSTRLIB_NOVSNP +# endif +#endif + +#define BSTR_ERR (-1) +#define BSTR_OK (0) +#define BSTR_BS_BUFF_LENGTH_GET (0) + +typedef struct tagbstring * bstring; +typedef const struct tagbstring * const_bstring; + +/* Copy functions */ +#define cstr2bstr bfromcstr +extern bstring bfromcstr (const char * str); +extern bstring bfromcstralloc (int mlen, const char * str); +extern bstring blk2bstr (const void * blk, int len); +extern char * bstr2cstr (const_bstring s, char z); +extern int bcstrfree (char * s); +extern bstring bstrcpy (const_bstring b1); +extern int bassign (bstring a, const_bstring b); +extern int bassignmidstr (bstring a, const_bstring b, int left, int len); +extern int bassigncstr (bstring a, const char * str); +extern int bassignblk (bstring a, const void * s, int len); + +/* Destroy function */ +extern int bdestroy (bstring b); + +/* Space allocation hinting functions */ +extern int balloc (bstring s, int len); +extern int ballocmin (bstring b, int len); + +/* Substring extraction */ +extern bstring bmidstr (const_bstring b, int left, int len); + +/* Various standard manipulations */ +extern int bconcat (bstring b0, const_bstring b1); +extern int bconchar (bstring b0, char c); +extern int bcatcstr (bstring b, const char * s); +extern int bcatblk (bstring b, const void * s, int len); +extern int binsert (bstring s1, int pos, const_bstring s2, unsigned char fill); +extern int binsertch (bstring s1, int pos, int len, unsigned char fill); +extern int breplace (bstring b1, int pos, int len, const_bstring b2, unsigned char fill); +extern int bdelete (bstring s1, int pos, int len); +extern int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill); +extern int btrunc (bstring b, int n); + +/* Scan/search functions */ +extern int bstricmp (const_bstring b0, const_bstring b1); +extern int bstrnicmp (const_bstring b0, const_bstring b1, int n); +extern int biseqcaseless (const_bstring b0, const_bstring b1); +extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); +extern int biseq (const_bstring b0, const_bstring b1); +extern int bisstemeqblk (const_bstring b0, const void * blk, int len); +extern int biseqcstr (const_bstring b, const char * s); +extern int biseqcstrcaseless (const_bstring b, const char * s); +extern int bstrcmp (const_bstring b0, const_bstring b1); +extern int bstrncmp (const_bstring b0, const_bstring b1, int n); +extern int binstr (const_bstring s1, int pos, const_bstring s2); +extern int binstrr (const_bstring s1, int pos, const_bstring s2); +extern int binstrcaseless (const_bstring s1, int pos, const_bstring s2); +extern int binstrrcaseless (const_bstring s1, int pos, const_bstring s2); +extern int bstrchrp (const_bstring b, int c, int pos); +extern int bstrrchrp (const_bstring b, int c, int pos); +#define bstrchr(b,c) bstrchrp ((b), (c), 0) +#define bstrrchr(b,c) bstrrchrp ((b), (c), blength(b)-1) +extern int binchr (const_bstring b0, int pos, const_bstring b1); +extern int binchrr (const_bstring b0, int pos, const_bstring b1); +extern int bninchr (const_bstring b0, int pos, const_bstring b1); +extern int bninchrr (const_bstring b0, int pos, const_bstring b1); +extern int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos); +extern int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos); + +/* List of string container functions */ +struct bstrList { + int qty, mlen; + bstring * entry; +}; +extern struct bstrList * bstrListCreate (void); +extern int bstrListDestroy (struct bstrList * sl); +extern int bstrListAlloc (struct bstrList * sl, int msz); +extern int bstrListAllocMin (struct bstrList * sl, int msz); + +/* String split and join functions */ +extern struct bstrList * bsplit (const_bstring str, unsigned char splitChar); +extern struct bstrList * bsplits (const_bstring str, const_bstring splitStr); +extern struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr); +extern bstring bjoin (const struct bstrList * bl, const_bstring sep); +extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos, + int (* cb) (void * parm, int ofs, int len), void * parm); +extern int bsplitscb (const_bstring str, const_bstring splitStr, int pos, + int (* cb) (void * parm, int ofs, int len), void * parm); +extern int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos, + int (* cb) (void * parm, int ofs, int len), void * parm); + +/* Miscellaneous functions */ +extern int bpattern (bstring b, int len); +extern int btoupper (bstring b); +extern int btolower (bstring b); +extern int bltrimws (bstring b); +extern int brtrimws (bstring b); +extern int btrimws (bstring b); + +/* <*>printf format functions */ +#if !defined (BSTRLIB_NOVSNP) +extern bstring bformat (const char * fmt, ...); +extern int bformata (bstring b, const char * fmt, ...); +extern int bassignformat (bstring b, const char * fmt, ...); +extern int bvcformata (bstring b, int count, const char * fmt, va_list arglist); + +#define bvformata(ret, b, fmt, lastarg) { \ +bstring bstrtmp_b = (b); \ +const char * bstrtmp_fmt = (fmt); \ +int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \ + for (;;) { \ + va_list bstrtmp_arglist; \ + va_start (bstrtmp_arglist, lastarg); \ + bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \ + va_end (bstrtmp_arglist); \ + if (bstrtmp_r >= 0) { /* Everything went ok */ \ + bstrtmp_r = BSTR_OK; \ + break; \ + } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \ + bstrtmp_r = BSTR_ERR; \ + break; \ + } \ + bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \ + } \ + ret = bstrtmp_r; \ +} + +#endif + +typedef int (*bNgetc) (void *parm); +typedef size_t (* bNread) (void *buff, size_t elsize, size_t nelem, void *parm); + +/* Input functions */ +extern bstring bgets (bNgetc getcPtr, void * parm, char terminator); +extern bstring bread (bNread readPtr, void * parm); +extern int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator); +extern int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator); +extern int breada (bstring b, bNread readPtr, void * parm); + +/* Stream functions */ +extern struct bStream * bsopen (bNread readPtr, void * parm); +extern void * bsclose (struct bStream * s); +extern int bsbufflength (struct bStream * s, int sz); +extern int bsreadln (bstring b, struct bStream * s, char terminator); +extern int bsreadlns (bstring r, struct bStream * s, const_bstring term); +extern int bsread (bstring b, struct bStream * s, int n); +extern int bsreadlna (bstring b, struct bStream * s, char terminator); +extern int bsreadlnsa (bstring r, struct bStream * s, const_bstring term); +extern int bsreada (bstring b, struct bStream * s, int n); +extern int bsunread (struct bStream * s, const_bstring b); +extern int bspeek (bstring r, const struct bStream * s); +extern int bssplitscb (struct bStream * s, const_bstring splitStr, + int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); +extern int bssplitstrcb (struct bStream * s, const_bstring splitStr, + int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); +extern int bseof (const struct bStream * s); + +struct tagbstring { + int mlen; + int slen; + unsigned char * data; +}; + +/* Accessor macros */ +#define blengthe(b, e) (((b) == (void *)0 || (b)->slen < 0) ? (int)(e) : ((b)->slen)) +#define blength(b) (blengthe ((b), 0)) +#define bdataofse(b, o, e) (((b) == (void *)0 || (b)->data == (void*)0) ? (char *)(e) : ((char *)(b)->data) + (o)) +#define bdataofs(b, o) (bdataofse ((b), (o), (void *)0)) +#define bdatae(b, e) (bdataofse (b, 0, e)) +#define bdata(b) (bdataofs (b, 0)) +#define bchare(b, p, e) ((((unsigned)(p)) < (unsigned)blength(b)) ? ((b)->data[(p)]) : (e)) +#define bchar(b, p) bchare ((b), (p), '\0') + +/* Static constant string initialization macro */ +#define bsStaticMlen(q,m) {(m), (int) sizeof(q)-1, (unsigned char *) ("" q "")} +#if defined(_MSC_VER) +/* There are many versions of MSVC which emit __LINE__ as a non-constant. */ +# define bsStatic(q) bsStaticMlen(q,-32) +#endif +#ifndef bsStatic +# define bsStatic(q) bsStaticMlen(q,-__LINE__) +#endif + +/* Static constant block parameter pair */ +#define bsStaticBlkParms(q) ((void *)("" q "")), ((int) sizeof(q)-1) + +/* Reference building macros */ +#define cstr2tbstr btfromcstr +#define btfromcstr(t,s) { \ + (t).data = (unsigned char *) (s); \ + (t).slen = ((t).data) ? ((int) (strlen) ((char *)(t).data)) : 0; \ + (t).mlen = -1; \ +} +#define blk2tbstr(t,s,l) { \ + (t).data = (unsigned char *) (s); \ + (t).slen = l; \ + (t).mlen = -1; \ +} +#define btfromblk(t,s,l) blk2tbstr(t,s,l) +#define bmid2tbstr(t,b,p,l) { \ + const_bstring bstrtmp_s = (b); \ + if (bstrtmp_s && bstrtmp_s->data && bstrtmp_s->slen >= 0) { \ + int bstrtmp_left = (p); \ + int bstrtmp_len = (l); \ + if (bstrtmp_left < 0) { \ + bstrtmp_len += bstrtmp_left; \ + bstrtmp_left = 0; \ + } \ + if (bstrtmp_len > bstrtmp_s->slen - bstrtmp_left) \ + bstrtmp_len = bstrtmp_s->slen - bstrtmp_left; \ + if (bstrtmp_len <= 0) { \ + (t).data = (unsigned char *)""; \ + (t).slen = 0; \ + } else { \ + (t).data = bstrtmp_s->data + bstrtmp_left; \ + (t).slen = bstrtmp_len; \ + } \ + } else { \ + (t).data = (unsigned char *)""; \ + (t).slen = 0; \ + } \ + (t).mlen = -__LINE__; \ +} +#define btfromblkltrimws(t,s,l) { \ + int bstrtmp_idx = 0, bstrtmp_len = (l); \ + unsigned char * bstrtmp_s = (s); \ + if (bstrtmp_s && bstrtmp_len >= 0) { \ + for (; bstrtmp_idx < bstrtmp_len; bstrtmp_idx++) { \ + if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ + } \ + } \ + (t).data = bstrtmp_s + bstrtmp_idx; \ + (t).slen = bstrtmp_len - bstrtmp_idx; \ + (t).mlen = -__LINE__; \ +} +#define btfromblkrtrimws(t,s,l) { \ + int bstrtmp_len = (l) - 1; \ + unsigned char * bstrtmp_s = (s); \ + if (bstrtmp_s && bstrtmp_len >= 0) { \ + for (; bstrtmp_len >= 0; bstrtmp_len--) { \ + if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ + } \ + } \ + (t).data = bstrtmp_s; \ + (t).slen = bstrtmp_len + 1; \ + (t).mlen = -__LINE__; \ +} +#define btfromblktrimws(t,s,l) { \ + int bstrtmp_idx = 0, bstrtmp_len = (l) - 1; \ + unsigned char * bstrtmp_s = (s); \ + if (bstrtmp_s && bstrtmp_len >= 0) { \ + for (; bstrtmp_idx <= bstrtmp_len; bstrtmp_idx++) { \ + if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ + } \ + for (; bstrtmp_len >= bstrtmp_idx; bstrtmp_len--) { \ + if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ + } \ + } \ + (t).data = bstrtmp_s + bstrtmp_idx; \ + (t).slen = bstrtmp_len + 1 - bstrtmp_idx; \ + (t).mlen = -__LINE__; \ +} + +/* Write protection macros */ +#define bwriteprotect(t) { if ((t).mlen >= 0) (t).mlen = -1; } +#define bwriteallow(t) { if ((t).mlen == -1) (t).mlen = (t).slen + ((t).slen == 0); } +#define biswriteprotected(t) ((t).mlen <= 0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/devpkg/dbg.h b/devpkg/dbg.h new file mode 120000 index 0000000..459ed97 --- /dev/null +++ b/devpkg/dbg.h @@ -0,0 +1 @@ +../dbg.h \ No newline at end of file From e4ce3ea6cc6c78a9f93053c804858b4e7456755e Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 15 Nov 2011 19:21:53 -0500 Subject: [PATCH 124/145] First version of makefile for devpkg --- devpkg/Makefile | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/devpkg/Makefile b/devpkg/Makefile index e69de29..abaa64b 100644 --- a/devpkg/Makefile +++ b/devpkg/Makefile @@ -0,0 +1,16 @@ +PREFIX?=/usr/local +CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 -I${PREFIX}/apr/include/apr-util-1 +LDFLAGS=-lapr-1 -pthread -laprutil-1 + +all: devpkg + +devpkg: bstrlib.o db.o shell.o commands.o + +install: all + install -d $(DESTDIR)/$(PREFIX)/bin/ + install devpkg $(DESTDIR)/$(PREFIX)/bin/ + +clean: + rm -f *.o + rm -f devpkg + rm -rf *.dSYM From 4d9a65545cda4e27df458f505aee2d32f7c6e365 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 15 Nov 2011 21:44:11 -0500 Subject: [PATCH 125/145] Working through ch27 devpkg, though still having compilation problems with apr_errno.h --- apr-install-script.sh | 5 +- devpkg/Makefile | 2 +- devpkg/apr_errno_test.c | 7 +++ devpkg/db.c | 124 ++++++++++++++++++++++++++++++++++++++++ devpkg/db.h | 13 +++++ devpkg/shell.c | 113 ++++++++++++++++++++++++++++++++++++ devpkg/shell.h | 31 ++++++++++ 7 files changed, 291 insertions(+), 4 deletions(-) create mode 100644 devpkg/apr_errno_test.c create mode 100644 devpkg/db.c create mode 100644 devpkg/db.h create mode 100644 devpkg/shell.c create mode 100644 devpkg/shell.h diff --git a/apr-install-script.sh b/apr-install-script.sh index f7a202e..870d3ba 100755 --- a/apr-install-script.sh +++ b/apr-install-script.sh @@ -16,9 +16,8 @@ cd apr-1.4.5 make sudo make install -# reset and cleanup +# reset cd /tmp -rm -rf apr-1.4.5 apr-1.4.5.tar.gz # do the same with apr-util curl -L -O http://download.nextag.com/apache/apr/apr-util-1.3.12.tar.gz @@ -37,4 +36,4 @@ sudo make install # cleanup cd /tmp -rm -rf apr-util-1.3.12* apr-1.4.5* +#rm -rvf apr-util-1.3.12* apr-1.4.5* diff --git a/devpkg/Makefile b/devpkg/Makefile index abaa64b..4a1f3e3 100644 --- a/devpkg/Makefile +++ b/devpkg/Makefile @@ -1,5 +1,5 @@ PREFIX?=/usr/local -CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 -I${PREFIX}/apr/include/apr-util-1 +CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 LDFLAGS=-lapr-1 -pthread -laprutil-1 all: devpkg diff --git a/devpkg/apr_errno_test.c b/devpkg/apr_errno_test.c new file mode 100644 index 0000000..7a9be27 --- /dev/null +++ b/devpkg/apr_errno_test.c @@ -0,0 +1,7 @@ +#include + + +int main(int argc, char *argv[]) +{ + return 0; +} diff --git a/devpkg/db.c b/devpkg/db.c new file mode 100644 index 0000000..3a5c333 --- /dev/null +++ b/devpkg/db.c @@ -0,0 +1,124 @@ +#include +#include +#include + +#include "db.h" +#include "bstrlib.h" +#include "dbg.h" + +static FILE *DB_open(const char *path, const char *mode) +{ + return fopen(path, mode); +} + + +static void DB_close(FILE *db) +{ + fclose(db); +} + + +static bstring DB_load(const char *path) +{ + FILE *db = NULL; + bstring data = NULL; + + db = DB_open(DB_FILE, "r"); + check(db, "Failed to open database: %s", DB_FILE); + + data = bread((bNread)fread, db); + check(data, "Failed to read from db file: %s", DB_FILE); + + DB_close(db); + return data; + +error: + if(db) DB_close(db); + if(data) bdestroy(data); + return NULL; +} + + +int DB_update(const char *url) +{ + if(DB_find(url)) { + log_info("Already recorded as installed: %s", url); + } + + FILE *db = DB_open(DB_FILE, "a+"); + check(db, "Failed to open DB file: %s", DB_FILE); + + bstring line = bfromcstr(url); + bconchar(line, '\n'); + int rc = fwrite(line->data, blength(line), 1, db); + check(rc == 1, "Failed to append to the db."); + + return 0; +error: + if(db) DB_close(db); + return -1; +} + + +int DB_find(const char *url) +{ + bstring data = NULL; + bstring line = bfromcstr(url); + int res = -1; + + data = DB_load(DB_FILE); + check(data, "Failed to load: %s", DB_FILE); + + if(binstr(data, 0, line) == BSTR_ERR) { + res = 0; + } else { + res = 1; + } + +error: //fallthrough + if(data) bdestroy(data); + if(line) bdestroy(line); + return res; +} + + +int DB_init() +{ + apr_pool_t *p = NULL; + apr_pool_initialize(); + apr_pool_create(&p, NULL); + + if(access(DB_DIR, W_OK | X_OK) == -1) { + apr_status_t rc = apr_dir_make_recursive(DB_DIR, + APR_UREAD | APR_UWRITE | APR_UEXECUTE | + APR_GREAD | APR_GWRITE | APR_GEXECUTE, p); + check(rc == APR_SUCCESS, "Failed to make database dir: %s", DB_DIR); + } + + if(access(DB_FILE, W_OK) == -1) { + FILE *db = DB_open(DB_FILE, "w"); + check(db, "Cannot open database: %s", DB_FILE); + DB_close(db); + } + + apr_pool_destroy(p); + return 0; + +error: + apr_pool_destroy(p); + return -1; +} + + +int DB_list() +{ + bstring data = DB_load(DB_FILE); + check(data, "Failed to read load: %s", DB_FILE); + + printf("%s", bdata(data)); + bdestroy(data); + return 0; + +error: + return -1; +} diff --git a/devpkg/db.h b/devpkg/db.h new file mode 100644 index 0000000..6318d62 --- /dev/null +++ b/devpkg/db.h @@ -0,0 +1,13 @@ +#ifndef _db_h +#define _db_h + +#define DB_FILE "/usr/local/.devpkg/db" +#define DB_DIR "/usr/local/.devpkg" + + +int DB_init(); +int DB_list(); +int DB_update(const char *url); +int DB_find(const char *url); + +#endif diff --git a/devpkg/shell.c b/devpkg/shell.c new file mode 100644 index 0000000..054903f --- /dev/null +++ b/devpkg/shell.c @@ -0,0 +1,113 @@ +#include "shell.h" +#include "dbg.h" +#include + +int Shell_exec(Shell template, ...) +{ + apr_pool_t *p = NULL; + apr_pool_create(&p, NULL); + + va_list argp; + const char *key = NULL; + const char *arg = NULL; + int i = 0; + + va_start(argp, template); + + for(key = va_arg(argp, const char*); + key != NULL; + key = va_arg(argp, const char *)) + { + arg = va_arg(argp, const char *); + + for(i = 0; template.args[i] != NULL; i++) { + if(strcmp(template.args[i], key) == 0) { + template.args[i] = arg; + break; // found it + } + } + } + + int rc = Shell_run(p, &template); + apr_pool_create(&p, NULL); + va_end(argp); + return rc; +} + + +int Shell_run(apr_pool_t *p, Shell *cmd) +{ + apr_procattr_t *attr; + apr_status_t rv; + apr_proc_t newproc; + + rv = apr_procattr_create(&attr, p); + check(rv == APR_SUCCESS, "Failed to create proc attr."); + + rv = apr_procattr_io_set(attr, APR_NO_PIPE, APR_NO_PIPE, + APR_NO_PIPE); + check(rv == APR_SUCCESS, "Failed to set IO of command."); + + rv = apr_procattr_dir_set(attr, cmd->dir); + check(rv == APR_SUCCESS, "Failed to set root to %s", cmd->dir); + + rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM_PATH); + check(rv == APR_SUCCESS, "Failed to set cmd type."); + + rv = apr_proc_create(&newproc, cmd->exe, cmd->args, NULL, attr, p); + check(rv == APR_SUCCESS, "Failed to run command."); + + rv = apr_proc_wait(&newproc, &cmd->exit_code, &cmd->exit_why, APR_WAIT); + check(rv == APR_CHILD_DONE, "Failed to wait."); + + check(cmd->exit_code == 0, "%s exited badly.", cmd->exe); + check(cmd->exit_why == APR_PROC_EXIT, "%s was killed or crashed", cmd->exe); + + return 0; + +error: + return -1; +} + +Shell CLEANUP_SH = { + .exe = "rm", + .dir = "/tmp", + .args = {"rm", "-rf", "/tmp/pkg-build", "/tmp/pkg-src.tar.gz", + "/tmp/pkg-src.tar.bz2", "/tmp/DEPENDS", NULL} +}; + +Shell GIT_SH = { + .dir = "/tmp", + .exe = "git", + .args = {"git", "clone", "URL", "pkg-build", NULL} +}; + +Shell TAR_SH = { + .dir = "/tmp/pkg-build", + .exe = "tar", + .args = {"tar", "-xzf", "FILE", "--strip-components", "1", NULL} +}; + +Shell CURL_SH = { + .dir = "/tmp", + .exe = "curl", + .args = {"curl", "-L", "-o", "TARGET", "URL", NULL} +} + +Shell CONFIGURE_SH = { + .exe = "./configure", + .dir = "/tmp/pkg-build", + .args = {"configure", "OPTS", NULL} +}; + +Shell MAKE_SH = { + .exe = "make", + .dir = "/tmp/pkg-build", + .args = {"make", "OPTS", NULL} +}; + +Shell INSTALL_SH = { + .exe = "sudo", + .dir = "/tmp/pkg-build", + .args = {"sudo", "make", "TARGET", NULL} +}; diff --git a/devpkg/shell.h b/devpkg/shell.h new file mode 100644 index 0000000..a4301d3 --- /dev/null +++ b/devpkg/shell.h @@ -0,0 +1,31 @@ +#ifndef _shell_h +#define _shell_h + +#define MAX_COMMAND_ARGS 100 + +#include + +typedef struct Shell { + const char *dir; + const char *exe; + + apr_procattr_t *attr; + apr_proc_t proc; + apr_exit_why_e exit_why; + int exit_code; + + const char *args[MAX_COMMAND_ARGS]; +} Shell; + +int Shell_run(apr_pool_t *p, Shell *cmd); +int Shell_exec(Shell cmd, ...); + +extern Shell CLEANUP_SH; +extern Shell GIT_SH; +extern Shell TAR_SH; +extern Shell CURL_SH; +extern Shell CONFIGURE_SH; +extern Shell MAKE_SH; +extern Shell INSTALL_SH; + +#endif From 8e5f3ee27df4c4ba0f3056355077d6d49ddc5937 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 16 Nov 2011 08:58:37 -0500 Subject: [PATCH 126/145] Done up through the commands.* files, but still getting compilation errors related to apr (?) --- devpkg/commands.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++ devpkg/commands.h | 32 +++++++++ 2 files changed, 207 insertions(+) create mode 100644 devpkg/commands.c create mode 100644 devpkg/commands.h diff --git a/devpkg/commands.c b/devpkg/commands.c new file mode 100644 index 0000000..9b483c4 --- /dev/null +++ b/devpkg/commands.c @@ -0,0 +1,175 @@ +#include +#include +#include + +#include "commands.h" +#include "dbg.h" +#include "bstrlib.h" +#include "db.h" +#include "shell.h" + + +int Command_depends(apr_pool_t *p, const char *path) +{ + FILE *in = NULL; + bstring line = NULL; + + in = fopen(path, "r"); + check(in != NULL, "Failed to open downloaded depends: %s", path); + + for(line = bgets((bNgetc)fgetc, in, '\n'); line != NULL; + line = bgets((bNgetc)fgetc, in, '\n')) + { + btrimws(line); + log_info("Processing depends: %s", bdata(line)); + int rc = Command_install(p, bdata(line), NULL, NULL, NULL); + check(rc == 0, "Failed to install: %s", bdata(line)); + bdestroy(line); + } + + fclose(in); + return 0; + +error: + if(line) bdestroy(line); + if(in) fclose(in); + return -1; +} + + +int Command_fetch(apr_pool_t *p, const char *url, int fetch_only) +{ + apr_uri_t info = {.port = 0}; + int rc = 0; + const char *depends_file = NULL; + apr_status_t rv = apr_uri_parse(p, url, &info); + + check(rv == APR_SUCCESS, "Failed to parse URL: %s", url); + + if(apr_fnmatch(GIT_PAT, info.path, 0) == APR_SUCCESS) { + rc = Shell_exec(GIT_SH, "URL", url, NULL); + check(rc == 0, "git failed."); + } else if(apr_fnmatch(DEPEND_PAT, info.path, 0) == APR_SUCCESS) { + check(!fetch_only, "No point in fetching a DEPENDS file."); + + if(info.scheme) { + depends_file = DEPENDS_PATH; + rc = Shell_exec(CURL_SH, "URL", url, "TARGET", depends_file, NULL); + check(rc == 0, "Curl failed."); + } else { + depends_file = info.path; + } + + // recursively process the devpkg list + log_info("Building according to DEPENDS: %s", url); + rv = Command_depends(p, depends_file); + check(rv == 0, "Failed to process the DEPENDS: %s", url); + + // this indicates that nothing needs to be done + return 0; + + } else if(apr_fnmatch(TAR_GZ_PAT, info.path, 0) == APR_SUCCESS) { + if(info.scheme) { + rc = Shell_exec(CURL_SH, + "URL", url, + "TARGET", TAR_GZ_SRC, NULL); + check(rc == 0, "Failed to curl source: %s", url); + } + + rv = apr_dir_make_recursive(BUILD_DIR, + APR_UREAD | APR_UWRITE | APR_UEXECUTE, p); + check(rv == APR_SUCCESS, "Failed to make directory %s", BUILD_DIR); + + rc = Shell_exec(TAR_SH, "FILE", TAR_GZ_SRC, NULL); + check(rc == 0, "Failed to untar %s", TAR_GZ_SRC); + } else if(apr_fnmatch(TAR_BZ2_PAT, info.path, 0) == APR_SUCCESS) { + if(info.scheme) { + rc = Shell_exec(CURL_SH, "URL", url, "TARGET", TAR_BZ2_SRC, NULL); + check(rc == 0, "Curl failed."); + } + + apr_status_t rc = apr_dir_make_recursive(BUILD_DIR, + APR_UREAD | APR_UWRITE | APR_UEXECUTE, p); + + check(rc == 0, "Failed to make directory %s", BUILD_DIR); + rc = Shell_exec(TAR_SH, "FILE", TAR_BZ2_SRC, NULL); + check(rc == 0, "Failed to untar %s", TAR_BZ2_SRC); + } else { + sentinel("Don't know how to handle %s", url); + } + + // indicates that an install needs to actually run + return 1; + +error: + return -1; +} + +int Command_build(apr_pool_t *p, const char *url, const char *configure_opts, + const char *make_opts, const char *install_opts) +{ + int rc = 0; + + check(access(BUILD_DIR, X_OK | R_OK | W_OK) == 0, + "Build directory doesn't exist: %s", BUILD_DIR); + + // actually do an install + if(access(CONFIG_SCRIPT, X_OK) == 0) { + log_info("Has a configure script, running it."); + rc = Shell_exec(CONFIGURE_SH, "OPTS", configure_opts, NULL); + check(rc == 0, "Failed to configure."); + } + + rc = Shell_exec(MAKE_SH, "OPTS", make_opts, NULL); + check(rc == 0, "Failed to build."); + + rc = Shell_exec(INSTALL_SH, + "TARGET", install_opts ? install_opts : "install", + NULL); + check(rc == 0, "Failed to install."); + + rc = Shell_exec(CLEANUP_SH, NULL); + check(rc == 0, "Failed to cleanup after build."); + + rc = DB_update(url); + check(rc == 0, "Failed to add this package to the database."); + + return 0; + +error: + return 1; +} + +int Command_install(apr_pool_t *p, const char *url, const char *configure_opts, + const char *make_opts, const char *install_opts) +{ + int rc = 0; + check(Shell_exec(CLEANUP_SH, NULL) == 0, "Failed to cleanup before building."); + + rc = DB_find(url); + check(rc != -1, "Error checking the install database."); + + if(rc == 1) { + log_info("Package %s already installed.", url); + return 0; + } + + rc = Command_fetch(p, url, 0); + if(rc == 1) { + rc = Command_build(p, url, configure_opts, make_opts, install_opts); + check(rc == 0, "Failed to build: %s", url); + } else if(rc == 0) { + // no install needed + log_info("Depends successfully installed: %s", url); + } else { + // had an error + sentinel("Install failed: %s", url); + } + + Shell_exec(CLEANUP_SH, NULL); + return 0; + +error: + Shell_exec(CLEANUP_SH, NULL); + return -1; +} diff --git a/devpkg/commands.h b/devpkg/commands.h new file mode 100644 index 0000000..443308b --- /dev/null +++ b/devpkg/commands.h @@ -0,0 +1,32 @@ +#ifndef _commands_h +#define _commands_h + +#include + +#define DEPENDS_PATH "/tmp/DEPENDS" +#define TAR_GZ_SRC "/tmp/pkg-src.tar.gz" +#define TAR_BZ2_SRC "/tmp/pkg-src.tar.bz2" +#define BUILD_DIR "/tmp/pkg-build" +#define GIT_PAT "*.git" +#define DEPEND_PAT "*DEPENDS" +#define TAR_GZ_PAT "*.tar.gz" +#define TAR_BZ2_PAT "*.tar.bz2" +#define CONFIG_SCRIPT "/tmp/pkg-build/configure" + +enum CommandType { + COMMAND_NONE, COMMAND_INSTALL, COMMAND_LIST, COMMAND_FETCH, + COMMAND_INIT, COMMAND_BUILD +}; + + +int Command_fetch(apr_pool_t *p, const char *url, int fetch_only); + +int Command_install(apr_pool_t *p, const char *url, const char *configure_opts, + const char *make_opts, const char *install_opts); + +int Command_depends(apr_pool_t *p, const char *path); + +int Command_build(apr_pool_t *p, const char *url, const char *configure_opts, + const char *make_opts, const char *install_opts); + +#endif From 61c100d6dcf932024d78fab1dcc523284020319c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 16 Nov 2011 09:10:55 -0500 Subject: [PATCH 127/145] Finally fixing the compilation error related to apr by defining _LARGEFILE64_SOURCE --- devpkg/Makefile | 2 +- devpkg/shell.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devpkg/Makefile b/devpkg/Makefile index 4a1f3e3..677e8c4 100644 --- a/devpkg/Makefile +++ b/devpkg/Makefile @@ -1,5 +1,5 @@ PREFIX?=/usr/local -CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 +CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 -D_LARGEFILE64_SOURCE LDFLAGS=-lapr-1 -pthread -laprutil-1 all: devpkg diff --git a/devpkg/shell.c b/devpkg/shell.c index 054903f..1bbe0ba 100644 --- a/devpkg/shell.c +++ b/devpkg/shell.c @@ -92,7 +92,7 @@ Shell CURL_SH = { .dir = "/tmp", .exe = "curl", .args = {"curl", "-L", "-o", "TARGET", "URL", NULL} -} +}; Shell CONFIGURE_SH = { .exe = "./configure", From 313b7e6e441619bb52b2aee1d28766ea69150ef5 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 17 Nov 2011 07:55:03 -0500 Subject: [PATCH 128/145] Filling in the devpkg main executable, almost ready for challenge and mid-term (?) --- devpkg/.gitignore | 1 + devpkg/Makefile | 2 +- devpkg/devpkg.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 devpkg/.gitignore create mode 100644 devpkg/devpkg.c diff --git a/devpkg/.gitignore b/devpkg/.gitignore new file mode 100644 index 0000000..4642b33 --- /dev/null +++ b/devpkg/.gitignore @@ -0,0 +1 @@ +devpkg diff --git a/devpkg/Makefile b/devpkg/Makefile index 677e8c4..190f9a4 100644 --- a/devpkg/Makefile +++ b/devpkg/Makefile @@ -1,6 +1,6 @@ PREFIX?=/usr/local CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 -D_LARGEFILE64_SOURCE -LDFLAGS=-lapr-1 -pthread -laprutil-1 +LDFLAGS=-L${PREFIX}/apr/lib -lapr-1 -pthread -laprutil-1 all: devpkg diff --git a/devpkg/devpkg.c b/devpkg/devpkg.c new file mode 100644 index 0000000..4dbabfb --- /dev/null +++ b/devpkg/devpkg.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include + +#include "dbg.h" +#include "db.h" +#include "commands.h" + + +int main(int argc, const char const *argv[]) +{ + apr_pool_t *p = NULL; + apr_pool_initialize(); + apr_pool_create(&p, NULL); + + apr_getopt_t *opt; + apr_status_t rv; + + char ch = '\0'; + const char *optarg = NULL; + const char *config_opts = NULL; + const char *install_opts = NULL; + const char *make_opts = NULL; + const char *url = NULL; + enum CommandType request = COMMAND_NONE; + + rv = apr_getopt_init(&opt, p, argc, argv); + + while(apr_getopt(opt, "I:Lc:m:i:d:SF:B:", &ch, &optarg) == APR_SUCCESS) { + switch (ch) { + case 'I': + request = COMMAND_INSTALL; + url = optarg; + break; + + case 'L': + request = COMMAND_LIST; + break; + + case 'c': + config_opts = optarg; + break; + + case 'm': + make_opts = optarg; + break; + + case 'i': + install_opts = optarg; + break; + + case 'S': + request = COMMAND_INIT; + break; + + case 'F': + request = COMMAND_FETCH; + url = optarg; + break; + + case 'B': + request = COMMAND_BUILD; + url = optarg; + break; + } + } + + switch(request) { + case COMMAND_INSTALL: + check(url, "You must at least give a URL."); + Command_install(p, url, config_opts, make_opts, install_opts); + break; + + case COMMAND_LIST: + DB_list(); + break; + + case COMMAND_FETCH: + check(url != NULL, "You must give a URL."); + Command_fetch(p, url, 1); + log_info("Downloaded to %s and in /tmp/", BUILD_DIR); + break; + + case COMMAND_BUILD: + check(url, "You must at least give a URL."); + Command_build(p, url, config_opts, make_opts, install_opts); + break; + + case COMMAND_INIT: + rv = DB_init(); + check(rv == 0, "Failed to make the database."); + break; + + default: + sentinel("Invalid command given."); + } + + return 0; + +error: + return 1; +} From 1f224f98ef1784532a4965bc3b38e9e3edc33e06 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 11 Feb 2012 13:24:36 -0500 Subject: [PATCH 129/145] Fixing some format sequences to get rid of warnings --- ex8.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ex8.c b/ex8.c index e89e124..b7efc4b 100644 --- a/ex8.c +++ b/ex8.c @@ -10,10 +10,10 @@ int main(int argc, char *argv[]) 'S', 'h', 'a', 'w', '\0' }; - printf("The size of an int: %d\n", sizeof(int)); - printf("The size of areas (int[]): %d\n", + printf("The size of an int: %ld\n", sizeof(int)); + printf("The size of areas (int[]): %ld\n", sizeof(areas)); - printf("The number of ints in areas: %d\n", + printf("The number of ints in areas: %ld\n", sizeof(areas) / sizeof(int)); printf("The first area is %d, then 2nd %d.\n", areas[0], areas[1]); @@ -22,15 +22,15 @@ int main(int argc, char *argv[]) printf("Now the first area is %d and the 3rd area is %d.\n", areas[0], areas[2]); - printf("The size of char: %d\n", sizeof(char)); - printf("The size of name (char[]): %d\n", + printf("The size of char: %ld\n", sizeof(char)); + printf("The size of name (char[]): %ld\n", sizeof(name)); - printf("The number of chars: %d\n", + printf("The number of chars: %ld\n", sizeof(name) / sizeof(char)); - printf("The size of full_name (char[]): %d\n", + printf("The size of full_name (char[]): %ld\n", sizeof(full_name)); - printf("The number of chars: %d\n", + printf("The number of chars: %ld\n", sizeof(full_name) / sizeof(char)); printf("name=\"%s\" and full_name=\"%s\"\n", From bb0ac185fe6fdd6700c95e34ba06377f424fabde Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 11 Feb 2012 13:26:39 -0500 Subject: [PATCH 130/145] Perhaps incorrectly fixing another format sequence warning --- ex9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex9.c b/ex9.c index 02edc6e..6756764 100644 --- a/ex9.c +++ b/ex9.c @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) printf("%d\n", name[2]); printf("%d\n", name[3]); - printf("name as int=%d\n", (int)name); + printf("name as int=%d\n", (int)*name); printf("numbers: %d %d %d %d\n", numbers[0], numbers[1], From 8ad2b3d4ca2a6023565b8a11efee86b65ec6ab93 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 11 Feb 2012 14:33:56 -0500 Subject: [PATCH 131/145] Forgot to clean up after myself a bit --- ex22.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ex22.mk b/ex22.mk index e726f51..5ef707f 100644 --- a/ex22.mk +++ b/ex22.mk @@ -5,6 +5,6 @@ ex22_main: ex22_main.o ex22.o clean: - rm -f ex22_main ex22.o ex22_main.o + rm -f ex22_main ex22.o ex22_main.o ex22_ec1 .PHONY: all clean From 898c6e4be13bcbc59d3d8b6ba3f9ad76c6db2eec Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 11 Feb 2012 14:39:50 -0500 Subject: [PATCH 132/145] Getting rid of some more compiler warnings --- ex21.c | 108 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/ex21.c b/ex21.c index 695e1c4..82833cb 100644 --- a/ex21.c +++ b/ex21.c @@ -4,121 +4,121 @@ int main(int argc, char *argv[]) { - printf("sizeof(int8_t) = %d\n", sizeof(int8_t)); - printf("sizeof(uint8_t) = %d\n", sizeof(uint8_t)); - printf("sizeof(int16_t) = %d\n", sizeof(int16_t)); - printf("sizeof(uint16_t) = %d\n", sizeof(uint16_t)); - printf("sizeof(int32_t) = %d\n", sizeof(int32_t)); - printf("sizeof(uint32_t) = %d\n", sizeof(uint32_t)); + printf("sizeof(int8_t) = %ld\n", sizeof(int8_t)); + printf("sizeof(uint8_t) = %ld\n", sizeof(uint8_t)); + printf("sizeof(int16_t) = %ld\n", sizeof(int16_t)); + printf("sizeof(uint16_t) = %ld\n", sizeof(uint16_t)); + printf("sizeof(int32_t) = %ld\n", sizeof(int32_t)); + printf("sizeof(uint32_t) = %ld\n", sizeof(uint32_t)); #if defined(_M_X64) || defined(__amd64__) - printf("sizeof(int64_t) = %d\n", sizeof(int64_t)); - printf("sizeof(uint64_t) = %d\n", sizeof(uint64_t)); + printf("sizeof(int64_t) = %ld\n", sizeof(int64_t)); + printf("sizeof(uint64_t) = %ld\n", sizeof(uint64_t)); #endif printf("INT8_MAX = %d\n", INT8_MAX); printf("INT16_MAX = %d\n", INT16_MAX); printf("INT32_MAX = %d\n", INT32_MAX); #if defined(_M_X64) || defined(__amd64__) - printf("INT64_MAX = %d\n", INT64_MAX); + printf("INT64_MAX = %ld\n", INT64_MAX); #endif printf("INT8_MIN = %d\n", INT8_MIN); printf("INT16_MIN = %d\n", INT16_MIN); printf("INT32_MIN = %d\n", INT32_MIN); #if defined(_M_X64) || defined(__amd64__) - printf("INT64_MIN = %d\n", INT64_MIN); + printf("INT64_MIN = %ld\n", INT64_MIN); #endif - printf("sizeof(int_least8_t) = %d\n", sizeof(int_least8_t)); - printf("sizeof(int_least16_t) = %d\n", sizeof(int_least16_t)); - printf("sizeof(int_least32_t) = %d\n", sizeof(int_least32_t)); + printf("sizeof(int_least8_t) = %ld\n", sizeof(int_least8_t)); + printf("sizeof(int_least16_t) = %ld\n", sizeof(int_least16_t)); + printf("sizeof(int_least32_t) = %ld\n", sizeof(int_least32_t)); #if defined(_M_X64) || defined(__amd64__) - printf("sizeof(int_least64_t) = %d\n", sizeof(int_least64_t)); + printf("sizeof(int_least64_t) = %ld\n", sizeof(int_least64_t)); #endif - printf("sizeof(uint_least8_t) = %d\n", sizeof(uint_least8_t)); - printf("sizeof(uint_least16_t) = %d\n", sizeof(uint_least16_t)); - printf("sizeof(uint_least32_t) = %d\n", sizeof(uint_least32_t)); + printf("sizeof(uint_least8_t) = %ld\n", sizeof(uint_least8_t)); + printf("sizeof(uint_least16_t) = %ld\n", sizeof(uint_least16_t)); + printf("sizeof(uint_least32_t) = %ld\n", sizeof(uint_least32_t)); #if defined(_M_X64) || defined(__amd64__) - printf("sizeof(uint_least64_t) = %d\n", sizeof(uint_least64_t)); + printf("sizeof(uint_least64_t) = %ld\n", sizeof(uint_least64_t)); #endif printf("INT_LEAST8_MAX = %d\n", INT_LEAST8_MAX); printf("INT_LEAST16_MAX = %d\n", INT_LEAST16_MAX); printf("INT_LEAST32_MAX = %d\n", INT_LEAST32_MAX); #if defined(_M_X64) || defined(__amd64__) - printf("INT_LEAST64_MAX = %d\n", INT_LEAST64_MAX); + printf("INT_LEAST64_MAX = %ld\n", INT_LEAST64_MAX); #endif printf("INT_LEAST8_MIN = %d\n", INT_LEAST8_MIN); printf("INT_LEAST16_MIN = %d\n", INT_LEAST16_MIN); printf("INT_LEAST32_MIN = %d\n", INT_LEAST32_MIN); #if defined(_M_X64) || defined(__amd64__) - printf("INT_LEAST64_MIN = %d\n", INT_LEAST64_MIN); + printf("INT_LEAST64_MIN = %ld\n", INT_LEAST64_MIN); #endif printf("UINT_LEAST8_MAX = %d\n", UINT_LEAST8_MAX); printf("UINT_LEAST16_MAX = %d\n", UINT_LEAST16_MAX); printf("UINT_LEAST32_MAX = %d\n", UINT_LEAST32_MAX); #if defined(_M_X64) || defined(__amd64__) - printf("UINT_LEAST64_MAX = %d\n", UINT_LEAST64_MAX); + printf("UINT_LEAST64_MAX = %ld\n", UINT_LEAST64_MAX); #endif - printf("sizeof(int_fast8_t) = %d\n", sizeof(int_fast8_t)); - printf("sizeof(int_fast16_t) = %d\n", sizeof(int_fast16_t)); - printf("sizeof(int_fast32_t) = %d\n", sizeof(int_fast32_t)); + printf("sizeof(int_fast8_t) = %ld\n", sizeof(int_fast8_t)); + printf("sizeof(int_fast16_t) = %ld\n", sizeof(int_fast16_t)); + printf("sizeof(int_fast32_t) = %ld\n", sizeof(int_fast32_t)); #if defined(_M_X64) || defined(__amd64__) - printf("sizeof(int_fast64_t) = %d\n", sizeof(int_fast64_t)); + printf("sizeof(int_fast64_t) = %ld\n", sizeof(int_fast64_t)); #endif - printf("sizeof(uint_fast8_t) = %d\n", sizeof(uint_fast8_t)); - printf("sizeof(uint_fast16_t) = %d\n", sizeof(uint_fast16_t)); - printf("sizeof(uint_fast32_t) = %d\n", sizeof(uint_fast32_t)); + printf("sizeof(uint_fast8_t) = %ld\n", sizeof(uint_fast8_t)); + printf("sizeof(uint_fast16_t) = %ld\n", sizeof(uint_fast16_t)); + printf("sizeof(uint_fast32_t) = %ld\n", sizeof(uint_fast32_t)); #if defined(_M_X64) || defined(__amd64__) - printf("sizeof(uint_fast64_t) = %d\n", sizeof(uint_fast64_t)); + printf("sizeof(uint_fast64_t) = %ld\n", sizeof(uint_fast64_t)); #endif printf("INT_FAST8_MAX = %d\n", INT_FAST8_MAX); - printf("INT_FAST16_MAX = %d\n", INT_FAST16_MAX); - printf("INT_FAST32_MAX = %d\n", INT_FAST32_MAX); + printf("INT_FAST16_MAX = %ld\n", INT_FAST16_MAX); + printf("INT_FAST32_MAX = %ld\n", INT_FAST32_MAX); #if defined(_M_X64) || defined(__amd64__) - printf("INT_FAST64_MAX = %d\n", INT_FAST64_MAX); + printf("INT_FAST64_MAX = %ld\n", INT_FAST64_MAX); #endif printf("INT_FAST8_MAX = %d\n", INT_FAST8_MAX); - printf("INT_FAST16_MAX = %d\n", INT_FAST16_MAX); - printf("INT_FAST32_MAX = %d\n", INT_FAST32_MAX); + printf("INT_FAST16_MAX = %ld\n", INT_FAST16_MAX); + printf("INT_FAST32_MAX = %ld\n", INT_FAST32_MAX); #if defined(_M_X64) || defined(__amd64__) - printf("INT_FAST64_MAX = %d\n", INT_FAST64_MAX); + printf("INT_FAST64_MAX = %ld\n", INT_FAST64_MAX); #endif printf("INT_FAST8_MIN = %d\n", INT_FAST8_MIN); - printf("INT_FAST16_MIN = %d\n", INT_FAST16_MIN); - printf("INT_FAST32_MIN = %d\n", INT_FAST32_MIN); + printf("INT_FAST16_MIN = %ld\n", INT_FAST16_MIN); + printf("INT_FAST32_MIN = %ld\n", INT_FAST32_MIN); #if defined(_M_X64) || defined(__amd64__) - printf("INT_FAST64_MIN = %d\n", INT_FAST64_MIN); + printf("INT_FAST64_MIN = %ld\n", INT_FAST64_MIN); #endif printf("UINT_FAST8_MAX = %d\n", UINT_FAST8_MAX); - printf("UINT_FAST16_MAX = %d\n", UINT_FAST16_MAX); - printf("UINT_FAST32_MAX = %d\n", UINT_FAST32_MAX); + printf("UINT_FAST16_MAX = %ld\n", UINT_FAST16_MAX); + printf("UINT_FAST32_MAX = %ld\n", UINT_FAST32_MAX); #if defined(_M_X64) || defined(__amd64__) - printf("UINT_FAST64_MAX = %d\n", UINT_FAST64_MAX); + printf("UINT_FAST64_MAX = %ld\n", UINT_FAST64_MAX); #endif - printf("sizeof(intptr_t) = %d\n", sizeof(intptr_t)); - printf("sizeof(uintptr_t) = %d\n", sizeof(uintptr_t)); - printf("INTPTR_MAX = %d\n", INTPTR_MAX); - printf("INTPTR_MIN = %d\n", INTPTR_MIN); - printf("UINTPTR_MAX = %d\n", UINTPTR_MAX); - printf("sizeof(intmax_t) = %d\n", sizeof(intmax_t)); - printf("sizeof(uintmax_t) = %d\n", sizeof(uintmax_t)); - printf("INTMAX_MAX = %lld\n", INTMAX_MAX); - printf("INTMAX_MIN = %lld\n", INTMAX_MIN); - printf("UINTMAX_MAX = %lld\n", UINTMAX_MAX); - printf("PTRDIFF_MIN = %d\n", PTRDIFF_MIN); - printf("PTRDIFF_MAX = %d\n", PTRDIFF_MAX); - printf("SIZE_MAX = %d\n", SIZE_MAX); + printf("sizeof(intptr_t) = %ld\n", sizeof(intptr_t)); + printf("sizeof(uintptr_t) = %ld\n", sizeof(uintptr_t)); + printf("INTPTR_MAX = %ld\n", INTPTR_MAX); + printf("INTPTR_MIN = %ld\n", INTPTR_MIN); + printf("UINTPTR_MAX = %ld\n", UINTPTR_MAX); + printf("sizeof(intmax_t) = %ld\n", sizeof(intmax_t)); + printf("sizeof(uintmax_t) = %ld\n", sizeof(uintmax_t)); + printf("INTMAX_MAX = %ld\n", INTMAX_MAX); + printf("INTMAX_MIN = %ld\n", INTMAX_MIN); + printf("UINTMAX_MAX = %ld\n", UINTMAX_MAX); + printf("PTRDIFF_MIN = %ld\n", PTRDIFF_MIN); + printf("PTRDIFF_MAX = %ld\n", PTRDIFF_MAX); + printf("SIZE_MAX = %ld\n", SIZE_MAX); return 0; } From 97043b1831a008fe89e9176a8d76c3f939124f5d Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 11 Feb 2012 21:22:19 -0500 Subject: [PATCH 133/145] Extending CFLAGS a bit so that stuff breaks if it ain't right --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 03350c8..e721092 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-Wall -g -DNDEBUG +CFLAGS=-Wall -Wextra -pedantic-errors -g -DNDEBUG EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | egrep -v "ex(19|22)")) From e5fffdeaf106dc37beb260236470c207c3509f43 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 11 Feb 2012 21:44:35 -0500 Subject: [PATCH 134/145] Working through more compiler warnings... --- Makefile | 2 +- ex15.c | 2 +- ex16.c | 6 +++--- ex18.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index e721092..846874e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-Wall -Wextra -pedantic-errors -g -DNDEBUG +CFLAGS=-Wall -Wextra -pedantic -g -DNDEBUG EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | egrep -v "ex(19|22)")) diff --git a/ex15.c b/ex15.c index 1621a1c..8480c5d 100644 --- a/ex15.c +++ b/ex15.c @@ -81,7 +81,7 @@ int main(int argc, char *argv[]) int i; char **arg = argv; for(i = 0; i < argc; i++) { - printf("argument %d is '%s' (address = %p)\n", i, *arg, arg); + printf("argument %d is '%s' (address = %p)\n", i, *arg, (void *)arg); arg++; } diff --git a/ex16.c b/ex16.c index e586bab..9b4c240 100644 --- a/ex16.c +++ b/ex16.c @@ -15,7 +15,7 @@ struct Person *Person_create(char *name, int age, int height, int weight) struct Person *who = malloc(sizeof(struct Person)); assert(who != NULL); - who->name = strdup(name); + who->name = strdup((char *)name); who->age = age; who->height = height; who->weight = weight; @@ -49,10 +49,10 @@ int main(int argc, char *argv[]) "Frank Blank", 20, 72, 180); // print them out and where they are in memory - printf("Joe is at memory location %p:\n", joe); + printf("Joe is at memory location %p:\n", (void *)joe); Person_print(joe); - printf("Frank is at memory location %p:\n", frank); + printf("Frank is at memory location %p:\n", (void *)frank); Person_print(frank); // make everyone age 20 years and print them again diff --git a/ex18.c b/ex18.c index 5a5a77a..f6735b3 100644 --- a/ex18.c +++ b/ex18.c @@ -81,7 +81,7 @@ void test_sorting(int *numbers, int count, compare_cb cmp) free(sorted); - unsigned char *data = (unsigned char *)cmp; + unsigned char *data = (unsigned char *)&cmp; for(i = 0; i < 25; i++) { printf("%0x:", data[i]); From 27b496fbe3a0fc3254f2cd869a64c9d0a9ead990 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 12 Feb 2012 13:11:03 -0500 Subject: [PATCH 135/145] While re-reading through ex4, it seems a shell script has been added for installing valgrind (yay!) --- ex4.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 ex4.sh diff --git a/ex4.sh b/ex4.sh new file mode 100755 index 0000000..ce5c1f1 --- /dev/null +++ b/ex4.sh @@ -0,0 +1,20 @@ +# 1) Download it (use wget if you don't have curl) +curl -O http://valgrind.org/downloads/valgrind-3.6.1.tar.bz2 + +# use md5sum to make sure it matches the one on the site +md5sum valgrind-3.6.1.tar.bz2 + +# 2) Unpack it. +tar -xjvf valgrind-3.6.1.tar.bz2 + +# cd into the newly created directory +cd valgrind-3.6.1 + +# 3) configure it +./configure + +# 4) make it +make + +# 5) install it (need root) +sudo make install From 5494981c64cec89810ee951728b25e76dc0f15f6 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 12 Feb 2012 13:11:30 -0500 Subject: [PATCH 136/145] wherps, no shebang line thar --- ex4.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 ex4.sh diff --git a/ex4.sh b/ex4.sh old mode 100755 new mode 100644 From c2d4d59032e7c53099ab52693ba00402c7a8d878 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 12 Feb 2012 13:24:31 -0500 Subject: [PATCH 137/145] Upgrading to valgrind 3.7.0 since I'm on linux3 --- .gitignore | 1 + ex4.sh | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index fd6da7c..6372ebf 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ ex8 ex9 .exrc .rvmrc +valgrind-* diff --git a/ex4.sh b/ex4.sh index ce5c1f1..c32c4e1 100644 --- a/ex4.sh +++ b/ex4.sh @@ -1,14 +1,14 @@ # 1) Download it (use wget if you don't have curl) -curl -O http://valgrind.org/downloads/valgrind-3.6.1.tar.bz2 +curl -O http://valgrind.org/downloads/valgrind-3.7.0.tar.bz2 # use md5sum to make sure it matches the one on the site -md5sum valgrind-3.6.1.tar.bz2 +md5sum valgrind-3.7.0.tar.bz2 # 2) Unpack it. -tar -xjvf valgrind-3.6.1.tar.bz2 +tar -xjvf valgrind-3.7.0.tar.bz2 # cd into the newly created directory -cd valgrind-3.6.1 +cd valgrind-3.7.0 # 3) configure it ./configure From 0b956cbf0606dcac2ea7da114616951d9acaf2d3 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 13 Feb 2012 21:54:10 -0500 Subject: [PATCH 138/145] Adding back the -std argument to CFLAGS so that we're allowed to use '//' comments --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 846874e..4b9e702 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-Wall -Wextra -pedantic -g -DNDEBUG +CFLAGS += -Wall -Wextra -pedantic -std=gnu99 -g -DNDEBUG EXERCISES = $(patsubst %.c,%,$(shell ls ex*.c | egrep -v "ex(19|22)")) From 2345f4fa0b3fc2f968605a855c9249bc2546d739 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 13 Feb 2012 22:03:16 -0500 Subject: [PATCH 139/145] Adding back in some comments for line number matchiness --- ex7.c | 2 +- ex8.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ex7.c b/ex7.c index 074acc6..b6e9cfe 100644 --- a/ex7.c +++ b/ex7.c @@ -20,7 +20,7 @@ int main(int argc, char *argv[]) printf("That is only a %e portion of the universe.\n", part_of_universe); - + // this makes no sense, just a demo of something weird char nul_byte = '\0'; int care_percentage = bugs * nul_byte; printf("Which means you should care %d%%.\n", diff --git a/ex8.c b/ex8.c index b7efc4b..0b42543 100644 --- a/ex8.c +++ b/ex8.c @@ -10,6 +10,8 @@ int main(int argc, char *argv[]) 'S', 'h', 'a', 'w', '\0' }; + // WARNING: On some systems you may have to change the + // %ld in this code to a %u since it will use unsigned ints printf("The size of an int: %ld\n", sizeof(int)); printf("The size of areas (int[]): %ld\n", sizeof(areas)); From 2e571b46418e8dbb868232f7664778f16a405e80 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 13 Feb 2012 22:08:28 -0500 Subject: [PATCH 140/145] Adding comments and modifying code to include changes made since last reading --- ex9.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ex9.c b/ex9.c index 6756764..7ea8227 100644 --- a/ex9.c +++ b/ex9.c @@ -5,6 +5,7 @@ int main(int argc, char *argv[]) int numbers[4] = {0}; char name[4] = {'a'}; + // first, print them out raw printf("numbers: %d %d %d %d\n", numbers[0], numbers[1], numbers[2], numbers[3]); @@ -15,11 +16,13 @@ int main(int argc, char *argv[]) printf("name: %s\n", name); + // setup the numbers numbers[0] = 1; numbers[1] = 2; numbers[2] = 3; numbers[3] = 4; + // setup the name name[0] = 'Z'; name[1] = 'e'; name[2] = 'd'; @@ -32,6 +35,7 @@ int main(int argc, char *argv[]) printf("name as int=%d\n", (int)*name); + // then print them out initialized printf("numbers: %d %d %d %d\n", numbers[0], numbers[1], numbers[2], numbers[3]); @@ -40,7 +44,17 @@ int main(int argc, char *argv[]) name[0], name[1], name[2], name[3]); + // print the name like a string printf("name: %s\n", name); + // another way to use name + char *another = "Zed"; + + printf("another: %s\n", another); + + printf("another each: %c %c %c %c\n", + another[0], another[1], + another[2], another[3]); + return 0; } From a3133a86727530babee12d753ccc949261a1d148 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 13 Feb 2012 22:11:10 -0500 Subject: [PATCH 141/145] Adding in comments to match example code --- ex10.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ex10.c b/ex10.c index c06d77b..ebc964b 100644 --- a/ex10.c +++ b/ex10.c @@ -4,10 +4,13 @@ int main(int argc, char *argv[]) { int i = 0; + // go through each string in argv + // why am I skipping argv[0]? for(i = 0; i < argc; i++) { printf("arg %d: %s\n", i, argv[i]); } + // let's make our own array of strings char *states[] = { "California", "Oregon", "Washington", "Texas" From 40a718203c5ed7874ecb2ba6a0e0cadf95779f9e Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 2 Mar 2012 22:10:11 -0500 Subject: [PATCH 142/145] Copying over the ex17 bits so that I can revert the main file to pre-extra-credit state --- ex17-ec.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 ex17-ec.c diff --git a/ex17-ec.c b/ex17-ec.c new file mode 100644 index 0000000..1eaece1 --- /dev/null +++ b/ex17-ec.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include + +#define DEFAULT_MAX_DATA 512 +#define DEFAULT_MAX_ROWS 100 + +struct Address { + int id; + int set; + char *name; + char *email; +}; + +struct Database { + size_t size; + int max_data; + int max_rows; + struct Address *rows; +}; + +struct Connection { + FILE *file; + struct Database *db; +}; + +void Database_close(struct Connection *conn); + +void die(const char *message, struct Connection *conn) +{ + if(errno) { + perror(message); + } else { + printf("ERROR: %s\n", message); + } + + Database_close(conn); + + exit(1); +} + +void Address_print(struct Address *addr) +{ + printf("%d %s %s\n", + addr->id, addr->name, addr->email); +} + +void Database_load(struct Connection *conn) +{ + rewind(conn->file); + + int rc = fread(&conn->db->max_rows, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to load database max_rows.", conn); + + rc = fread(&conn->db->max_data, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to load database max_data.", conn); + + rc = fread(conn->db->rows, sizeof(struct Address), conn->db->max_rows, conn->file); + if(rc != 1) die("Failed to load database rows.", conn); +} + +struct Connection* Database_open(const char *filename, char mode, int max_rows) +{ + struct Connection *conn = malloc(sizeof(struct Connection)); + if(!conn) die("Memory error", conn); + + conn->db = malloc(sizeof(struct Database)); + if(!conn->db) die("Memory error", conn); + + size_t rowsize = max_rows * sizeof(struct Address); + conn->db->size = rowsize; + conn->db->rows = malloc(rowsize); + if(!conn->db->rows) die("Memory error", conn); + + if(mode == 'c') { + conn->file = fopen(filename, "w"); + } else { + conn->file = fopen(filename, "r+"); + + if(conn->file) { + Database_load(conn); + } + } + + if(!conn->file) die("Failed to open the file", conn); + + return conn; +} + +void Database_close(struct Connection *conn) +{ + if(conn != NULL) { + if(conn->file) fclose(conn->file); + if(conn->db) free(conn->db); + free(conn); + } +} + +void Database_write(struct Connection *conn) +{ + rewind(conn->file); + + int rc = fwrite(&conn->db->size, sizeof(size_t), 1, conn->file); + if(rc != 1) die("Failed to write database size.", conn); + + rc = fwrite(&conn->db->max_rows, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to write database max_rows.", conn); + + rc = fwrite(&conn->db->max_data, sizeof(int), 1, conn->file); + if(rc != 1) die("Failed to write database max_data.", conn); + + rc = fwrite(conn->db->rows, conn->db->size, 1, conn->file); + if(rc != 1) die("Failed to write database rows.", conn); + + rc = fflush(conn->file); + if(rc == -1) die("Cannot flush database.", conn); +} + +void Database_create(struct Connection *conn, int max_rows, int max_data) +{ + int i = 0; + conn->db->max_rows = max_rows; + conn->db->max_data = max_data; + + for(i = 0; i < conn->db->max_rows; i++) { + // make a prototype to initialize it + struct Address addr = {.id = i, .set = 0}; + // then just assign it + conn->db->rows[i] = addr; + } +} + +void Database_set(struct Connection *conn, int id, const char *name, const char *email) +{ + int max_data = conn->db->max_data; + struct Address *addr = &conn->db->rows[id]; + if(addr->set) die("Already set, delete it first", conn); + + addr->set = 1; + char *res = strncpy(addr->name, name, max_data); + if(!res) die("Name copy failed", conn); + addr->name[max_data - 1] = '\0'; + + res = strncpy(addr->email, email, max_data); + if(!res) die("Email copy failed", conn); + addr->email[max_data - 1] = '\0'; +} + +void Database_get(struct Connection *conn, int id) +{ + struct Address *addr = &conn->db->rows[id]; + + if(addr->set) { + Address_print(addr); + } else { + die("ID is not set", conn); + } +} + +void Database_delete(struct Connection *conn, int id) +{ + struct Address addr = {.id = id, .set = 0}; + conn->db->rows[id] = addr; +} + +void Database_list(struct Connection *conn) +{ + int i = 0; + struct Database *db = conn->db; + + for(i = 0; i < conn->db->max_rows; i++) { + struct Address *cur = &db->rows[i]; + + if(cur->set) { + Address_print(cur); + } + } +} + +int main(int argc, char *argv[]) +{ + if(argc < 3) die("USAGE: ex17 [:max_data,max_rows] [action params]", NULL); + + char *filename = argv[1]; + + int max_data = DEFAULT_MAX_DATA; + int max_rows = DEFAULT_MAX_ROWS; + + char action = argv[2][0]; + if(':' == argv[2][1]) { + sscanf(argv[2], "%c:%d,%d", &action, &max_data, &max_rows); + } + + struct Connection *conn = Database_open(filename, action, max_rows); + int id = 0; + + if(argc > 3) id = atoi(argv[3]); + if(id >= max_rows) die("There's not that many records.", conn); + + switch(action) { + case 'c': + Database_create(conn, max_rows, max_data); + Database_write(conn); + break; + + case 'g': + if(argc != 4) die("Need an id to get", conn); + + Database_get(conn, id); + break; + + case 's': + if(argc != 6) die("Need id, name, email to set", conn); + + Database_set(conn, id, argv[4], argv[5]); + Database_write(conn); + break; + + case 'd': + if(argc != 4) die("Need id to delete", conn); + + Database_delete(conn, id); + Database_write(conn); + break; + + case 'l': + Database_list(conn); + break; + default: + die("Invalid action, only: c=create, g=get, s=set, d=del, l=list", conn); + } + + Database_close(conn); + + return 0; +} + From b70415e2c0da00ebbdc6a17867e04757107ba04c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 2 Mar 2012 22:14:13 -0500 Subject: [PATCH 143/145] Reverting ex17 to a state that should be pretty close to the book source ... still need to check --- ex17.c | 110 ++++++++++++++++++--------------------------------------- 1 file changed, 35 insertions(+), 75 deletions(-) diff --git a/ex17.c b/ex17.c index 1eaece1..493d9a1 100644 --- a/ex17.c +++ b/ex17.c @@ -4,21 +4,18 @@ #include #include -#define DEFAULT_MAX_DATA 512 -#define DEFAULT_MAX_ROWS 100 +#define MAX_DATA 512 +#define MAX_ROWS 100 struct Address { int id; int set; - char *name; - char *email; + char name[MAX_DATA]; + char email[MAX_DATA]; }; struct Database { - size_t size; - int max_data; - int max_rows; - struct Address *rows; + struct Address rows[MAX_ROWS]; }; struct Connection { @@ -26,9 +23,7 @@ struct Connection { struct Database *db; }; -void Database_close(struct Connection *conn); - -void die(const char *message, struct Connection *conn) +void die(const char *message) { if(errno) { perror(message); @@ -36,8 +31,6 @@ void die(const char *message, struct Connection *conn) printf("ERROR: %s\n", message); } - Database_close(conn); - exit(1); } @@ -49,30 +42,17 @@ void Address_print(struct Address *addr) void Database_load(struct Connection *conn) { - rewind(conn->file); - - int rc = fread(&conn->db->max_rows, sizeof(int), 1, conn->file); - if(rc != 1) die("Failed to load database max_rows.", conn); - - rc = fread(&conn->db->max_data, sizeof(int), 1, conn->file); - if(rc != 1) die("Failed to load database max_data.", conn); - - rc = fread(conn->db->rows, sizeof(struct Address), conn->db->max_rows, conn->file); - if(rc != 1) die("Failed to load database rows.", conn); + int rc = fread(conn->db, sizeof(struct Database), 1, conn->file); + if(rc != 1) die("Failed to load database."); } -struct Connection* Database_open(const char *filename, char mode, int max_rows) +struct Connection* Database_open(const char *filename, char mode) { struct Connection *conn = malloc(sizeof(struct Connection)); - if(!conn) die("Memory error", conn); + if(!conn) die("Memory error"); conn->db = malloc(sizeof(struct Database)); - if(!conn->db) die("Memory error", conn); - - size_t rowsize = max_rows * sizeof(struct Address); - conn->db->size = rowsize; - conn->db->rows = malloc(rowsize); - if(!conn->db->rows) die("Memory error", conn); + if(!conn->db) die("Memory error"); if(mode == 'c') { conn->file = fopen(filename, "w"); @@ -84,14 +64,14 @@ struct Connection* Database_open(const char *filename, char mode, int max_rows) } } - if(!conn->file) die("Failed to open the file", conn); + if(!conn->file) die("Failed to open the file"); return conn; } void Database_close(struct Connection *conn) { - if(conn != NULL) { + if(conn) { if(conn->file) fclose(conn->file); if(conn->db) free(conn->db); free(conn); @@ -102,29 +82,18 @@ void Database_write(struct Connection *conn) { rewind(conn->file); - int rc = fwrite(&conn->db->size, sizeof(size_t), 1, conn->file); - if(rc != 1) die("Failed to write database size.", conn); - - rc = fwrite(&conn->db->max_rows, sizeof(int), 1, conn->file); - if(rc != 1) die("Failed to write database max_rows.", conn); - - rc = fwrite(&conn->db->max_data, sizeof(int), 1, conn->file); - if(rc != 1) die("Failed to write database max_data.", conn); - - rc = fwrite(conn->db->rows, conn->db->size, 1, conn->file); - if(rc != 1) die("Failed to write database rows.", conn); + int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file); + if(rc != 1) die("Failed to write database."); rc = fflush(conn->file); - if(rc == -1) die("Cannot flush database.", conn); + if(rc == -1) die("Cannot flush database."); } -void Database_create(struct Connection *conn, int max_rows, int max_data) +void Database_create(struct Connection *conn) { int i = 0; - conn->db->max_rows = max_rows; - conn->db->max_data = max_data; - for(i = 0; i < conn->db->max_rows; i++) { + for(i = 0; i < MAX_ROWS; i++) { // make a prototype to initialize it struct Address addr = {.id = i, .set = 0}; // then just assign it @@ -134,18 +103,17 @@ void Database_create(struct Connection *conn, int max_rows, int max_data) void Database_set(struct Connection *conn, int id, const char *name, const char *email) { - int max_data = conn->db->max_data; struct Address *addr = &conn->db->rows[id]; - if(addr->set) die("Already set, delete it first", conn); + if(addr->set) die("Already set, delete it first"); addr->set = 1; - char *res = strncpy(addr->name, name, max_data); - if(!res) die("Name copy failed", conn); - addr->name[max_data - 1] = '\0'; + // WARNING: bug, read the "How To Break It" and fix this + char *res = strncpy(addr->name, name, MAX_DATA); + // demonstrate the strncpy bug + if(!res) die("Name copy failed"); - res = strncpy(addr->email, email, max_data); - if(!res) die("Email copy failed", conn); - addr->email[max_data - 1] = '\0'; + res = strncpy(addr->email, email, MAX_DATA); + if(!res) die("Email copy failed"); } void Database_get(struct Connection *conn, int id) @@ -155,7 +123,7 @@ void Database_get(struct Connection *conn, int id) if(addr->set) { Address_print(addr); } else { - die("ID is not set", conn); + die("ID is not set"); } } @@ -170,7 +138,7 @@ void Database_list(struct Connection *conn) int i = 0; struct Database *db = conn->db; - for(i = 0; i < conn->db->max_rows; i++) { + for(i = 0; i < MAX_ROWS; i++) { struct Address *cur = &db->rows[i]; if(cur->set) { @@ -181,45 +149,37 @@ void Database_list(struct Connection *conn) int main(int argc, char *argv[]) { - if(argc < 3) die("USAGE: ex17 [:max_data,max_rows] [action params]", NULL); + if(argc < 3) die("USAGE: ex17 [action params]"); char *filename = argv[1]; - - int max_data = DEFAULT_MAX_DATA; - int max_rows = DEFAULT_MAX_ROWS; - char action = argv[2][0]; - if(':' == argv[2][1]) { - sscanf(argv[2], "%c:%d,%d", &action, &max_data, &max_rows); - } - - struct Connection *conn = Database_open(filename, action, max_rows); + struct Connection *conn = Database_open(filename, action); int id = 0; if(argc > 3) id = atoi(argv[3]); - if(id >= max_rows) die("There's not that many records.", conn); + if(id >= MAX_ROWS) die("There's not that many records."); switch(action) { case 'c': - Database_create(conn, max_rows, max_data); + Database_create(conn); Database_write(conn); break; case 'g': - if(argc != 4) die("Need an id to get", conn); + if(argc != 4) die("Need an id to get"); Database_get(conn, id); break; case 's': - if(argc != 6) die("Need id, name, email to set", conn); + if(argc != 6) die("Need id, name, email to set"); Database_set(conn, id, argv[4], argv[5]); Database_write(conn); break; case 'd': - if(argc != 4) die("Need id to delete", conn); + if(argc != 4) die("Need id to delete"); Database_delete(conn, id); Database_write(conn); @@ -229,7 +189,7 @@ int main(int argc, char *argv[]) Database_list(conn); break; default: - die("Invalid action, only: c=create, g=get, s=set, d=del, l=list", conn); + die("Invalid action, only: c=create, g=get, s=set, d=del, l=list"); } Database_close(conn); From d6c08d37b9c7de1ad02eae2541dd09c7abf6df36 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 12 Apr 2012 21:30:52 -0400 Subject: [PATCH 144/145] TRIVIAL whitespace removal --- ex17.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ex17.c b/ex17.c index 493d9a1..409a86a 100644 --- a/ex17.c +++ b/ex17.c @@ -196,4 +196,3 @@ int main(int argc, char *argv[]) return 0; } - From e172f73c8297b22a579c94558f0c171ca74a0e5c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 13 Apr 2012 08:36:43 -0400 Subject: [PATCH 145/145] Working through ex17 extra credit (again) and writing tests this time --- .gitignore | 2 + ex17-ec1.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++ test.sh | 35 +++++++++ test_ex17.sh | 55 ++++++++++++++ 4 files changed, 293 insertions(+) create mode 100644 ex17-ec1.c create mode 100644 test.sh create mode 100755 test_ex17.sh diff --git a/.gitignore b/.gitignore index 6372ebf..8ed1cb2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ ex14 ex15 ex16 ex17 +ex17-* +!ex17-*.c ex18 ex19 ex20 diff --git a/ex17-ec1.c b/ex17-ec1.c new file mode 100644 index 0000000..aa360cb --- /dev/null +++ b/ex17-ec1.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include + +#define MAX_DATA 512 +#define MAX_ROWS 100 + +struct Address { + int id; + int set; + char name[MAX_DATA]; + char email[MAX_DATA]; +}; + +struct Database { + struct Address rows[MAX_ROWS]; +}; + +struct Connection { + FILE *file; + struct Database *db; +}; + +void Database_close(struct Connection *conn); + +void die(struct Connection *conn, const char *message) +{ + if(errno) { + perror(message); + } else { + printf("ERROR: %s\n", message); + } + + Database_close(conn); + exit(1); +} + +void Address_print(struct Address *addr) +{ + printf("%d %s %s\n", + addr->id, addr->name, addr->email); +} + +void Database_load(struct Connection *conn) +{ + int rc = fread(conn->db, sizeof(struct Database), 1, conn->file); + if(rc != 1) die(conn, "Failed to load database."); +} + +struct Connection* Database_open(const char *filename, char mode) +{ + struct Connection *conn = malloc(sizeof(struct Connection)); + if(!conn) die(NULL, "Memory error"); + + conn->db = malloc(sizeof(struct Database)); + if(!conn->db) die(conn, "Memory error"); + + if(mode == 'c') { + conn->file = fopen(filename, "w"); + } else { + conn->file = fopen(filename, "r+"); + + if(conn->file) { + Database_load(conn); + } + } + + if(!conn->file) die(conn, "Failed to open the file"); + + return conn; +} + +void Database_close(struct Connection *conn) +{ + if(conn) { + if(conn->file) fclose(conn->file); + if(conn->db) free(conn->db); + free(conn); + } +} + +void Database_write(struct Connection *conn) +{ + rewind(conn->file); + + int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file); + if(rc != 1) die(conn, "Failed to write database."); + + rc = fflush(conn->file); + if(rc == -1) die(conn, "Cannot flush database."); +} + +void Database_create(struct Connection *conn) +{ + int i = 0; + + for(i = 0; i < MAX_ROWS; i++) { + // make a prototype to initialize it + struct Address addr = {.id = i, .set = 0}; + // then just assign it + conn->db->rows[i] = addr; + } +} + +void Database_set(struct Connection *conn, int id, const char *name, const char *email) +{ + struct Address *addr = &conn->db->rows[id]; + if(addr->set) die(conn, "Already set, delete it first"); + + addr->set = 1; + // WARNING: bug, read the "How To Break It" and fix this + char *res = strncpy(addr->name, name, MAX_DATA); + // demonstrate the strncpy bug + if(!res) die(conn, "Name copy failed"); + + res = strncpy(addr->email, email, MAX_DATA); + if(!res) die(conn, "Email copy failed"); +} + +void Database_get(struct Connection *conn, int id) +{ + struct Address *addr = &conn->db->rows[id]; + + if(addr->set) { + Address_print(addr); + } else { + die(conn, "ID is not set"); + } +} + +void Database_delete(struct Connection *conn, int id) +{ + struct Address addr = {.id = id, .set = 0}; + conn->db->rows[id] = addr; +} + +void Database_list(struct Connection *conn) +{ + int i = 0; + struct Database *db = conn->db; + + for(i = 0; i < MAX_ROWS; i++) { + struct Address *cur = &db->rows[i]; + + if(cur->set) { + Address_print(cur); + } + } +} + +int main(int argc, char *argv[]) +{ + if(argc < 3) die(NULL, "USAGE: ex17 [action params]"); + + char *filename = argv[1]; + char action = argv[2][0]; + struct Connection *conn = Database_open(filename, action); + int id = 0; + + if(argc > 3) id = atoi(argv[3]); + if(id >= MAX_ROWS) die(conn, "There's not that many records."); + + switch(action) { + case 'c': + Database_create(conn); + Database_write(conn); + break; + + case 'g': + if(argc != 4) die(conn, "Need an id to get"); + + Database_get(conn, id); + break; + + case 's': + if(argc != 6) die(conn, "Need id, name, email to set"); + + Database_set(conn, id, argv[4], argv[5]); + Database_write(conn); + break; + + case 'd': + if(argc != 4) die(conn, "Need id to delete"); + + Database_delete(conn, id); + Database_write(conn); + break; + + case 'l': + Database_list(conn); + break; + default: + die(conn, "Invalid action, only: c=create, g=get, s=set, d=del, l=list"); + } + + Database_close(conn); + + return 0; +} diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..7a580f2 --- /dev/null +++ b/test.sh @@ -0,0 +1,35 @@ +EXIT_CODE=0 +ASSERT_COUNT=0 + + +function assert_equal(){ + if [[ $1 == $2 ]] ; then + echo -n "." + else + echo -n "F" + EXIT_CODE=1 + fi + ASSERT_COUNT=$(expr $ASSERT_COUNT + 1) +} + + +function assert_not_equal(){ + if [[ $1 != $2 ]] ; then + echo -n "." + else + echo -n "F" + EXIT_CODE=1 + fi + ASSERT_COUNT=$(expr $ASSERT_COUNT + 1) +} + + +function test_finish(){ + echo + if [ $EXIT_CODE -eq 0 ]; then + echo "PASS" + else + echo "FAIL" + fi + exit $EXIT_CODE +} diff --git a/test_ex17.sh b/test_ex17.sh new file mode 100755 index 0000000..2619301 --- /dev/null +++ b/test_ex17.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +source './test.sh' + +prog=${1-'./ex17'} +test_db=db.$$.$RANDOM.dat + +# ---------------------------------------------------------------------------- + +$prog 2>&1 >/dev/null +assert_equal $? 1 + +$prog $test_db c 2>&1 >/dev/null +assert_equal $? 0 + +$prog $test_db s 2>&1 >/dev/null +assert_equal $? 1 + +$prog $test_db s 1 ham ham@foo.bar +assert_equal $? 0 +$prog $test_db s 2 derp derp@foo.bar +assert_equal $? 0 +$prog $test_db s 3 herp herp@foo.bar +assert_equal $? 0 +$prog $test_db s 4 zap zap@foo.bar +assert_equal $? 0 + +$prog $test_db l > $$.out +grep '1 ham ham@foo.bar' $$.out >/dev/null +assert_equal $? 0 +$prog $test_db l > $$.out +grep '2 derp derp@foo.bar' $$.out >/dev/null +assert_equal $? 0 +$prog $test_db l > $$.out +grep '3 herp herp@foo.bar' $$.out >/dev/null +assert_equal $? 0 +$prog $test_db l > $$.out +grep '4 zap zap@foo.bar' $$.out >/dev/null +assert_equal $? 0 + +$prog $test_db g 1 > $$.out +grep '1 ham ham@foo.bar' $$.out >/dev/null +assert_equal $? 0 + +$prog $test_db d 1 +$prog $test_db l > $$.out +grep 'ham@foo.bar' $$.out >/dev/null +assert_not_equal $? 0 + +# ---------------------------------------------------------------------------- + +rm -f $$.out +rm -f $test_db + +test_finish