diff --git a/README.md b/README.md index fbcb2ccca81ed9cf996d1a3dea689c6012e0249a..8952b627200bd31041b48e886a811ef001972a60 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ 21st-Century-Examples ===================== -[ Until I actually populate this repository, get the examples from http://examples.oreilly.com/0636920025108/ .] - Dear Reader, Here are all of the examples from _21st Century C_ by Ben Klemens [ http://tinyurl.com/C-for-moderns ]. You'll notice that the captions for all of the examples in the text end in a filename in parens, like (string_utilities.c); that name is referring to the file here. diff --git a/amort_interface.c b/amort_interface.c new file mode 100644 index 0000000000000000000000000000000000000000..3df1a6cea9d7c5d49904cea1212b92b0e498cbd0 --- /dev/null +++ b/amort_interface.c @@ -0,0 +1,28 @@ +/* See compilation notes in amort_use.c*/ +#include "stopif.h" +#include +#include "amortize.h" + +amortization_s amortize_prep(amortization_s in){ + Stopif(!in.amount || in.amount < 0 || in.rate < 0 + || in.months < 0 || in.years < 0 || in.selloff_month < 0 || in.selloff_year < 0, + return (amortization_s){.error="Invalid input"}, + "Invalid input. Returning zeros."); + + int months = in.months; + if (!months){ + if (in.years) months = in.years * 12; + else months = 12 * 30; //home loan + } + + int selloff_month = in.selloff_month; + if (!selloff_month && in.selloff_year) + selloff_month = in.selloff_year * 12; + + amortization_s out = in; + out.rate = in.rate ? in.rate : 4.5; + out.interest = amortize(in.amount, out.rate, in.inflation, + months, selloff_month, in.extra_payoff, in.show_table, + &(out.interest_pv), &(out.years_to_payoff), &(out.monthly_payment)); + return out; +} diff --git a/amort_use.c b/amort_use.c new file mode 100644 index 0000000000000000000000000000000000000000..73c8bd6402035f1f2d776d0362e2a25f2132ba6e --- /dev/null +++ b/amort_use.c @@ -0,0 +1,29 @@ +/* Suggested makefile: +---------- +P=amort_use +objects=amort_interface.o amortize.o +LDLIBS=-lm +CFLAGS=-g -Wall -O3 -std=gnu11 #the usual + +$(P):$(objects) +---------- +*/ +#include +#include "amortize.h" + +int main(){ + printf("A typical loan:\n"); + amortization_s nopayments = amortization(.amount=200000, .inflation=3); + printf("You flushed real $%g down the toilet, or $%g in present value.\n", + nopayments.interest, nopayments.interest_pv); + + amortization_s a_hundred = amortization(.amount=200000, .inflation=3, + .show_table=0, .extra_payoff=100); + printf("Paying an extra $100/month, you lose only $%g (PV), " + "and the loan is paid off in %g years.\n", + a_hundred.interest_pv, a_hundred.years_to_payoff); + + printf("If you sell off in ten years, you pay $%g in interest (PV).\n", + amortization(.amount=200000, .inflation=3, + .show_table=0, .selloff_year=10).interest_pv); +} diff --git a/amortize.c b/amortize.c new file mode 100644 index 0000000000000000000000000000000000000000..c5208f3809af2c5df4ebff42f1537f0eb1c9b21c --- /dev/null +++ b/amortize.c @@ -0,0 +1,38 @@ +/* See compilation notes in amort_use.c*/ +#include //pow. +#include +#include "amortize.h" + +double amortize(double amt, double rate, double inflation, int months, + int selloff_month, double extra_payoff, int verbose, + double *interest_pv, double *duration, double *monthly_payment){ + double total_interest = 0; + *interest_pv = 0; + double mrate = rate/1200; + + //The monthly rate is fixed, but the proportion going to interest changes. + *monthly_payment = amt * mrate/(1-pow(1+mrate, -months))+extra_payoff; + if (verbose) printf("Your total monthly payment: %g\n\n", *monthly_payment); + int end_month = (selloff_month && selloff_month < months ) + ? selloff_month + : months; + if (verbose) printf("yr/mon\t Princ.\t\tInt.\t| PV Princ.\t PV Int.\t Ratio\n"); + int m; + for (m=0; m < end_month && amt > 0; m++){ + double interest_payment = amt*mrate; + double principal_payment = *monthly_payment - interest_payment; + if (amt <= 0) + principal_payment = + interest_payment = 0; + amt -= principal_payment; + double deflator = pow(1+ inflation/100, -m/12.); + *interest_pv += interest_payment * deflator; + total_interest += interest_payment; + if (verbose) printf("%i/%i\t%7.2f\t\t%7.2f\t| %7.2f\t %7.2f\t%7.2f\n", + m/12, m-12*(m/12)+1, principal_payment, interest_payment, + principal_payment*deflator, interest_payment*deflator, + principal_payment/(principal_payment+interest_payment)*100); + } + *duration = m/12.; + return total_interest; +} diff --git a/amortize.h b/amortize.h new file mode 100644 index 0000000000000000000000000000000000000000..fcbe98829027269f32e4e478f90bec7bbb3d0079 --- /dev/null +++ b/amortize.h @@ -0,0 +1,57 @@ +/* See compilation notes in amort_use.c*/ +double amortize(double amt, double rate, double inflation, int months, + int selloff_month, double extra_payoff, int verbose, + double *interest_pv, double *duration, double *monthly_payment); + +typedef struct { + double amount, years, rate, selloff_year, extra_payoff, inflation; + int months, selloff_month; + _Bool show_table; + double interest, interest_pv, monthly_payment, years_to_payoff; + char *error; +} amortization_s; + + +/** +Calculate the inflation-adjusted amount of interest you would pay +over the life of an amortized loan, such as a mortgage. + +\li \c amount The dollar value of the loan. No default--if unspecified, + I print an error and return zeros. +\li \c months The number of months in the loan. Default: zero, but see years. +\li \c years If you do not specify months, you can specify the number of + years. E.g., 10.5=ten years, six months. + Default: 30 (a typical U.S. mortgage). +\li \c rate The interest rate of the loan, expressed in annual + percentage rate (APR). Default: 4.5 (i.e., 4.5%), which + is typical for the current (US 2012) housing market. +\li \c inflation The inflation rate as an annual percent, for calculating + the present value of money. Default: 0, meaning no + present-value adjustment. A rate of about 3 has been typical + for the last few decades in the USA. +\li \c selloff_month At this month, the loan is paid off (e.g., you resell + the house). Default: zero (meaning no selloff). +\li \c selloff_year If selloff_month==0 and this is positive, the year of + selloff. Default: zero (meaning no selloff). +\li \c extra_payoff Additional monthly principal payment. Default: zero. +\li \c show_table If nonzero, display a table of payments. If zero, display + nothing (just return the total interest). Default: 1 + +All inputs but \c extra_payoff and \c inflation must be nonnegative. + +\return an \c amortization_s structure, with all of the above values set as + per your input, plus: + +\li \c interest Total cash paid in interest. +\li \c interest_pv Total interest paid, with present-value adjustment for inflation. +\li \c monthly_payment The fixed monthly payment (for a mortgage, taxes and + interest get added to this) +\li \c years_to_payoff Normally the duration or selloff date, but if you make early + payments, the loan is paid off sooner. +\li error If error != NULL, something went wrong and the results are invalid. + +*/ +#define amortization(...) amortize_prep((amortization_s){.show_table=1, \ + __VA_ARGS__}) + +amortization_s amortize_prep(amortization_s in); diff --git a/arithmetic.c b/arithmetic.c new file mode 100644 index 0000000000000000000000000000000000000000..6838033a12a7ceb638c158fbe6f03af50c6d56a9 --- /dev/null +++ b/arithmetic.c @@ -0,0 +1,11 @@ +/* Compile with: +make arithmetic CFLAGS="-g -Wall -std=gnu11 -O3" +*/ +#include + +int main(){ + int evens[5] = {0, 2, 4, 6, 8}; + printf("The first even number is, of course, %i\n", *evens); + int *positive_evens = &evens[1]; + printf("The first positive even number is %i\n", positive_evens[0]); +} diff --git a/auto.conf b/auto.conf new file mode 100644 index 0000000000000000000000000000000000000000..388531301555259e22f240c1d31674db2dffb2f0 --- /dev/null +++ b/auto.conf @@ -0,0 +1,29 @@ +if [ -e autodemo ]; then rm -r autodemo; fi +mkdir -p autodemo +cd autodemo +cat > hello.c <<\ +"--------------" +#include + +int main(){ printf("Hi.\n"); } +-------------- + +cat > Makefile.am <<\ +"--------------" +bin_PROGRAMS=hello +hello_SOURCES=hello.c +-------------- + +autoscan +sed -e 's/FULL-PACKAGE-NAME/hello/' \ + -e 's/VERSION/1/' \ + -e 's|BUG-REPORT-ADDRESS|/dev/null|' \ + -e '10i\ +AM_INIT_AUTOMAKE' \ + < configure.scan > configure.ac + +touch NEWS README AUTHORS ChangeLog + +autoreconf -iv +./configure +make distcheck diff --git a/automem.c b/automem.c new file mode 100644 index 0000000000000000000000000000000000000000..12f241f84d664b40c7de5dc6fa78c349d0e80c9e --- /dev/null +++ b/automem.c @@ -0,0 +1,30 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make automem +*/ +#include + +typedef struct powers { + double base, square, cube; +} powers; + +powers get_power(double in){ + powers out = {.base = in, + .square = in*in, + .cube = in*in*in}; + return out; +} + +int *get_even(int count){ + int out[count]; + for (int i=0; i< count; i++) + out[i] = 2*i; + return out; //bad. +} + +int main(){ + powers threes = get_power(3); + int *evens = get_even(3); + printf("threes: %g\t%g\t%g\n", threes.base, threes.square, threes.cube); + printf("evens: %i\t%i\t%i\n", evens[0], evens[1], evens[2]); +} diff --git a/benford.sh b/benford.sh new file mode 100644 index 0000000000000000000000000000000000000000..82ba5d8668d4e0d237ffb92257567486a9a40fa6 --- /dev/null +++ b/benford.sh @@ -0,0 +1,2 @@ +for i in 0 1 2 3 4 5 6 7 8 9; do grep -E '(^|[^0-9.])'$i *.c > lines_with_${i}; done +wc -l lines_with* diff --git a/boxes.c b/boxes.c new file mode 100644 index 0000000000000000000000000000000000000000..48e2ef0898f74a102fa3067bad158a42604ec21c --- /dev/null +++ b/boxes.c @@ -0,0 +1,37 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make boxes +*/ +#include + +typedef struct { + char *name; + int left, right, up, down; +} direction_s; + +void this_row(direction_s d); //these functions are below +void draw_box(direction_s d); + +int main(){ + direction_s D = {.name="left", .left=1}; + draw_box(D); + + D = (direction_s) {"upper right", .up=1, .right=1}; + draw_box(D); + + draw_box((direction_s){}); +} + +void this_row(direction_s d){ + printf( d.left ? "*..\n" + : d.right ? "..*\n" + : ".*.\n"); +} + +void draw_box(direction_s d){ + printf("%s:\n", (d.name ? d.name : "a box")); + d.up ? this_row(d) : printf("...\n"); + (!d.up && !d.down) ? this_row(d) : printf("...\n"); + d.down ? this_row(d) : printf("...\n"); + printf("\n"); +} diff --git a/cetology.c b/cetology.c new file mode 100644 index 0000000000000000000000000000000000000000..5ec633bd7d33be7a6940fa82078e31f5b3c6eea1 --- /dev/null +++ b/cetology.c @@ -0,0 +1,31 @@ +/* Suggested makefile: +---------- +P=cetology +CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3 +LDLIBS=`pkg-config --libs glib-2.0` +objects=fstr.o string_utilities.o + +$(P): $(objects) +---------- +*/ +#include "fstr.h" + +int main(){ + fstr_s *fstr = fstr_new("moby"); + fstr_list chapters = fstr_split(fstr, "\nCHAPTER"); + for (int i=0; i< chapters.count; i++){ + fstr_list for_the_title=fstr_split(chapters.strings[i],"\\."); + fstr_show(for_the_title.strings[1]); + fstr_list me = fstr_split(chapters.strings[i], "\\WI\\W"); + fstr_list whales = fstr_split(chapters.strings[i], "whale(s|)"); + fstr_list words = fstr_split(chapters.strings[i], "\\W"); + printf("\nch %i, words: %i.\t Is: %i\twhales: %i\n", i, words.count-1, + me.count-1, whales.count-1); + fstr_list_free(for_the_title); + fstr_list_free(me); + fstr_list_free(whales); + fstr_list_free(words); + } + fstr_list_free(chapters); + fstr_free(fstr); +} diff --git a/cetology.make b/cetology.make new file mode 100644 index 0000000000000000000000000000000000000000..a9c7710d4eaf34499a998f1214292d2cbeeb9be7 --- /dev/null +++ b/cetology.make @@ -0,0 +1,6 @@ +P=cetology +CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3 +LDLIBS=`pkg-config --libs glib-2.0` +objects=fstr.o string_utilities.o + +$(P): $(objects) diff --git a/charct.c b/charct.c new file mode 100644 index 0000000000000000000000000000000000000000..2c956f1ca60817e00be583c092381a9ca65f9dc6 --- /dev/null +++ b/charct.c @@ -0,0 +1,39 @@ +/* Suggested makefile: +---------- +P=charct +objects=string_utilities.o process_dir.o unictr.o +CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu11 -O3 +LDLIBS=`pkg-config --libs glib-2.0` + +$(P): $(objects) +---------- +*/ +#define _GNU_SOURCE //get stdio.h to define asprintf +#include "string_utilities.h" //string_from_file +#include "process_dir.h" +#include "unictr.h" +#include +#include //free + +void hash_a_file(filestruct path){ + GHashTable *hash = path.data; + char *sf = string_from_file(path.fullname); + if (!sf) return; + char *sf_copy = sf; + if (g_utf8_validate(sf, -1, NULL)){ + for (gunichar uc; (uc = g_utf8_get_char(sf))!='\0'; + sf = g_utf8_next_char(sf)) + hash_a_character(uc, hash); + } + free(sf_copy); +} + +int main(int argc, char **argv){ + GHashTable *hash; + hash = new_unicode_counting_hash(); + char *start=NULL; + if (argc>1) asprintf(&start, "%s", argv[1]); + printf("Hashing %s\n", start ? start: "the current directory"); + process_dir(.name=start, .file_action=hash_a_file, .data=hash); + g_hash_table_foreach(hash, printone, NULL); +} diff --git a/complex.c b/complex.c new file mode 100644 index 0000000000000000000000000000000000000000..7b183c39a38edec6dfff8511146603fa195a6548 --- /dev/null +++ b/complex.c @@ -0,0 +1,37 @@ +/* See compilation notes in simple_cplx.c*/ +#include "cplx.h" //gsl_cplx_from_c99; see below. +#include //gsl_blas_ddot +#include //gsl_complex_mul(_real) + +gsl_vector_complex *cvec_dot_gslcplx(gsl_vector_complex *v, gsl_complex x){ + gsl_vector_complex *out = gsl_vector_complex_alloc(v->size); + for (int i=0; i< v->size; i++) + gsl_vector_complex_set(out, i, + gsl_complex_mul(x, gsl_vector_complex_get(v, i))); + return out; +} + +gsl_vector_complex *vec_dot_gslcplx(gsl_vector *v, gsl_complex x){ + gsl_vector_complex *out = gsl_vector_complex_alloc(v->size); + for (int i=0; i< v->size; i++) + gsl_vector_complex_set(out, i, + gsl_complex_mul_real(x, gsl_vector_get(v, i))); + return out; +} + +gsl_vector_complex *cvec_dot_c(gsl_vector_complex *v, complex double x){ + return cvec_dot_gslcplx(v, gsl_cplx_from_c99(x)); +} + +gsl_vector_complex *vec_dot_c(gsl_vector *v, complex double x){ + return vec_dot_gslcplx(v, gsl_cplx_from_c99(x)); +} + +complex double ddot (complex double x, complex double y){return x*y;} + +void gsl_vector_complex_print(gsl_vector_complex *v){ + for (int i=0; i< v->size; i++) { + gsl_complex x = gsl_vector_complex_get(v, i); + printf("%4g+%4gi%c", GSL_REAL(x), GSL_IMAG(x), i < v->size-1 ? '\t' : '\n'); + } +} diff --git a/const.c b/const.c new file mode 100644 index 0000000000000000000000000000000000000000..732d138d0c9e165a9cfef3217d9ef83f3a97f5e8 --- /dev/null +++ b/const.c @@ -0,0 +1,14 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make const +*/ +#include + +int main(){ + int *var; + int const **constptr = &var; // the line that sets up the failure + int const fixed = 20; + *constptr = &fixed; // 100% valid + *var = 30; + printf("x=%i y=%i\n", fixed, *var); +} diff --git a/constchange.c b/constchange.c new file mode 100644 index 0000000000000000000000000000000000000000..e91065d9ccb5878e4f160ce0ec87f6a9d2948dd4 --- /dev/null +++ b/constchange.c @@ -0,0 +1,12 @@ +/* Compile with: +CFLAGS="-g -Wall" CC=c99 make constchange +*/ +void set_elmt(int *a, int const *b){ + a[0] = 3; +} + +int main(){ + int a[10] = {}; + int const *b = a; + set_elmt(a, b); +} diff --git a/constfusion.c b/constfusion.c new file mode 100644 index 0000000000000000000000000000000000000000..97edd5d935a2afddff0440e179a7bb8088348ae1 --- /dev/null +++ b/constfusion.c @@ -0,0 +1,14 @@ +/* Compile with: +export CFLAGS="-g -std=gnu11 -O3" #The usual, but without -Wall +make constfusion #Still, this will throw a warning +*/ +#include + +int main(){ + int *var; + int const **constptr = &var; // the line that sets up the failure + int const fixed = 20; + *constptr = &fixed; // 100% valid + *var = 30; + printf("x=%i y=%i\n", fixed, *var); +} diff --git a/conststruct.c b/conststruct.c new file mode 100644 index 0000000000000000000000000000000000000000..3c74cc942b5b53929fd4c920a22ffbb42cff9c2c --- /dev/null +++ b/conststruct.c @@ -0,0 +1,25 @@ +/* Compile with: +export CFLAGS="-g -Wall -O3" #the usual. +export CC=c99 +make conststruct +*/ +#include +#include + +typedef struct { + int *counter1, *counter2; +} counter_s; + +void check_counter(int *ctr){ assert(*ctr !=0); } + +double ratio(counter_s const *in){ + check_counter(in->counter2); + return *in->counter1/(*in->counter2+0.0); +} + +int main(){ + counter_s cc = {.counter1=malloc(sizeof(int)), + .counter2=malloc(sizeof(int))}; + *cc.counter1 = *cc.counter2 = 1; + ratio(&cc); +} diff --git a/copystructs.c b/copystructs.c new file mode 100644 index 0000000000000000000000000000000000000000..7ed69ac3e4d7a4b7a9092d28767b64d2ace839c4 --- /dev/null +++ b/copystructs.c @@ -0,0 +1,25 @@ +/* Compile with: +make copystructs CFLAGS="-g -Wall -O3 -std=gnu99" +*/ +#include + +typedef struct{ + int a, b; + double c, d; + int *efg; +} demo_s; + +int main(){ + demo_s d1 = {.b=1, .c=2, .d=3, .efg=(int[]){4,5,6}}; + demo_s d2 = d1; + + d1.b=14; + d1.c=41; + d1.efg[0]=7; + + assert(d2.a==0); + assert(d2.b==1); + assert(d2.c==2); + assert(d2.d==3); + assert(d2.efg[0]==7); +} diff --git a/copystructs2.c b/copystructs2.c new file mode 100644 index 0000000000000000000000000000000000000000..36bd922f815f2425406acb648ca39cac48aa371b --- /dev/null +++ b/copystructs2.c @@ -0,0 +1,12 @@ +/* Compile with: +make copystructs2 CFLAGS="-g -Wall -O3 -std=gnu99" +*/ +#include + +int main(){ + int abc[] = {0, 1, 2}; + int *copy = abc; + + copy[0] = 3; + assert(abc[0]==3); +} diff --git a/cplx.h b/cplx.h new file mode 100644 index 0000000000000000000000000000000000000000..49dc2d52a27d1b26bb8b0963b1c2b1d1d24cf06a --- /dev/null +++ b/cplx.h @@ -0,0 +1,28 @@ +/* See compilation notes in simple_cplx.c*/ +#include //nice names for C's complex types +#include //gsl_vector_complex + +gsl_vector_complex *cvec_dot_gslcplx(gsl_vector_complex *v, gsl_complex x); +gsl_vector_complex *vec_dot_gslcplx(gsl_vector *v, gsl_complex x); +gsl_vector_complex *cvec_dot_c(gsl_vector_complex *v, complex double x); +gsl_vector_complex *vec_dot_c(gsl_vector *v, complex double x); +void gsl_vector_complex_print(gsl_vector_complex *v); + +#define gsl_cplx_from_c99(x) (gsl_complex){.dat= {creal(x), cimag(x)}} + +complex double ddot (complex double x, complex double y); + +#define dot(x,y) _Generic((x), \ + gsl_vector*: dot_given_vec(y), \ + gsl_vector_complex*: dot_given_cplx_vec(y), \ + default: ddot)((x),(y)) + +#define dot_given_vec(y) _Generic((y), \ + gsl_complex: vec_dot_gslcplx, \ + default: vec_dot_c) + +#define dot_given_cplx_vec(y) _Generic((y), \ + gsl_complex: cvec_dot_gslcplx, \ + default: cvec_dot_c) + + diff --git a/curly.c b/curly.c new file mode 100644 index 0000000000000000000000000000000000000000..98af1520928e28a1eb7b9a743665bcadf910fca2 --- /dev/null +++ b/curly.c @@ -0,0 +1,20 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make curly +*/ +#include + +#define sum(max, out) { \ + int total=0; \ + for (int i=0; i<= max; i++){ \ + total += i; \ + } \ + out = total; \ +} + +int main(){ + int out; + int total = 5; + sum(5, out); + printf("out= %i original total=%i\n", out, total); +} diff --git a/dict.automake b/dict.automake new file mode 100644 index 0000000000000000000000000000000000000000..c917550b3bb0c3152a6c429ec81418bce78bf7c2 --- /dev/null +++ b/dict.automake @@ -0,0 +1,14 @@ +AM_CFLAGS=`pkg-config --cflags glib-2.0` -O3 -Wall + +lib_LTLIBRARIES=libdict.la +libdict_la_SOURCES=dict.c keyval.c + +include_HEADERS=keyval.h dict.h + +bin_PROGRAMS=dict_use +dict_use_SOURCES=dict_use.c +dict_use_LDADD=libdict.la + +TESTS=$(check_PROGRAMS) +check_PROGRAMS=dict_test +dict_test_LDADD=libdict.la diff --git a/dict.c b/dict.c new file mode 100644 index 0000000000000000000000000000000000000000..2a26231c5134fe525f5c507b723f66e82d00ffa3 --- /dev/null +++ b/dict.c @@ -0,0 +1,45 @@ +/* See compilation notes in dict_use.c*/ +#include +#include +#include "dict.h" + +void *dictionary_not_found; + +dictionary *dictionary_new (void){ + static int dnf; + if (!dictionary_not_found) dictionary_not_found = &dnf; + dictionary *out= malloc(sizeof(dictionary)); + *out= (dictionary){ }; + return out; +} + +static void dictionary_add_keyval(dictionary *in, keyval *kv){ + in->length++; + in->pairs = realloc(in->pairs, sizeof(keyval*)*in->length); + in->pairs[in->length-1] = kv; +} + +void dictionary_add(dictionary *in, char *key, void *value){ + if (!key){fprintf(stderr, "NULL is not a valid key.\n"); abort();} + dictionary_add_keyval(in, keyval_new(key, value)); +} + +void *dictionary_find(dictionary const *in, char const *key){ + for (int i=0; i< in->length; i++) + if (keyval_matches(in->pairs[i], key)) + return in->pairs[i]->value; + return dictionary_not_found; +} + +dictionary *dictionary_copy(dictionary *in){ + dictionary *out = dictionary_new(); + for (int i=0; i< in->length; i++) + dictionary_add_keyval(out, keyval_copy(in->pairs[i])); + return out; +} + +void dictionary_free(dictionary *in){ + for (int i=0; i< in->length; i++) + keyval_free(in->pairs[i]); + free(in); +} diff --git a/dict.h b/dict.h new file mode 100644 index 0000000000000000000000000000000000000000..2544d5f6074df2c11cddfd1301e3aada17204ce1 --- /dev/null +++ b/dict.h @@ -0,0 +1,15 @@ +/* See compilation notes in dict_use.c*/ +#include "keyval.h" + +extern void *dictionary_not_found; + +typedef struct dictionary{ + keyval **pairs; + int length; +} dictionary; + +dictionary *dictionary_new (void); +dictionary *dictionary_copy(dictionary *in); +void dictionary_free(dictionary *in); +void dictionary_add(dictionary *in, char *key, void *value); +void *dictionary_find(dictionary const *in, char const *key); diff --git a/dict_test.c b/dict_test.c new file mode 100644 index 0000000000000000000000000000000000000000..fa7b5693ad91982db0e5fd401d14ded2ee9eed3b --- /dev/null +++ b/dict_test.c @@ -0,0 +1,63 @@ +/* Suggested makefile: +---------- + #Or, use the script in dict_use.c to use as an Autotools build check. +CFLAGS=-g -Wall -O3 `pkg-config --cflags glib-2.0` +LDADD=`pkg-config --libs glib-2.0` + +dict_test: dict.o keyval.o +---------- +*/ +#include +#include "dict.h" + +typedef struct { + dictionary *dd; +} dfixture; + +void dict_setup(dfixture *df, gconstpointer test_data){ + df->dd = dictionary_new(); + dictionary_add(df->dd, "key1", "val1"); + dictionary_add(df->dd, "key2", NULL); +} + +void dict_teardown(dfixture *df, gconstpointer test_data){ + dictionary_free(df->dd); +} + +void check_keys(dictionary const *d){ + char *got_it = dictionary_find(d, "xx"); + g_assert(got_it == dictionary_not_found); + got_it = dictionary_find(d, "key1"); + g_assert_cmpstr(got_it, ==, "val1"); + got_it = dictionary_find(d, "key2"); + g_assert_cmpstr(got_it, ==, NULL); +} + +void test_new(dfixture *df, gconstpointer ignored){ + check_keys(df->dd); +} + +void test_copy(dfixture *df, gconstpointer ignored){ + dictionary *cp = dictionary_copy(df->dd); + check_keys(cp); + dictionary_free(cp); +} + +void test_failure(){ + if (g_test_trap_fork(0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)){ + dictionary *dd = dictionary_new(); + dictionary_add(dd, NULL, "blank"); + } + g_test_trap_assert_failed(); + g_test_trap_assert_stderr("NULL is not a valid key.\n"); +} + +int main(int argc, char **argv){ + g_test_init(&argc, &argv, NULL); + g_test_add ("/set1/new test", dfixture, NULL, + dict_setup, test_new, dict_teardown); + g_test_add ("/set1/copy test", dfixture, NULL, + dict_setup, test_copy, dict_teardown); + g_test_add_func ("/set2/fail test", test_failure); + return g_test_run(); +} diff --git a/dict_use.c b/dict_use.c new file mode 100644 index 0000000000000000000000000000000000000000..69787e8ab96b40fcf638acd4e270247c1d7df210 --- /dev/null +++ b/dict_use.c @@ -0,0 +1,41 @@ +/* Compile with: + mkdir -p hash + cp dict_use.c dict.h dict.c keyval.c keyval.h dict_test.c hash + cp dict.automake hash/Makefile.am + cd hash + + touch NEWS README AUTHORS ChangeLog #still cheating + + autoscan + sed -e 's/FULL-PACKAGE-NAME/hashdict/' \ + -e 's/VERSION/1/' \ + -e 's|BUG-REPORT-ADDRESS|/dev/null|' \ + -e '12i\ + AM_INIT_AUTOMAKE' \ + -e '13i\ + LT_INIT' \ + -e '14i\ + AC_CHECK_LIB([glib-2.0],[g_free])' \ + -e 's|PROG_CC|PROG_CC_C99|' \ + < configure.scan > configure.ac + + autoreconf -i > /dev/null + ./configure + make distcheck + make +*/ +#include +#include "dict.h" + +int main(){ + int zero = 0; + float one = 1.0; + char two[] = "two"; + dictionary *d = dictionary_new(); + dictionary_add(d, "an int", &zero); + dictionary_add(d, "a float", &one); + dictionary_add(d, "a string", &two); + printf("The integer I recorded was: %i\n", *(int*)dictionary_find(d, "an int")); + printf("The string was: %s\n", (char*)dictionary_find(d, "a string")); + dictionary_free(d); +} diff --git a/dynamic.c b/dynamic.c new file mode 100644 index 0000000000000000000000000000000000000000..10cad7b20e74e1fabf0a855c55de2e479f27ae62 --- /dev/null +++ b/dynamic.c @@ -0,0 +1,48 @@ +/* Compile with: +LDLIBS="-lm -ldl -lreadline" CFLAGS="-g -Wall -std=gnu11 -O3" make dynamic +*/ +#define _GNU_SOURCE //cause stdio.h to include asprintf +#include +#include +#include +#include + +void get_a_function(){ + FILE *f = fopen("fn.c", "w"); + fprintf(f, "#include \n" + "double fn(double in){\n"); + char *a_line = NULL; + char *header = ">>double fn(double in){\n>> "; + do { + free(a_line); + a_line = readline(header); + fprintf(f, "%s\n", a_line); + header = ">> "; + } while (strcmp(a_line, "}")); + fclose(f); +} + +void compile_and_run(){ + char *run_me; + asprintf(&run_me, "c99 -fPIC -shared fn.c -o fn.so"); + if (system(run_me)!=0){ + printf("Compilation error."); + return; + } + + void *handle = dlopen("fn.so", RTLD_LAZY); + if (!handle) printf("Failed to load fn.so: %s\n", dlerror()); + + typedef double (*fn_type)(double); + fn_type f = dlsym(handle, "fn"); + printf("f(1) = %g\n", f(1)); + printf("f(2) = %g\n", f(2)); + printf("f(10) = %g\n", f(10)); +} + +int main(){ + printf("I am about to run a function. But first, you have to write it for me.\n" + "Enter the function body. Conclude with a '}' alone on a line.\n\n"); + get_a_function(); + compile_and_run(); +} diff --git a/erf.c b/erf.c new file mode 100644 index 0000000000000000000000000000000000000000..dcd59e566f06a2a0bab28f03e48f5d325ce0f4a7 --- /dev/null +++ b/erf.c @@ -0,0 +1,10 @@ +/* Compile with: +make erf LDLIBS="-lm" CFLAGS="-g -Wall -std=gnu11 -O3" +*/ +#include //erf, sqrt +#include //printf + +int main(){ + printf("The integral of a Normal(0, 1) distribution " + "between -1.96 and 1.96 is: %g\n", erf(1.96*sqrt(1/2.))); +} diff --git a/errortuple.c b/errortuple.c new file mode 100644 index 0000000000000000000000000000000000000000..eef409b7bd21afbe6da964d0157097bb990ce3c0 --- /dev/null +++ b/errortuple.c @@ -0,0 +1,45 @@ +/* Compile with: +make errortuple CFLAGS="-g -Wall -std=gnu11 -O3" +*/ +#include +#include //NaN, pow + +#define make_err_s(intype, shortname) \ + typedef struct { \ + intype value; \ + char const *error; \ + } shortname##_err_s; + +make_err_s(double, double) +make_err_s(int, int) +make_err_s(char *, string) + +double_err_s free_fall_energy(double time, double mass){ + double_err_s out = {}; //initialize to all zeros. + out.error = time < 0 ? "negative time" + : mass < 0 ? "negative mass" + : isnan(time) ? "NaN time" + : isnan(mass) ? "NaN mass" + : NULL; + if (out.error) return out; + + double velocity = 9.8*time; + out.value = mass*pow(velocity,2)/2.; + return out; +} + +#define Check_err(checkme, return_val) \ + if (checkme.error) {fprintf(stderr, "error: %s\n", checkme.error); return return_val;} + +int main(){ + double notime=0, fraction=0; + double_err_s energy = free_fall_energy(1, 1); + Check_err(energy, 1); + printf("Energy after one second: %g Joules\n", energy.value); + energy = free_fall_energy(2, 1); + Check_err(energy, 1); + printf("Energy after two seconds: %g Joules\n", energy.value); + energy = free_fall_energy(notime/fraction, 1); + Check_err(energy, 1); + printf("Energy after 0/0 seconds: %g Joules\n", energy.value); +} diff --git a/fibo.c b/fibo.c new file mode 100644 index 0000000000000000000000000000000000000000..adc8bf9e062cb3d8a2670363a0174d8495456286 --- /dev/null +++ b/fibo.c @@ -0,0 +1,18 @@ +/* Compile with: +make fibo CFLAGS="-g -Wall -std=gnu11 -O3" +*/ +#include + +long long int fibonacci(){ + static long long int first = 0; + static long long int second = 1; + long long int out = first+second; + first=second; + second=out; + return out; +} + +int main(){ + for (int i=0; i< 50; i++) + printf("%lli\n", fibonacci()); +} diff --git a/find.moby b/find.moby new file mode 100644 index 0000000000000000000000000000000000000000..faf7a3f27e098bebeff36f16236f3f45c0fb2bd4 --- /dev/null +++ b/find.moby @@ -0,0 +1,6 @@ +if [ ! -e moby ] ; then + curl -A "Mozilla/4.0" http://www.gutenberg.org/cache/epub/2701/pg2701.txt \ + | sed -e '1,/START OF THIS PROJECT GUTENBERG/d' \ + | sed -e '/End of Project Gutenberg/,$d' \ + > moby +fi diff --git a/floatfail.c b/floatfail.c new file mode 100644 index 0000000000000000000000000000000000000000..c39341ae4fa01033a4bbe840b94cc4a9f3004cd6 --- /dev/null +++ b/floatfail.c @@ -0,0 +1,10 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make floatfail +*/ +#include + +int main(){ + printf("%f\n", (float)333334126.98); + printf("%f\n", (float)333334125.31); +} diff --git a/fstr.c b/fstr.c new file mode 100644 index 0000000000000000000000000000000000000000..780983616fe1f6a5009b041cf32bd18a230ea8b0 --- /dev/null +++ b/fstr.c @@ -0,0 +1,68 @@ +/* See compilation notes in cetology.c*/ +#include "fstr.h" +#include "string_utilities.h" + +fstr_s *fstr_new(char const *filename){ + fstr_s *out = malloc(sizeof(fstr_s)); + *out = (fstr_s){.start=0, .refs=malloc(sizeof(int))}; + out->data = string_from_file(filename); + out->end = out->data ? strlen(out->data): 0; + *out->refs = 1; + return out; +} + +fstr_s *fstr_copy(fstr_s const *in, size_t start, size_t len){ + fstr_s *out = malloc(sizeof(fstr_s)); + *out=*in; + out->start += start; + if (in->end > out->start + len) + out->end = out->start + len; + (*out->refs)++; + return out; +} + +void fstr_free(fstr_s *in){ + (*in->refs)--; + if (!*in->refs) { + free(in->data); + free(in->refs); + } + free(in); +} + +fstr_list fstr_split (fstr_s const *in, gchar const *start_pattern){ + if (!in->data) return (fstr_list){ }; + fstr_s **out=malloc(sizeof(fstr_s*)); + int outlen = 1; + out[0] = fstr_copy(in, 0, in->end); + GRegex *start_regex = g_regex_new (start_pattern, 0, 0, NULL); + gint mstart=0, mend=0; + fstr_s *remaining = fstr_copy(in, 0, in->end); + do { + GMatchInfo *start_info; + g_regex_match(start_regex, &remaining->data[remaining->start], + 0, &start_info); + g_match_info_fetch_pos(start_info, 0, &mstart, &mend); + g_match_info_free(start_info); + if (mend > 0 && mend < remaining->end - remaining->start){ + out = realloc(out, ++outlen * sizeof(fstr_s*)); + out[outlen-1] = fstr_copy(remaining, mend, remaining->end-mend); + out[outlen-2]->end = remaining->start + mstart; + remaining->start += mend; + } else break; + } while (1); + fstr_free(remaining); + g_regex_unref(start_regex); + return (fstr_list){.strings=out, .count=outlen}; +} + +void fstr_list_free(fstr_list in){ + for (int i=0; i< in.count; i++){ + fstr_free(in.strings[i]); + } + free(in.strings); +} + +void fstr_show(fstr_s const *fstr){ + printf("%.*s", (int)fstr->end-fstr->start, &fstr->data[fstr->start]); +} diff --git a/fstr.h b/fstr.h new file mode 100644 index 0000000000000000000000000000000000000000..ddca7199c99960fbc28836c33bcb130f8679322e --- /dev/null +++ b/fstr.h @@ -0,0 +1,23 @@ +/* See compilation notes in cetology.c*/ +#include +#include +#include + +typedef struct { + char *data; + size_t start, end; + int* refs; +} fstr_s; + +fstr_s *fstr_new(char const *filename); +fstr_s *fstr_copy(fstr_s const *in, size_t start, size_t len); +void fstr_show(fstr_s const *fstr); +void fstr_free(fstr_s *in); + +typedef struct { + fstr_s **strings; + int count; +} fstr_list; + +fstr_list fstr_split (fstr_s const *in, gchar const *start_pattern); +void fstr_list_free(fstr_list in); diff --git a/gcov.sh b/gcov.sh new file mode 100644 index 0000000000000000000000000000000000000000..6786f57ce6c7a759007e13072bb81d2d302a9e72 --- /dev/null +++ b/gcov.sh @@ -0,0 +1,14 @@ +cat > makefile << '------' +P=dict_test +objects = keyval.o dict.o +CFLAGS = `pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -fprofile-arcs -ftest-coverage +LDLIBS = `pkg-config --libs glib-2.0` +CC=gcc + +$(P):$(objects) +------ + +make +./dict_test +for i in *gcda; do gcov $i; done; +grep -C3 '#####' *.c.gcov diff --git a/gdb_showlist b/gdb_showlist new file mode 100644 index 0000000000000000000000000000000000000000..d1464ed61922974bed86c2cca5e0ccc6365da9ff --- /dev/null +++ b/gdb_showlist @@ -0,0 +1,46 @@ +define phead + set $ptr = $arg1 + plistdata $arg0 +end +document phead +Print the first element of a list. E.g., given the declaration + Glist *datalist; + g_list_add(datalist, "Hello"); +view the list with something like +gdb> phead char datalist +gdb> pnext char +gdb> pnext char +This macro defines $ptr as the current pointed-to list struct, +and $pdata as the data in that list element. +end + +define pnext + set $ptr = $ptr->next + plistdata $arg0 +end +document pnext +You need to call phead first; that will set $ptr. +This macro will step forward in the list, then show the value at +that next element. Give the type of the list data as the only argument. + +This macro defines $ptr as the current pointed-to list struct, and +$pdata as the data in that list element. +end + +define plistdata + if $ptr + set $pdata = $ptr->data + else + set $pdata= 0 + end + if $pdata + p ($arg0*)$pdata + else + + p "NULL" + end +end +document plistdata +This is intended to be used by phead and pnext, q.v. It sets $pdata and prints its value. +end diff --git a/getenv.c b/getenv.c new file mode 100644 index 0000000000000000000000000000000000000000..3c1c8f9ef8bc470a3b580f74edca29e5966e3ddd --- /dev/null +++ b/getenv.c @@ -0,0 +1,22 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make getenv + +#Sample usage +reps=10 msg="Ha" ./getenv +msg="Ha" ./getenv +reps=20 msg=" " ./getenv +*/ +#include //getenv, atoi +#include //printf + +int main(){ + char *repstext = getenv("reps"); + int reps = repstext ? atoi(repstext) : 10; + + char *msg = getenv("msg"); + if (!msg) msg = "Hello."; + + for (int i=0; i< reps; i++) + printf("%s\n", msg); +} diff --git a/getstrings.c b/getstrings.c new file mode 100644 index 0000000000000000000000000000000000000000..84efc3135cef935dd746b252395a576e6fe40386 --- /dev/null +++ b/getstrings.c @@ -0,0 +1,18 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make getstrings +*/ +#define _GNU_SOURCE //cause stdio.h to include asprintf +#include +#include //free + +void get_strings(char const *in){ + char *cmd; + asprintf(&cmd, "strings %s", in); + if (system(cmd)) fprintf(stderr, "something went wrong running %s.\n", cmd); + free(cmd); +} + +int main(int argc, char **argv){ + get_strings(argv[0]); +} diff --git a/glist.c b/glist.c new file mode 100644 index 0000000000000000000000000000000000000000..58e316c8e1284e4e66f4931bcf42a19b9799eda0 --- /dev/null +++ b/glist.c @@ -0,0 +1,18 @@ +/* Compile with: +export CFLAGS="`pkg-config --cflags glib-2.0` -g -Wall -std=gnu11 -O3" +export LDLIBS="`pkg-config --libs glib-2.0`" +make glist +*/ +#include +#include + +GList *list; + +int main(){ + list = g_list_append(list, "a"); + list = g_list_append(list, "b"); + list = g_list_append(list, "c"); + + for ( ; list!= NULL; list=list->next) + printf("%s\n", (char*)list->data); +} diff --git a/groupabm.w b/groupabm.w new file mode 100644 index 0000000000000000000000000000000000000000..14d690373f50b81337636fbca4a92672e1ceb965 --- /dev/null +++ b/groupabm.w @@ -0,0 +1,141 @@ +@ +/* Suggested makefile: +---------- +#GNU make knows how to run ctangle groupabm.w to generate groupabm.c. +#If you have TeX installed, also try "make groupabm.tex; pdftex groupabm.tex" . +P = groupabm +objects = groups.o +CFLAGS=`pkg-config --cflags glib-2.0 apophenia` -std=gnu11 -g -Wall -O3 +LDLIBS=`pkg-config --libs glib-2.0 apophenia` + +$(P): $(objects) +---------- +*/ + +@* Initializations. + +@ This is the part of the agent-based model with the handlers for the +|people| structures and the procedure itself. + +At this point all interface with the groups happens via the +new/join/exit/print functions from |groups.cweb.c|. Thus, there is zero +memory management code in this file--the reference counting guarantees us +that when the last member exits a group, the group will be freed. + +@c +#include "groups.h" + +int pop=2000, + periods=200, + dimension=2; + +@ In |main|, we'll initialize a few constants that we can't have as static +variables because they require math. + +@= + double new_group_odds = 1./pop, + mass_benefit = .7/pop; + gsl_rng *r = apop_rng_alloc(1234); + +@ The people in this simulation are pretty boring: they do not die, and do +not move. So the struct that represents them is simple, with just |position| +and a pointer to the group of which the agent is currently a member. + +@c +typedef struct { + gsl_vector *position; + group_s *group; +} person_s; + +@ The setup routine is also boring, and consists of allocating a uniform +random vector in two dimensions. + +@c +person_s person_setup(gsl_rng *r){ + gsl_vector *posn = gsl_vector_alloc(dimension); + for (int i=0; i< dimension; i++) + gsl_vector_set(posn, i, 2*gsl_rng_uniform(r)-1); + return (person_s){.position=posn}; +} + +@* Group membersip. + +@ At the outset of this function, the person leaves its group. +Then, the decision is only whether to form a new group or join an existing one. + +@c +void check_membership(person_s *p, gsl_rng *r, + double mass_benefit, double new_group_odds){ + group_exit(p->group, p->position); + p->group = (gsl_rng_uniform(r) < new_group_odds) + ? @
+ : @; +} + +@ +@= +group_new(p->position) + +@ +@= +group_join(group_closest(p->position, mass_benefit), p->position) + +@* Simulation startup. + +@ The initialization of the population. Using CWEB's macros, it is at this point +self-documenting. + +@c +void init(person_s *people, int pop, gsl_rng *r){ + @ + @ + @ +} + +@ +@= + for (int i=0; i< pop; i++) + people[i] = person_setup(r); + +@ The first ten people in our list form new groups, but because everybody's +position is random, this is assigning the ten groups at random. + +@= + for (int i=0; i< 10; i++) + people[i].group = group_new(people[i].position); + +@ +@= + for (int i=10; i< pop; i++) + people[i].group = group_join(people[i%10].group, people[i].position); + +@* Plotting. + +@ This is the header for Gnuplot. I arrived at it by manually playing +around with Gnuplot, then writing down my final picks for settings here. + +@= +printf("unset key;set xrange [-1:1]\nset yrange [-1:1]\n"); + +@ Gnuplot animation simply consists of sending a sequence of plot statements. +@= +print_groups(); + +@* |main|. + +@ The |main| routine consists of a few setup steps, and a simple loop: +calculate a new state, then plot it. + +@c +int main(){ + @ + person_s people[pop]; + init(people, pop, r); + + @ + for (int t=0; t< periods; t++){ + for (int i=0; i< pop; i++) + check_membership(&people[i], r, mass_benefit, new_group_odds); + @ + } +} diff --git a/groups.h b/groups.h new file mode 100644 index 0000000000000000000000000000000000000000..43fe3e48efbf1684b653d1941c1303598a707aaf --- /dev/null +++ b/groups.h @@ -0,0 +1,14 @@ +/* See compilation notes in groupabm.w*/ +#include +#include + +typedef struct { + gsl_vector *position; + int id, size; +} group_s; + +group_s* group_new(gsl_vector *position); +group_s* group_join(group_s *joinme, gsl_vector *position); +void group_exit(group_s *leaveme, gsl_vector *position); +group_s* group_closest(gsl_vector *position, double mb); +void print_groups(); diff --git a/groups.w b/groups.w new file mode 100644 index 0000000000000000000000000000000000000000..47d18057a041e5886a584e4beed83c6bd65bf8b8 --- /dev/null +++ b/groups.w @@ -0,0 +1,112 @@ +@ +/* See compilation notes in groupabm.w*/ + +@ Here in the introductory material, we include the header and specify +the global list of groups that the program makes use of. We'll need +new/copy/free functions for each group. + +@c +#include "groups.h" + +GList *group_list; +@ +@ +@ + +@ The new group method is boilerplate: we |malloc| some space, +fill the struct using designated initializers, and append the newly-formed +group to the list. + +@= +group_s *group_new(gsl_vector *position){ + static int id=0; + group_s *out = malloc(sizeof(group_s)); + *out = (group_s) {.position=apop_vector_copy(position), .id=id++, .size=1}; + group_list = g_list_append(group_list, out); + return out; +} + +@ When an agent joins a group, the group is `copied' to the agent, but +there isn't any memory being copied: the group is simply modified to +accommodate the new person. We have to increment the reference count, which +is easy enough, and then modify the mean position. If the mean position +without the $n$th person is $P_{n-1}$, and the $n$th person is at position +$p$, then the new mean position with the person, $P_n$ is the weighted sum. + +$$P_n = \left( (n-1)P_{n-1}/n \right) + p/n.$$ + +We calculate that for each dimension. + +@= +group_s *group_join(group_s *joinme, gsl_vector *position){ + int n = ++joinme->size; //increment the reference count + for (int i=0; i< joinme->position->size; i++){ + joinme->position->data[i] *= (n-1.)/n; + joinme->position->data[i] += position->data[i]/n; + } + return joinme; +} + +@ The `free` function really only frees the group when the reference count +is zero. When it isn't, then we need to run the data-augmenting formula +for the mean in reverse to remove a person. + +@= +void group_exit(group_s *leaveme, gsl_vector *position){ + int n = leaveme->size--; //lower the reference count + for (int i=0; i< leaveme->position->size; i++){ + leaveme->position->data[i] -= position->data[i]/n; + leaveme->position->data[i] *= n/(n-1.); + } + if (leaveme->size == 0){ //garbage collect? + gsl_vector_free(leaveme->position); + group_list= g_list_remove(group_list, leaveme); + free(leaveme); + } +} + +@ I played around a lot with different rules for how exactly people +evaluate the distance to the groups. In the end, I wound up using the $L_3$ +norm. The standard distance is the $L_2$ norm, aka Euclidian distance, +meaning that the distance between $(x_1, y_1)$ and $(x_2, y_2)$ is +$\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}$. This is $L_3$, +$\sqrt[3]{(x_1-x_2)^3+(y_1-y_2)^3}$. +This and the call to |apop_copy| above are the only calls to the Apophenia +library; you could write around them if you don't have that library on hand. + +@= +apop_vector_distance(g->position, position, .metric='L', .norm=3) + +@ By `closest', I mean the group that provides the greatest benefit, +by having the smallest distance minus weighted size. Given the utility +function represented by the |dist| line, this is just a simple |for| +loop to find the smallest distance. + +@c +group_s *group_closest(gsl_vector *position, double mass_benefit){ + group_s *fave=NULL; + double smallest_dist=GSL_POSINF; + for (GList *gl=group_list; gl!= NULL; gl = gl->next){ + group_s *g = gl->data; + double dist= @ - mass_benefit*g->size; + if(dist < smallest_dist){ + smallest_dist = dist; + fave = g; + } + } + return fave; +} + +@ Gnuplot is automation-friendly. Here we get an animated simulation with +four lines of plotting code. The header |plot '-'| tells the system to plot +the data to follow, then we print the $(X, Y)$ positions, one to a line. The +final |e| indicates the end of the data set. The main program will set some +initial Gnuplot settings. + +@c +void print_groups(){ + printf("plot '-' with points pointtype 6\n"); + for (GList *gl=group_list; gl!= NULL; gl = gl->next) + apop_vector_print(((group_s*)gl->data)->position); + printf("e\n"); +} diff --git a/gsl_distance.c b/gsl_distance.c new file mode 100644 index 0000000000000000000000000000000000000000..4e994aca4afad76c14e6dba781ae9061ecb4657c --- /dev/null +++ b/gsl_distance.c @@ -0,0 +1,33 @@ +/* Compile with: +export LDLIBS="`pkg-config --libs apophenia`" +export CFLAGS="`pkg-config --cflags apophenia` -g -Wall -O3" +export CC=c99 +make gsl_distance +*/ +#include + +double one_dist(gsl_vector *v1, void *v2){ + return apop_vector_distance(v1, v2); +} + +long double distance(apop_data *data, apop_model *model){ + gsl_vector *target = model->parameters->vector; + return -apop_map_sum(data, .fn_vp=one_dist, .param=target, .part='r'); +} + +apop_model *min_distance= &(apop_model){ + .name="Minimum distance to a set of input points.", .p=distance, .vsize=-1}; + +int main(){ + apop_data *locations = apop_data_falloc((5, 2), + 1.1, 2.2, + 4.8, 7.4, + 2.9, 8.6, + -1.3, 3.7, + 2.9, 1.1); + Apop_model_add_group(min_distance, apop_mle, .method= APOP_SIMPLEX_NM, + .tolerance=1e-5); + Apop_model_add_group(min_distance, apop_parts_wanted); + apop_model *est=apop_estimate(locations, min_distance); + apop_model_show(est); +} diff --git a/gsl_erf.c b/gsl_erf.c new file mode 100644 index 0000000000000000000000000000000000000000..88b09605f539c6917aa30783b7ad5a08ce390e95 --- /dev/null +++ b/gsl_erf.c @@ -0,0 +1,12 @@ +/* Compile with: +export LDLIBS="`pkg-config --libs gsl`" +export CFLAGS="`pkg-config --cflags gsl` -g -Wall -std=gnu11 -O3" +make gsl_erf +*/ +#include +#include + +int main(){ + double bottom_tail = gsl_cdf_gaussian_P(-1.96, 1); + printf("Area between [-1.96, 1.96]: %g\n", 1-2*bottom_tail); +} diff --git a/ideal.c b/ideal.c new file mode 100644 index 0000000000000000000000000000000000000000..8027457395e9a32ea4da99c7ffd432027462b671 --- /dev/null +++ b/ideal.c @@ -0,0 +1,30 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make ideal +*/ +#include + +typedef struct { + double pressure, moles, temp; +} ideal_struct; + +/** Find the volume (in cubic meters) via the ideal gas law: V =nRT/P +Inputs: +pressure in atmospheres (default 1) +moles of material (default 1) +temperature in Kelvins (default freezing = 273.15) + */ +#define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1, \ + .moles=1, .temp=273.15, __VA_ARGS__}) + +double ideal_pressure_base(ideal_struct in){ + return 8.314 * in.moles*in.temp/in.pressure; +} + +int main(){ + printf("volume given defaults: %g\n", ideal_pressure() ); + printf("volume given boiling temp: %g\n", ideal_pressure(.temp=373.15) ); + printf("volume given two moles: %g\n", ideal_pressure(.moles=2) ); + printf("volume given two boiling moles: %g\n", + ideal_pressure(.moles=2, .temp=373.15) ); +} diff --git a/ideal.h b/ideal.h new file mode 100644 index 0000000000000000000000000000000000000000..e6ee3ba64d60eb016ac7c2350df96e42130ba917 --- /dev/null +++ b/ideal.h @@ -0,0 +1,17 @@ +/* This is cut down from ideal.c, providing only that which is needed for + a header. The Python package will use this. */ + +typedef struct { + double pressure, moles, temp; +} ideal_struct; + +/** Find the volume (in cubic meters) via the ideal gas law: V =nRT/P +Inputs: +pressure in atmospheres (default 1) +moles of material (default 1) +temperature in Kelvins (default freezing = 273.15) + */ +#define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1, \ + .moles=1, .temp=273.15, __VA_ARGS__}) + +double ideal_pressure_base(ideal_struct in); diff --git a/iftest.sh b/iftest.sh new file mode 100644 index 0000000000000000000000000000000000000000..58d4df54793a85a973fd75557d825cf7d079de4e --- /dev/null +++ b/iftest.sh @@ -0,0 +1,7 @@ +if test ! -e a_test_file; then + echo test file had not existed + touch a_test_file +else + echo test file existed + rm a_test_file +fi diff --git a/iggy_pop_detector.c b/iggy_pop_detector.c new file mode 100644 index 0000000000000000000000000000000000000000..2e6e42b7aa8f917b39d47c088aab7662027afe0f --- /dev/null +++ b/iggy_pop_detector.c @@ -0,0 +1,16 @@ +/* Compile with: +export CFLAGS="-g -std=gnu11 -O3" #The usual, but without -Wall +make iggy_pop_detector #Still, this will throw a warning +*/ +#include +#include //strcasecmp (from POSIX) + +bool check_name(char const **in){ + return (!strcasecmp(in[0], "Iggy") && !strcasecmp(in[1], "Pop")) + ||(!strcasecmp(in[0], "James") && !strcasecmp(in[1], "Osterberg")); +} + +int main(int argc, char **argv){ + if (argc < 2) return 0; + return check_name(&argv[1]); +} diff --git a/intptr.c b/intptr.c new file mode 100644 index 0000000000000000000000000000000000000000..c272d66ffbbd63b285270ecefa3a05c6d22b3f72 --- /dev/null +++ b/intptr.c @@ -0,0 +1,11 @@ +/* Compile with: +make intptr CFLAGS="-g -Wall -std=gnu11" +*/ +#include +#include //intptr_t + +int main(){ + char *astring = "I am somwhere in memory."; + intptr_t location = (intptr_t)astring; + printf("%s\n", (char*)location); +} diff --git a/keyval.c b/keyval.c new file mode 100644 index 0000000000000000000000000000000000000000..77a052c94d4199b0f7cf5177a7922f08c066ee17 --- /dev/null +++ b/keyval.c @@ -0,0 +1,24 @@ +/* See compilation notes in dict_use.c*/ +#include //malloc +#include //strcasecmp (from POSIX) +#include "keyval.h" + +keyval *keyval_new(char *key, void *value){ + keyval *out = malloc(sizeof(keyval)); + *out = (keyval){.key = key, .value=value}; + return out; +} + +/** Copy a key/value pair. The new pair has pointers to + the values in the old pair, not copies of their data. */ +keyval *keyval_copy(keyval const *in){ + keyval *out = malloc(sizeof(keyval)); + *out = *in; + return out; +} + +void keyval_free(keyval *in){ free(in); } + +int keyval_matches(keyval const *in, char const *key){ + return !strcasecmp(in->key, key); +} diff --git a/keyval.h b/keyval.h new file mode 100644 index 0000000000000000000000000000000000000000..4c54a386f1927e53a431b5b05ba33dce4f2dcfb1 --- /dev/null +++ b/keyval.h @@ -0,0 +1,10 @@ +/* See compilation notes in dict_use.c*/ +typedef struct keyval{ + char *key; + void *value; +} keyval; + +keyval *keyval_new(char *key, void *value); +keyval *keyval_copy(keyval const *in); +void keyval_free(keyval *in); +int keyval_matches(keyval const *in, char const *key); diff --git a/linecount.sh b/linecount.sh new file mode 100644 index 0000000000000000000000000000000000000000..477fd8efaf79596dbefe3bcd0c2c3f2801879174 --- /dev/null +++ b/linecount.sh @@ -0,0 +1,19 @@ + # Count lines with a ;, ), or }, and let that count be named Lines. +Lines=`grep '[;)}]' *.c | wc -l` + + # Now count how many lines there are in a directory listing; + # name it Files. +Files=`ls *.c |wc -l` + +echo files=$Files and lines=$Lines + + # Arithmetic expansion is a double-paren. + # In bash, the remainder is truncated; more on this later. +echo lines/file = $(($Lines/$Files)) + + # Or, use those variables in a here script. + # By setting scale=3, answers are printed to 3 decimal places. +bc << --- +scale=3 +$Lines/$Files +--- diff --git a/macro_varargs.c b/macro_varargs.c new file mode 100644 index 0000000000000000000000000000000000000000..1411de443548c3af29e6d58346cd1db8e542db0a --- /dev/null +++ b/macro_varargs.c @@ -0,0 +1,22 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make macro_varargs +*/ +#define _GNU_SOURCE //cause stdio.h to include vasprintf +#include //printf, vasprintf +#include //system +#include + +#define System_w_printf(outval, ...) { \ + char *string_for_systemf; \ + asprintf(&string_for_systemf, __VA_ARGS__); \ + outval = system(string_for_systemf); \ + free(string_for_systemf); \ +} + +int main(int argc, char **argv){ + assert(argc == 2); + int out; + System_w_printf(out, "ls %s", argv[1]); + return out; +} diff --git a/make_bit b/make_bit new file mode 100644 index 0000000000000000000000000000000000000000..e58a8873d220fc9f3c53d5a80a88ad7ff71a7c9d --- /dev/null +++ b/make_bit @@ -0,0 +1,12 @@ + push: + @if [ "x$(MSG)" = 'x' ] ; then \ + echo "Usage: MSG='whatever.' make push"; fi + @test "x$(MSG)" != 'x' + git commit -a -m "$(MSG)" + git svn fetch + git svn rebase + git svn dcommit + + pull: + git svn fetch + git svn rebase diff --git a/memmove.c b/memmove.c new file mode 100644 index 0000000000000000000000000000000000000000..83c4dccb29da28090a65a7e59f4880ec803db8b6 --- /dev/null +++ b/memmove.c @@ -0,0 +1,18 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make memmove +*/ +#include +#include //memmove + +int main(){ + int abc[] = {0, 1, 2}; + int *copy1, copy2[3]; + + copy1 = abc; + memmove(copy2, abc, sizeof(int)*3); + + abc[0] = 3; + assert(copy1[0]==3); + assert(copy2[0]==0); +} diff --git a/mmap.c b/mmap.c new file mode 100644 index 0000000000000000000000000000000000000000..e30dd4e22944a2342165f1f9c1e798eb388c5f0f --- /dev/null +++ b/mmap.c @@ -0,0 +1,60 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make mmap +*/ +#include +#include //lseek, write, close +#include //exit +#include //open +#include +#include "stopif.h" + +#define Mapmalloc(number, type, filename, fd) \ + load_mmap((filename), &(fd), (number)*sizeof(type), 'y') +#define Mapload(number, type, filename, fd) \ + load_mmap((filename), &(fd), (number)*sizeof(type), 'n') +#define Mapfree(number, type, fd, pointer) \ + releasemmap((pointer), (number)*sizeof(type), (fd)) + +void *load_mmap(char const *filename, int *fd, size_t size, char make_room){ + *fd = open(filename, + make_room=='y' ? O_RDWR | O_CREAT | O_TRUNC : O_RDWR, + (mode_t)0600); + Stopif(*fd == -1, return NULL, "Error opening file"); + + if (make_room=='y'){ // Stretch the file size to the size of the (mmapped) array + int result = lseek(*fd, size-1, SEEK_SET); + Stopif(result == -1, close(*fd); return NULL, "Error calling lseek() to stretch the file"); + result = write(*fd, "", 1); + Stopif(result != 1, close(*fd); return NULL, "Error writing last byte of the file"); + } + + void *map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + Stopif(map == MAP_FAILED, return NULL, "Error mmapping the file"); + return map; +} + +int releasemmap(void *map, size_t size, int fd){ + Stopif(munmap(map, size) == -1, return -1, "Error un-mmapping the file"); + close(fd); + return 0; +} + +int main(int argc, char *argv[]) { + int fd; + long int N=1e5+6; + int *map = Mapmalloc(N, int, "mmapped.bin", fd); + + for (long int i = 0; i +#include //mutexes + +long int global_wc; + +typedef struct{ + int wc; + char *docname; +} wc_struct; + +void *wc(void *voidin){ + wc_struct *in = voidin; + char *doc = string_from_file(in->docname); + if (!doc) return NULL; + static GMutex count_lock; + + char *delimiters = " `~!@#$%^&*()_-+={[]}|\\;:\",<>./?\n\t"; + ok_array *words = ok_array_new(doc, delimiters); + if (!words) return NULL; + in->wc = words->length; + ok_array_free(words); + g_mutex_lock(&count_lock); + for (int i=0; i< in->wc; i++) + global_wc++; //a slow global_wc += in->wc; + g_mutex_unlock(&count_lock); + return NULL; +} + +int main(int argc, char **argv){ + argc--; + argv++; //step past the name of the program. + + pthread_t threads[argc]; + wc_struct s[argc]; + for (int i=0; i< argc; i++){ + s[i] = (wc_struct){.docname=argv[i]}; + pthread_create(&threads[i], NULL, wc, &s[i]); + } + + int values[argc]; + for (int i=0; i< argc; i++){ + pthread_join(threads[i], NULL); + values[i] = s[i].wc; + } + + for (int i=0; i< argc; i++) printf("%s:\t%i\n",argv[i], values[i]); + printf("The total: %li\n", global_wc); +} diff --git a/na.c b/na.c new file mode 100644 index 0000000000000000000000000000000000000000..d88fe18a0703a7216cfcc16fb825c209e7845d5f --- /dev/null +++ b/na.c @@ -0,0 +1,37 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make na +*/ +#include +#include //isnan + +double ref; + +double set_na(){ + if (!ref) { + ref=0/0.; + char *cr = (char *)(&ref); + cr[2]='a'; + } + return ref; +} + +int is_na(double in){ + if (!ref) return 0; //set_na was never called==>no NAs yet. + + char *cc = (char *)(&in); + char *cr = (char *)(&ref); + for (int i=0; i< sizeof(double); i++) + if (cc[i] != cr[i]) return 0; + return 1; +} + +int main(){ + double x = set_na(); + double y = x; + printf("Is x=set_na() NA? %i\n", is_na(x)); + printf("Is x=set_na() NAN? %i\n", isnan(x)); + printf("Is y=x NA? %i\n", is_na(y)); + printf("Is 0/0 NA? %i\n", is_na(0/0.)); + printf("Is 8 NA? %i\n", is_na(8)); +} diff --git a/nyt_feed.c b/nyt_feed.c new file mode 100644 index 0000000000000000000000000000000000000000..f5aa5f6cc294f567b56022548c15b01d23b34694 --- /dev/null +++ b/nyt_feed.c @@ -0,0 +1,126 @@ +/** \file + + A program to read in the NYT's headline feed and produce a simple + HTML page from the headlines. */ +#include +#include +#include +#include "stopif.h" + +/** \mainpage +The front page of the Grey Lady's web site is as gaudy as can be, including +several headlines and sections trying to get your attention, various formatting +schemes, and even photographs--in color. + +This program reads in the NYT Headlines RSS feed, and writes a simple list in +plain HTML. You can then click through to the headline that modestly piques +your attention. + +For notes on compilation, see the \ref compilation page. +*/ + +/** \page compilation Compiling the program + +Save the following code to \c makefile. + +Notice that cURL has a program, \c curl-config, that behaves like \c pkg-config, +but is cURL-specific. + +\code +CFLAGS =-g -Wall -O3 `curl-config --cflags` -I/usr/include/libxml2 +LDLIBS=`curl-config --libs ` -lxml2 +CC=c99 + +nyt_feed: +\endcode + +Having saved your makefile, use make nyt_feed to compile. + +Of course, you have to have the development packages for libcurl and libxml2 +installed for this to work. +*/ + +//These have in-line Doxygen documentation. The < points to the prior text +//being documented. +char *rss_url = "http://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml"; + /**< The URL for an NYT RSS. */ +char *rssfile = "nytimes_feeds.rss"; /**< A local file to write the RSS to.*/ +char *outfile = "now.html"; /**< The output file to open in your browser.*/ + +/** Print a list of headlines in HTML format to the outfile, which is overwritten. + +\param urls The list of urls. This should have been tested for non-NULLness +\param titles The list of titles, also pre-tested to be non-NULL. If the length + of the \c urls list or the \c titles list is \c NULL, this will crash. +*/ +void print_to_html(xmlXPathObjectPtr urls, xmlXPathObjectPtr titles){ + FILE *f = fopen(outfile, "w"); + for (int i=0; i< titles->nodesetval->nodeNr; i++) + fprintf(f, "%s
\n" + , xmlNodeGetContent(urls->nodesetval->nodeTab[i]) + , xmlNodeGetContent(titles->nodesetval->nodeTab[i])); + fclose(f); +} + +/** Parse an RSS feed on the hard drive. This will parse the XML, then find +all nodes matching the XPath for the title elements and all nodes matching +the XPath for the links. Then, it will write those to the outfile. + + \param infile The RSS file in. +*/ +int parse(char const *infile){ + const xmlChar *titlepath= (xmlChar*)"//item/title"; + const xmlChar *linkpath= (xmlChar*)"//item/link"; + + xmlDocPtr doc = xmlParseFile(infile); + Stopif(!doc, return -1, "Error: unable to parse file \"%s\"\n", infile); + + xmlXPathContextPtr context = xmlXPathNewContext(doc); + Stopif(!context, return -2, "Error: unable to create new XPath context\n"); + + xmlXPathObjectPtr titles = xmlXPathEvalExpression(titlepath, context); + xmlXPathObjectPtr urls = xmlXPathEvalExpression(linkpath, context); + Stopif(!titles || !urls, return -3, "either the Xpath '//item/title' " + "or '//item/link' failed."); + + print_to_html(urls, titles); + + xmlXPathFreeObject(titles); + xmlXPathFreeObject(urls); + xmlXPathFreeContext(context); + xmlFreeDoc(doc); + return 0; +} + +/** Use cURL's easy interface to download the current RSS feed. + +\param url The URL of the NY Times RSS feed. Any of the ones listed at + \url http://www.nytimes.com/services/xml/rss/nyt/ should work. + +\param outfile The headline file to write to your hard drive. First save +the RSS feed to this location, then overwrite it with the short list of links. + + \return 1==OK, 0==failure. + */ +int get_rss(char const *url, char const *outfile){ + FILE *feedfile = fopen(outfile, "w"); + if (!feedfile) return -1; + + CURL *curl = curl_easy_init(); + if(!curl) return -1; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, feedfile); + CURLcode res = curl_easy_perform(curl); + if (res) return -1; + + curl_easy_cleanup(curl); + fclose(feedfile); + return 0; +} + +int main(void) { + Stopif(get_rss(rss_url, rssfile), return 1, "failed to download %s to %s.\n", + rss_url, rssfile); + parse(rssfile); + printf("Wrote headlines to %s. Have a look at it in your browser.\n", outfile); +} diff --git a/olden_varargs.c b/olden_varargs.c new file mode 100644 index 0000000000000000000000000000000000000000..e831e4140ca30a01d33806c8201c4e44797924ef --- /dev/null +++ b/olden_varargs.c @@ -0,0 +1,27 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make olden_varargs +*/ +#define _GNU_SOURCE //cause stdio.h to include vasprintf +#include //printf, vasprintf +#include //va_start, va_end +#include //system, free +#include + +int system_w_printf(char const *fmt, ...) __attribute__ ((format (printf,1,2))); + +int system_w_printf(char const *fmt, ...){ + char *cmd; + va_list argp; + va_start(argp, fmt); + vasprintf(&cmd, fmt, argp); + va_end(argp); + int out= system(cmd); + free(cmd); + return out; +} + +int main(int argc, char **argv){ + assert(argc == 2); + return system_w_printf("ls %s", argv[1]); +} diff --git a/papersize.c b/papersize.c new file mode 100644 index 0000000000000000000000000000000000000000..238f7ededaf13444f1d3c484807387508f050f1a --- /dev/null +++ b/papersize.c @@ -0,0 +1,24 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make papersize +*/ +#include +#include //strcasecmp (from POSIX) +#include //NaN + +typedef struct { + double width, height; +} size_s; + +size_s width_height(char *papertype){ + return + !strcasecmp(papertype, "A4") ? (size_s) {.width=210, .height=297} + : !strcasecmp(papertype, "Letter") ? (size_s) {.width=216, .height=279} + : !strcasecmp(papertype, "Legal") ? (size_s) {.width=216, .height=356} + : (size_s) {.width=NAN, .height=NAN}; +} + +int main(){ + size_s a4size = width_height("a4"); + printf("width= %g, height=%g\n", a4size.width, a4size.height); +} diff --git a/pointer_arithmetic1.c b/pointer_arithmetic1.c new file mode 100644 index 0000000000000000000000000000000000000000..5fb09f25e5142cd07f5d809c01ce6935e2a6c2b6 --- /dev/null +++ b/pointer_arithmetic1.c @@ -0,0 +1,12 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make pointer_arithmetic1 +*/ +#include + +int main(){ + char *list[] = {"first", "second", "third", NULL}; + for (char **p=list; *p != NULL; p++){ + printf("%s\n", p[0]); + } +} diff --git a/pointer_arithmetic2.c b/pointer_arithmetic2.c new file mode 100644 index 0000000000000000000000000000000000000000..37c20a6ed247da7cffbb4b098b3c40a36ed2f121 --- /dev/null +++ b/pointer_arithmetic2.c @@ -0,0 +1,13 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make pointer_arithmetic2 +*/ +#include +typedef char* string; + +int main(){ + string list[] = {"first", "second", "third", NULL}; + for (string *p=list; *p != NULL; p++){ + printf("%s\n", *p); + } +} diff --git a/preprocess.c b/preprocess.c new file mode 100644 index 0000000000000000000000000000000000000000..15f4b13b17ae4ce5e9c021832b251dadf2381f8b --- /dev/null +++ b/preprocess.c @@ -0,0 +1,30 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make preprocess +*/ +#include +#include //NAN + +#define Setup_list(name, ...) \ + double *name ## _list = (double []){__VA_ARGS__, NAN}; \ + int name ## _len = 0; \ + for (name ## _len =0; \ + !isnan(name ## _list[name ## _len]); \ + ) name ## _len ++; + + +int main(){ + Setup_list(items, 1, 2, 4, 8); + double sum=0; + for (double *ptr= items_list; !isnan(*ptr); ptr++) + sum += *ptr; + printf("total for items list: %g\n", sum); + + #define Length(in) in ## _len + + sum=0; + Setup_list(next_set, -1, 2.2, 4.8, 0.1); + for (int i=0; i < Length(next_set); i++) + sum += next_set_list[i]; + printf("total for next set list: %g\n", sum); +} diff --git a/process_dir.c b/process_dir.c new file mode 100644 index 0000000000000000000000000000000000000000..6d011567b1cee064c058c828cd0235702d66c068 --- /dev/null +++ b/process_dir.c @@ -0,0 +1,37 @@ +/* See compilation notes in show_tree.c or charct.c*/ +#include "process_dir.h" +#define _GNU_SOURCE //cause stdio.h to include asprintf +#include //asprintf +#include //struct dirent +#include //free + +int process_dir_r(filestruct level){ + if (!level.fullname){ + if (level.name) level.fullname=level.name; + else level.fullname="."; + } + int errct=0; + + DIR *current=opendir(level.fullname); + if (!current) return 1; + struct dirent *entry; + while((entry=readdir(current))) { + if (entry->d_name[0]=='.') continue; + filestruct next_level = level; + next_level.name = entry->d_name; + asprintf(&next_level.fullname, "%s/%s", level.fullname, entry->d_name); + + if (entry->d_type==DT_DIR){ + next_level.depth ++; + if (level.directory_action) level.directory_action(next_level); + errct+= process_dir_r(next_level); + } + else if (entry->d_type==DT_REG && level.file_action){ + level.file_action(next_level); + errct+= next_level.error; + } + free(next_level.fullname); + } + closedir(current); + return errct; +} diff --git a/process_dir.h b/process_dir.h new file mode 100644 index 0000000000000000000000000000000000000000..9e8176d8ebc799604ef7d25199fafacdc5b449d8 --- /dev/null +++ b/process_dir.h @@ -0,0 +1,48 @@ +/* See compilation notes in show_tree.c or charct.c*/ +struct filestruct; +typedef void (*level_fn)(struct filestruct path); + +typedef struct filestruct{ + char *name, *fullname; + level_fn directory_action, file_action; + int depth, error; + void *data; +} filestruct; + +/** I get the contents of the given directory, run \c file_action on each + file, and for each directory run \c dir_action and recurse into the directory. + Note that this makes the traversal `depth first'. + + Your functions will take in a \c filestruct, qv. Note that there is an \c error + element, which you can set to one to indicate an error. + + Inputs are designated initializers, and may include: + + \li \c .name The current file or directory name + \li \c .fullname The path of the current file or directory + \li \c .directory_action A function that takes in a \c filestruct. + I will call it with an appropriately-set \c filestruct + for every directory (just before the files in the directory + are processed). + \li \c .file_action Like the \c directory_action, but the function + I will call for every non-directory file. + \li \c .data A void pointer to be passed in to your functions. + + \return 0=OK, otherwise the count of directories that failed + errors thrown by your scripts. + Your functions may change the \c data element of the \c filestruct. + + Sample usage: +\code + void dirp(filestruct in){ printf("Directory: <%s>\n", in.name); } + void filep(filestruct in){ printf("File: %s\n", in.name); } + + //list files, but not directories, in current dir: + process_dir(.file_action=filep); + + //show everything in my home directory: + process_dir(.name="/home/b", .file_action=filep, .directory_action=dirp); +\endcode +*/ +#define process_dir(...) process_dir_r((filestruct){__VA_ARGS__}) + +int process_dir_r(filestruct level); diff --git a/pthreads.c b/pthreads.c new file mode 100644 index 0000000000000000000000000000000000000000..754b0dfe1074e487718fbeb1e48f43017f9bc4fa --- /dev/null +++ b/pthreads.c @@ -0,0 +1,47 @@ +/* Suggested makefile: +---------- +P=pthreads +objects=string_utilities.o +# To use Glib mutexes, some systems will require both glib-2.0 and gthread-2.0. +CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3 -pthread +LDLIBS=`pkg-config --libs glib-2.0` -pthread + +$(P): $(objects) +---------- +*/ +#include "stopif.h" +#include "string_utilities.h" +#include + +typedef struct{ + int wc; + char *docname; +} wc_struct; + +void *wc(void *voidin){ + wc_struct *in = voidin; + char *doc = string_from_file(in->docname); + if (!doc) return NULL; // in->wc remains zero. + char *delimiters = " `~!@#$%^&*()_-+={[]}|\\;:\",<>./?\n"; + ok_array *words = ok_array_new(doc, delimiters); + if (!words) return NULL; + in->wc = words->length; + ok_array_free(words); + return NULL; +} + +int main(int argc, char **argv){ + argc--; + argv++; + Stopif(!argc, return 0, "Please give some file names on the command line."); + pthread_t threads[argc]; + wc_struct s[argc]; + for (int i=0; i< argc; i++){ + s[i] = (wc_struct){.docname=argv[i]}; + pthread_create(&threads[i], NULL, wc, &s[i]); + } + + for (int i=0; i< argc; i++) pthread_join(threads[i], NULL); + + for (int i=0; i< argc; i++) printf("%s:\t%i\n",argv[i], s[i].wc); +} diff --git a/pthreads.make b/pthreads.make new file mode 100644 index 0000000000000000000000000000000000000000..3186eefc575dc8672281b778a034d96543a12224 --- /dev/null +++ b/pthreads.make @@ -0,0 +1,7 @@ +P=pthreads +objects=string_utilities.o +# To use Glib mutexes, some systems will require both glib-2.0 and gthread-2.0. +CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu99 -O3 -pthread +LDLIBS=`pkg-config --libs glib-2.0` -pthread + +$(P): $(objects) diff --git a/py/Makefile.am b/py/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..29fd4a0755d2e4a61f27c2b22bf482e051fd2506 --- /dev/null +++ b/py/Makefile.am @@ -0,0 +1,8 @@ +pyexec_LTLIBRARIES=libpvnrt.la +libpvnrt_la_SOURCES=ideal.c + +SUBDIRS=. + +if HAVE_PYTHON +SUBDIRS += py +endif diff --git a/py/Makefile.py.am b/py/Makefile.py.am new file mode 100644 index 0000000000000000000000000000000000000000..1af930b6fc365a726a26bebf42a2d198bc3a8572 --- /dev/null +++ b/py/Makefile.py.am @@ -0,0 +1,7 @@ +all-local: pvnrt + +pvnrt: + CFLAGS='@CFLAGS@' python setup.py build + +install-exec-hook: + python setup.py install diff --git a/py/build.python b/py/build.python new file mode 100644 index 0000000000000000000000000000000000000000..c4cd42e6a82ed95ea5277f98192c7004139e8877 --- /dev/null +++ b/py/build.python @@ -0,0 +1,23 @@ +# This is a script to set up the Python demo. As per the text, there is +# a main directory with the C code, and a subdirectory with the Python part. +# Once those components are set up, run autoreconf to generate the components, +# then the usual ./configure; make; sudo make install. + + +if [ -e autodemo ]; then sudo rm -r autodemo; fi +mkdir -p autodemo +cp ../ideal.h ../ideal.c Makefile.am configure.ac autodemo/ +cd autodemo +touch NEWS README AUTHORS ChangeLog #still cheating. +mkdir py +cp ../setup.py ../ideal.py.c py/ +cp ../Makefile.py.am py/Makefile.am + +autoreconf -iv + +echo ----------configure------------ +./configure +echo ----------make------------ +make +echo ----------install------------ +sudo make install diff --git a/py/configure.ac b/py/configure.ac new file mode 100644 index 0000000000000000000000000000000000000000..944eb800cd87d5a32d9aaf0764279f8cbca4cf58 --- /dev/null +++ b/py/configure.ac @@ -0,0 +1,18 @@ +AC_PREREQ([2.68]) +AC_INIT([pvnrt], [1], [/dev/null]) +AC_CONFIG_SRCDIR([ideal.c]) +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE +AC_PROG_CC_C99 +LT_INIT + +AM_PATH_PYTHON(,, [:]) +AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :]) + +if test "$PYTHON" != : ; then +AC_CONFIG_SUBDIRS([py]) +fi + +AC_CONFIG_FILES([Makefile py/Makefile]) +AC_OUTPUT diff --git a/py/ideal.py.c b/py/ideal.py.c new file mode 100644 index 0000000000000000000000000000000000000000..d8ea3f4fb294530c5eec888e4bff1e691993c285 --- /dev/null +++ b/py/ideal.py.c @@ -0,0 +1,20 @@ +/* See compilation notes in build.python*/ +#include +#include "../ideal.h" + +static PyObject *ideal_py(PyObject *self, PyObject *args){ + double intemp; + if (!PyArg_ParseTuple(args, "d", &intemp)) return NULL; + double out = ideal_pressure(.temp=intemp); + return Py_BuildValue("d", out); +} + +static PyMethodDef method_list[] = { + {"pressure_from_temp", ideal_py, METH_VARARGS, + "Get the pressure from the temperature of one mole of gunk"}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC initpvnrt(void) { + Py_InitModule("pvnrt", method_list); +} diff --git a/py/setup.py b/py/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..03ff8b14a928707db7013b5de72c6737b9c9e974 --- /dev/null +++ b/py/setup.py @@ -0,0 +1,14 @@ +from distutils.core import setup, Extension + +py_modules= ['pvnrt'] + +Emodule = Extension('pvnrt', + libraries=['pvnrt'], + library_dirs=['..'], + sources = ['ideal.py.c']) + +setup (name = 'pvnrt', + #provides='pvnrt', + version = '1.0', + description = 'pressure * volume = n * R * Temperature', + ext_modules = [Emodule]) diff --git a/sadstrings.c b/sadstrings.c new file mode 100644 index 0000000000000000000000000000000000000000..5ec0bc7045969a631074fe415b7e69cd11d3de66 --- /dev/null +++ b/sadstrings.c @@ -0,0 +1,19 @@ +/* Compile with: +make sadstrings CFLAGS="-g -Wall -std=gnu11 -O3" +*/ +#include +#include //strlen +#include //malloc, free, system + +void get_strings(char const *in){ + char *cmd; + int len = strlen("strings ") + strlen(in) + 1; + cmd = malloc(len); + snprintf(cmd, len, "strings %s", in); + if (system(cmd)) printf("something went wrong running %s.\n", cmd); + free(cmd); +} + +int main(int argc, char **argv){ + get_strings(argv[0]); +} diff --git a/safe_sum.c b/safe_sum.c new file mode 100644 index 0000000000000000000000000000000000000000..5edc3dee9e255420a67737b3c33ee2e3f12879d0 --- /dev/null +++ b/safe_sum.c @@ -0,0 +1,21 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make safe_sum +*/ +#include //NAN +#include + +double sum_array(double in[]){ + double out=0; + for (int i=0; !isnan(in[i]); i++) out += in[i]; + return out; +} + +#define sum(...) sum_array((double[]){__VA_ARGS__, NAN}) + +int main(){ + double two_and_two = sum(2, 2); + printf("2+2 = %g\n", two_and_two); + printf("(2+2)*3 = %g\n", sum(two_and_two, two_and_two, two_and_two)); + printf("sum(asst) = %g\n", sum(3.1415, two_and_two, 3, 8, 98.4)); +} diff --git a/sasprintf.c b/sasprintf.c new file mode 100644 index 0000000000000000000000000000000000000000..9893488c83a52775b7d94ce0a6818314d2b69032 --- /dev/null +++ b/sasprintf.c @@ -0,0 +1,23 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual +make sasprintf +*/ +#define _GNU_SOURCE //asks stdio.h to include asprintf +#include //printf +#include //free + +//Safer asprintf macro +#define Sasprintf(write_to, ...) { \ + char *tmp_string_for_extend = (write_to); \ + asprintf(&(write_to), __VA_ARGS__); \ + free(tmp_string_for_extend); \ +} + +//sample usage: +int main(){ + int i=3; + char *q = NULL; + Sasprintf(q, "select * from tab"); + Sasprintf(q, "%s where col%i is not null", q, i); + printf("%s\n", q); +} diff --git a/seamlessone.c b/seamlessone.c new file mode 100644 index 0000000000000000000000000000000000000000..b76cb263c74f2e196c76fbff60668e83f0c241ac --- /dev/null +++ b/seamlessone.c @@ -0,0 +1,23 @@ +/* Compile with: +make LDLIBS='-lm' CFLAGS="-g -Wall -std=gnu11 --ms-extensions" seamlessone +*/ +#include +#include + +typedef struct point { + double x, y; +} point; + +typedef struct { + struct point; + double z; +} threepoint; + +double threelength (threepoint p){ + return sqrt(p.x*p.x + p.y*p.y + p.z*p.z); +} + +int main(){ + threepoint p = {.x=3, .y=0, .z=4}; + printf("p is %g units from the origin\n", threelength(p)); +} diff --git a/seamlesstwo.c b/seamlesstwo.c new file mode 100644 index 0000000000000000000000000000000000000000..54849753db3ceeff61998f5f0595e75085d90421 --- /dev/null +++ b/seamlesstwo.c @@ -0,0 +1,32 @@ +/* Compile with: +make LDLIBS='-lm' CFLAGS="-g -Wall -std=gnu11 --ms-extensions" seamlesstwo +*/ +#include +#include + +typedef struct point { + double x, y; +} point; + +typedef struct { + union { + struct point; + point p2; + }; + double z; +} threepoint; + +double length (point p){ + return sqrt(p.x*p.x + p.y*p.y); +} + +double threelength (threepoint p){ + return sqrt(p.x*p.x + p.y*p.y + p.z*p.z); +} + +int main(){ + threepoint p = {.x=3, .y=0, .z=4}; + printf("p is %g units from the origin\n", threelength(p)); + double xylength = length(p.p2); + printf("Its projection onto the XY plane is %g units from the origin\n", xylength); +} diff --git a/show_tree.c b/show_tree.c new file mode 100644 index 0000000000000000000000000000000000000000..6090b2d0425a64e7937366e81a32f65508c5b276 --- /dev/null +++ b/show_tree.c @@ -0,0 +1,32 @@ +/* Suggested makefile: +---------- +P=show_tree +objects=process_dir.o process_dir.h +CFLAGS= -g -Wall -O3 +LDLIBS= +CC=c99 + +$(P): $(objects) +---------- +*/ + +#include +#include "process_dir.h" + +void print_dir(filestruct in){ + for (int i=0; i< in.depth-1; i++) printf(" "); + printf("├ %s\n", in.name); + for (int i=0; i< in.depth-1; i++) printf(" "); + printf("└───┐\n"); +} + +void print_file(filestruct in){ + for (int i=0; i< in.depth; i++) printf(" "); + printf("│ %s\n", in.name); +} + +int main(int argc, char **argv){ + char *start = (argc>1) ? argv[1] : "."; + printf("Tree for %s:\n", start ? start: "the current directory"); + process_dir(.name=start, .file_action=print_file, .directory_action=print_dir); +} diff --git a/simple_cplx.c b/simple_cplx.c new file mode 100644 index 0000000000000000000000000000000000000000..964b8ce1d497716ed98237103a369c727196aaca --- /dev/null +++ b/simple_cplx.c @@ -0,0 +1,35 @@ +/* Suggested makefile: +---------- +CFLAGS =-g -Wall -O3 `pkg-config --cflags gsl` +LDLIBS=`pkg-config --libs gsl` +CC=clang + +simple_cplx: complex.o +---------- +*/ +#include +#include "cplx.h" + +int main(){ + int complex a = 1+2I; + complex double b = 2+I; + gsl_complex c = gsl_cplx_from_c99(a); + + gsl_vector *v = gsl_vector_alloc(8); + for (int i=0; i< v->size; i++) gsl_vector_set(v, i, i/8.); + + complex double adotb = dot(a, b); + printf("(1+2i) dot (2+i): %g + %gi\n", creal(adotb), cimag(adotb)); + + printf("v dot 2:\n"); + double d = 2; + gsl_vector_complex_print(dot(v, d)); + + printf("v dot (1+2i):\n"); + gsl_vector_complex *vc = dot(v, a); + gsl_vector_complex_print(vc); + + printf("v dot (1+2i) again:\n"); + gsl_vector_complex_print(dot(v, c)); +} + diff --git a/sizesof.c b/sizesof.c new file mode 100644 index 0000000000000000000000000000000000000000..a70e07e34db9434ddb95a52fdb68f79c37180eab --- /dev/null +++ b/sizesof.c @@ -0,0 +1,13 @@ +/* Compile with: +make sizesof CFLAGS="-g -Wall -std=gnu11 -O3" +*/ +#include + +#define peval(cmd) printf(#cmd ": %g\n", cmd); + +int main(){ + double *plist = (double[]){1, 2, 3}; + double list[] = {1, 2, 3}; + peval(sizeof(plist)/(sizeof(double)+0.0)); + peval(sizeof(list)/(sizeof(double)+0.0)); +} diff --git a/stddev.c b/stddev.c new file mode 100644 index 0000000000000000000000000000000000000000..6cedef0c27e9469ec62f7022b1c085bf5166698d --- /dev/null +++ b/stddev.c @@ -0,0 +1,43 @@ +/* Compile with: +export LDLIBS="`pkg-config --libs gsl`" +export CFLAGS="`pkg-config --cflags gsl` -g -Wall -std=gnu11 -O3" +make stddev +*/ +#include +#include //size_t + +typedef struct meanvar {double mean, var;} meanvar; + +meanvar mean_and_var(const double *data){ + long double avg = 0, + avg2 = 0; + long double ratio; + size_t cnt= 0; + for(size_t i=0; !isnan(data[i]); i++){ + ratio = cnt/(cnt+1.0); + cnt ++; + avg *= ratio; + avg2 *= ratio; + avg += data[i]/(cnt +0.0); + avg2 += pow(data[i], 2)/(cnt +0.0); + } + return (meanvar){.mean = avg, + .var = avg2 - pow(avg, 2)}; //E[x^2] - E^2[x] +} + +int main(){ + double d[] = { 34124.75, 34124.48, + 34124.90, 34125.31, + 34125.05, 34124.98, NAN}; + + meanvar mv = mean_and_var(d); + printf("mean: %.10g var: %.10g\n", mv.mean, mv.var*6/5.); + + double d2[] = { 4.75, 4.48, + 4.90, 5.31, + 5.05, 4.98, NAN}; + + mv = mean_and_var(d2); + mv.var *= 6./5; + printf("mean: %.10g var: %.10g\n", mv.mean, mv.var); +} diff --git a/stopif.h b/stopif.h new file mode 100644 index 0000000000000000000000000000000000000000..d41adaa02c99f9c4f30c5f56ffdeca390aceabb2 --- /dev/null +++ b/stopif.h @@ -0,0 +1,19 @@ +#include +#include //abort + +/** Set this to \c 's' to stop the program on an error. + Otherwise, functions take error_action on failure.*/ +char error_mode; + +/** To where should I write errors? If this is \c NULL, write to \c stderr. */ +FILE *error_log; + +#define Stopif(assertion, error_action, ...) do { \ + if (assertion){ \ + fprintf(error_log ? error_log : stderr, __VA_ARGS__); \ + fprintf(error_log ? error_log : stderr, "\n"); \ + if (error_mode=='s') abort(); \ + else {error_action;} \ + } } while(0) + + diff --git a/string_utilities.c b/string_utilities.c new file mode 100644 index 0000000000000000000000000000000000000000..90cefb364dcfe1240a80b12053ef49554ebe2c79 --- /dev/null +++ b/string_utilities.c @@ -0,0 +1,56 @@ +#include +#include +#include "string_utilities.h" +#include +#include +#include //abort + +char *string_from_file(char const *filename){ + char *out; + GError *e=NULL; + GIOChannel *f = g_io_channel_new_file(filename, "r", &e); + if (!f) { + fprintf(stderr, "failed to open file '%s'.\n", filename); + return NULL; + } + if (g_io_channel_read_to_end(f, &out, NULL, &e) != G_IO_STATUS_NORMAL){ + fprintf(stderr, "found file '%s' but couldn't read it.\n", filename); + return NULL; + } + return out; +} + +ok_array *ok_array_new(char *instring, char const *delimiters){ + ok_array *out= malloc(sizeof(ok_array)); + *out = (ok_array){.base_string=instring}; + char *scratch = NULL; + char *txt = strtok_r(instring, delimiters, &scratch); + if (!txt) return NULL; + while (txt) { + out->elements = realloc(out->elements, sizeof(char*)*++(out->length)); + out->elements[out->length-1] = txt; + txt = strtok_r(NULL, delimiters, &scratch); + } + return out; +} + +/* Frees the original string, because strtok_r mangled it, so it + isn't useful for any other purpose. */ +void ok_array_free(ok_array *ok_in){ + if (ok_in == NULL) return; + free(ok_in->base_string); + free(ok_in->elements); + free(ok_in); +} + +#ifdef test_ok_array +int main (){ + char *delimiters = " `~!@#$%^&*()_-+={[]}|\\;:\",<>./?\n"; + ok_array *o = ok_array_new(strdup("Hello, reader. This is text."), delimiters); + assert(o->length==5); + assert(!strcmp(o->elements[1], "reader")); + assert(!strcmp(o->elements[4], "text")); + ok_array_free(o); + printf("OK.\n"); +} +#endif diff --git a/string_utilities.h b/string_utilities.h new file mode 100644 index 0000000000000000000000000000000000000000..f374713df78a0edcb4723284235d34ff9dad897b --- /dev/null +++ b/string_utilities.h @@ -0,0 +1,22 @@ +#include +#define _GNU_SOURCE //asks stdio.h to include asprintf +#include + +//Safe asprintf macro +#define Sasprintf(write_to, ...) { \ + char *tmp_string_for_extend = write_to; \ + asprintf(&(write_to), __VA_ARGS__); \ + free(tmp_string_for_extend); \ +} + +char *string_from_file(char const *filename); + +typedef struct ok_array { + char **elements; + char *base_string; + int length; +} ok_array; + +ok_array *ok_array_new(char *instring, char const *delimiters); + +void ok_array_free(ok_array *ok_in); diff --git a/strtod.c b/strtod.c new file mode 100644 index 0000000000000000000000000000000000000000..bae3585de53031d383751c0303cbee07176b18f5 --- /dev/null +++ b/strtod.c @@ -0,0 +1,12 @@ +#include "stopif.h" +#include //strtod +#include //pow + +int main(int argc, char **argv){ + Stopif (argc < 2, return 1, "Give me a number on the command line to square."); + char *end; + double in = strtod(argv[1], &end); + Stopif(*end, return 2, "I couldn't parse '%s' to a number. " + "I had trouble with '%s'.", argv[1], end); + printf("The square of %g is %g\n", argv[1], pow(in, 2)); +} diff --git a/sum_to_nan.c b/sum_to_nan.c new file mode 100644 index 0000000000000000000000000000000000000000..a5ab20a0ed98e69551b933737893c038bdcc8fb2 --- /dev/null +++ b/sum_to_nan.c @@ -0,0 +1,18 @@ +/* Compile with: +make sum_to_nan CFLAGS="-g -Wall -std=gnu11 -O3" +*/ +#include //NAN +#include + +double sum(double in[]){ + double out=0; + for (int i=0; !isnan(in[i]); i++) out += in[i]; + return out; +} + +int main(){ + double list[] = {1.1, 2.2, 3.3, NAN}; + printf("sum: %g\n", sum(list)); + + printf("sum: %g\n", sum((double[]){1.1, 2.2, 3.3, NAN})); +} diff --git a/times_table.c b/times_table.c new file mode 100644 index 0000000000000000000000000000000000000000..d50d6f915edee1510166899ec9769f93721005a5 --- /dev/null +++ b/times_table.c @@ -0,0 +1,28 @@ +#include //NAN +#include + +#define make_a_list(...) (double[]){__VA_ARGS__, NAN} + +#define matrix_cross(list1, list2) matrix_cross_base(make_a_list list1, make_a_list list2) + +void matrix_cross_base(double *list1, double *list2){ + int count1 = 0, count2 = 0; + while (!isnan(list1[count1])) count1++; + while (!isnan(list2[count2])) count2++; + if (!count1 || !count2) {printf("missing data."); return;} + + for (int i=0; i + +int main(){ + int neg = -2; + size_t zero = 0; + if (neg < zero) printf("Yes, -2 is less than 0.\n"); + else printf("No, -2 is not less than 0.\n"); +} diff --git a/unicode.c b/unicode.c new file mode 100644 index 0000000000000000000000000000000000000000..f47a5c2599b5d5e736738b87f1c9ed93f3d57df0 --- /dev/null +++ b/unicode.c @@ -0,0 +1,62 @@ +/* Suggested makefile: +---------- +P=unicode +objects=string_utilities.o +CFLAGS=`pkg-config --cflags glib-2.0` -g -Wall -std=gnu11 -O3 +LDLIBS=`pkg-config --libs glib-2.0` + +$(P): $(objects) +---------- +*/ +/* Here is some sample UTF-8, so you can try this out. + If this looks like a mess, your browser may have an easier time displaying it, or try + iconv -f utf-8 -t UTF-16 < unicode.c > unicode.c.16 + +京冀洪涝灾情启动四级响应 #Today's headline from Chinadaily.com. +España, cercada por los mercados, prohíbe las operaciones especulativas #Today's headline from elpais.es. +3.141592653589793238462643383279 #pi. + + */ +#include +#include //setlocale +#include "string_utilities.h" +#include "stopif.h" + +//Frees instring for you--we can't use it for anything else. +char *localstring_to_utf8(char *instring){ + GError *e=NULL; + setlocale(LC_ALL, ""); //get the OS's locale. + char *out = g_locale_to_utf8(instring, -1, NULL, NULL, &e); + free(instring); //done with the original + Stopif(!out, return NULL, "Trouble converting from your locale to UTF-8."); + Stopif(!g_utf8_validate(out, -1, NULL), free(out); return NULL, + "Trouble: I couldn't convert your file to a valid UTF-8 string."); + return out; +} + +int main(int argc, char **argv){ + Stopif(argc==1, return 1, "Please give a filename as an argument. " + "I will print useful info about it to uout.html."); + + char *ucs = localstring_to_utf8(string_from_file(argv[1])); + Stopif(!ucs, return 1, "Exiting."); + FILE *out = fopen("uout.html", "w"); + Stopif(!out, return 1, "Couldn't open uout.html for writing."); + fprintf(out, "\n"); + fprintf(out, "This document has %li characters.
", g_utf8_strlen(ucs, -1)); + fprintf(out, "Its Unicode encoding required %zu bytes.
", strlen(ucs)); + fprintf(out, "Here it is, with each space-delimited element on a line " + "(with commentary on the first character):
"); + ok_array *spaced = ok_array_new(ucs, " \n"); + for (int i=0; i< spaced->length; i++, (spaced->elements)++){ + fprintf(out, "%s", *spaced->elements); + gunichar c = g_utf8_get_char(*spaced->elements); + if (g_unichar_isalpha(c)) fprintf(out, " (a letter)"); + if (g_unichar_isdigit(c)) fprintf(out, " (a digit)"); + if (g_unichar_iswide(c)) fprintf(out, " (wide, CJK)"); + fprintf(out, "
"); + } + fclose(out); + printf("Info printed to uout.html. Have a look at it in your browser.\n"); +} diff --git a/unictr.c b/unictr.c new file mode 100644 index 0000000000000000000000000000000000000000..5621e54720c07d52aa8e9c500cd6bb23f3854592 --- /dev/null +++ b/unictr.c @@ -0,0 +1,39 @@ +/* See compilation notes in charct.c*/ +#include "string_utilities.h" +#include "process_dir.h" +#include "unictr.h" +#include +#include //calloc, malloc + +typedef struct { + int count; +} count_s; + +void hash_a_character(gunichar uc, GHashTable *hash){ + count_s *ct = g_hash_table_lookup(hash, &uc); + if (!ct){ + ct = calloc(1, sizeof(count_s)); + gunichar *newchar = malloc(sizeof(gunichar)); + *newchar = uc; + g_hash_table_insert(hash, newchar, ct); + } + ct->count++; +} + +void printone(void *key_in, void *val_in, void *ignored){ + gunichar const *key= key_in; + count_s const *val= val_in; + char utf8[7]; + utf8[g_unichar_to_utf8(*key, utf8)]='\0'; + printf("%s\t%i\n", utf8, val->count); +} + +static gboolean equal_chars(void const * a_in, void const * b_in){ + const gunichar *a= a_in; + const gunichar *b= b_in; + return (*a==*b); +} + +GHashTable *new_unicode_counting_hash(){ + return g_hash_table_new(g_str_hash, equal_chars); +} diff --git a/unictr.h b/unictr.h new file mode 100644 index 0000000000000000000000000000000000000000..772b701cbbf3660d3697c05d7b770a49bd16383a --- /dev/null +++ b/unictr.h @@ -0,0 +1,6 @@ +/* See compilation notes in charct.c*/ +#include + +void hash_a_character(gunichar uc, GHashTable *hash); +void printone(void *key_in, void *val_in, void *xx); +GHashTable *new_unicode_counting_hash(); diff --git a/varad.c b/varad.c new file mode 100644 index 0000000000000000000000000000000000000000..ae3c5301d04628e84f002d7689856ba20f0839c1 --- /dev/null +++ b/varad.c @@ -0,0 +1,16 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make varad +*/ +#include + +#define forloop(i, loopmax, ...) for(int i=0; i< loopmax; i++) \ + {__VA_ARGS__} + +int main(){ + int sum=0; + forloop(i, 10, + sum += i; + printf("sum to %i: %i\n", i, sum); + ) +} diff --git a/vectorize.c b/vectorize.c new file mode 100644 index 0000000000000000000000000000000000000000..f2cc94ba5a0f3361b8e7ddf6a2910f6a26aa82d9 --- /dev/null +++ b/vectorize.c @@ -0,0 +1,23 @@ +/* Compile with: +export CFLAGS="-g -Wall -std=gnu11 -O3" #the usual. +make vectorize +*/ +#include +#include //malloc, free + +#define Fn_apply(type, fn, ...) { \ + void *stopper_for_apply = (int[]){0}; \ + type **list_for_apply = (type*[]){__VA_ARGS__, stopper_for_apply}; \ + for (int i=0; list_for_apply[i] != stopper_for_apply; i++) \ + fn(list_for_apply[i]); \ +} + +#define Free_all(...) Fn_apply(void, free, __VA_ARGS__); + +int main(){ + double *x= malloc(10); + double *y= malloc(100); + double *z= malloc(1000); + + Free_all(x, y, z); +}