From 4b14221751d0cbed0c1ceecaa5e54c011be873c6 Mon Sep 17 00:00:00 2001 From: eddyem Date: Tue, 8 Dec 2015 16:16:00 +0300 Subject: [PATCH] modification of cmdlnopts --- 11a.c | 80 ++++ erosion-dilation/binmorph.c | 23 +- erosion-dilation/binmorph.h | 7 +- erosion-dilation/cclabling.h | 30 +- erosion-dilation/cclabling_1.h | 102 ++-- erosion-dilation/main.c | 145 ++---- getopt/cmdlnopts/Makefile | 22 + getopt/cmdlnopts/cmdlnopts.c | 264 +++++++++++ getopt/cmdlnopts/cmdlnopts.h | 61 +++ getopt/cmdlnopts/main.c | 107 +++++ getopt/cmdlnopts/parceargs.c | 434 ++++++++++++++++++ getopt/cmdlnopts/parceargs.h | 124 +++++ getopt/{ => cmdlnopts_deprecated}/cmdlnopts.c | 0 getopt/{ => cmdlnopts_deprecated}/cmdlnopts.h | 0 getopt/{ => cmdlnopts_deprecated}/parceargs.c | 0 getopt/{ => cmdlnopts_deprecated}/parceargs.h | 0 getopt/{ => getopt}/getopt.c | 0 getopt/{ => getopt}/getopt.h | 0 med.c | 245 ++++++++++ 19 files changed, 1465 insertions(+), 179 deletions(-) create mode 100644 11a.c create mode 100644 getopt/cmdlnopts/Makefile create mode 100644 getopt/cmdlnopts/cmdlnopts.c create mode 100644 getopt/cmdlnopts/cmdlnopts.h create mode 100644 getopt/cmdlnopts/main.c create mode 100644 getopt/cmdlnopts/parceargs.c create mode 100644 getopt/cmdlnopts/parceargs.h rename getopt/{ => cmdlnopts_deprecated}/cmdlnopts.c (100%) rename getopt/{ => cmdlnopts_deprecated}/cmdlnopts.h (100%) rename getopt/{ => cmdlnopts_deprecated}/parceargs.c (100%) rename getopt/{ => cmdlnopts_deprecated}/parceargs.h (100%) rename getopt/{ => getopt}/getopt.c (100%) rename getopt/{ => getopt}/getopt.h (100%) create mode 100644 med.c diff --git a/11a.c b/11a.c new file mode 100644 index 0000000..31aaa8e --- /dev/null +++ b/11a.c @@ -0,0 +1,80 @@ +#include +#include +#include + +#define NMEMB 10000000 + +/* + * Timings (in seconds): + * -Ox sort3a sort3c qsort + * 0 0.22787 0.24655 0.54751 + * 1 0.034301 0.120855 0.543839 + * 2 0.032332 0.102875 0.515567 + * 3 0.032472 0.102684 0.514301 + */ + +static inline void sort3a(int *d){ +#define min(x, y) (x b){d[x] = b; d[y] = a;}} + CMPSWAP(0, 1); + CMPSWAP(1, 2); + CMPSWAP(0, 1); +#undef CMPSWAP +} + +static int cmpints(const void *p1, const void *p2){ + return (*((int*)p1) - *((int*)p2)); +} + +double timediff(struct timespec *tstart, struct timespec *tend){ + return (((double)tend->tv_sec + 1.0e-9*tend->tv_nsec) - + ((double)tstart->tv_sec + 1.0e-9*tstart->tv_nsec)); +} + +int main(){ + double t1, t2, t3; + int *arra, *arrb, *arrc; + struct timespec tstart, tend; + int i, nmemb = 3*NMEMB; + // generate + i = nmemb * sizeof(int); + arra = malloc(i); + arrb = malloc(i); + arrc = malloc(i); + srand(time(NULL)); + for(i = 0; i < nmemb; i++){ + arra[i] = arrb[i] = arrc[i] = rand(); + } + clock_gettime(CLOCK_MONOTONIC, &tstart); + for(i = 0; i < nmemb ; i+=3){ + sort3a(&arra[i]); + } + clock_gettime(CLOCK_MONOTONIC, &tend); + t1 = timediff(&tstart, &tend); + clock_gettime(CLOCK_MONOTONIC, &tstart); + for(i = 0; i < nmemb ; i+=3){ + sort3c(&arrb[i]); + } + clock_gettime(CLOCK_MONOTONIC, &tend); + t2 = timediff(&tstart, &tend); + clock_gettime(CLOCK_MONOTONIC, &tstart); + for(i = 0; i < nmemb ; i+=3){ + qsort(&arrc[i], 3, sizeof(int), cmpints); + } + clock_gettime(CLOCK_MONOTONIC, &tend); + t3 = timediff(&tstart, &tend); + printf("%g, %g, %g; ", t1, t2, t3); +} + diff --git a/erosion-dilation/binmorph.c b/erosion-dilation/binmorph.c index eb6b8f3..5becec7 100644 --- a/erosion-dilation/binmorph.c +++ b/erosion-dilation/binmorph.c @@ -249,7 +249,7 @@ size_t *char2st(unsigned char *image, int W, int H, int W_0){ * @return allocated memory area with converted input image */ unsigned char *FC_filter(unsigned char *image, int W, int H){ - if(W < 2 || H < 2) errx(1, "4-connect: image size too small"); + if(W < 1 || H < 2) errx(1, "4-connect: image size too small"); unsigned char *ret = Malloc(W*H, 1); int y = 0, w = W-1, h = H-1; // top of image, y = 0 @@ -381,15 +381,6 @@ unsigned char *substim(unsigned char *im1, unsigned char *im2, int W, int H){ -/* - * <=================== CONNECTED COMPONENTS LABELING =================== - */ -/* -#undef DBG -#undef EBUG -#define DBG(...) -*/ - /** * label 4-connected components on image * (slow algorythm, but easy to parallel) @@ -406,6 +397,13 @@ CCbox *cclabel4(unsigned char *Img, int W, int H, int W_0, size_t *Nobj){ return ret; } +CCbox *cclabel4_1(unsigned char *Img, int W, int H, int W_0, size_t *Nobj){ + unsigned char *I = FC_filter(Img, W_0, H); + #include "cclabling.h" + FREE(I); + return ret; +} + // label 8-connected components, look cclabel4 CCbox *cclabel8(unsigned char *I, int W, int H, int W_0, size_t *Nobj){ //unsigned char *I = EC_filter(Img, W_0, H); @@ -423,6 +421,11 @@ CCbox *cclabel8_1(unsigned char *I, int W, int H, int W_0, size_t *Nobj){ return ret; } +/* + * <=================== CONNECTED COMPONENTS LABELING =================== + */ + + /* * <=================== template ===================> */ diff --git a/erosion-dilation/binmorph.h b/erosion-dilation/binmorph.h index 7761965..770b19d 100644 --- a/erosion-dilation/binmorph.h +++ b/erosion-dilation/binmorph.h @@ -27,9 +27,9 @@ #include #ifdef EBUG -#ifndef DBG - #define DBG(...) do{fprintf(stderr, __VA_ARGS__);}while(0) -#endif +#define DBG(...) do{fprintf(stderr, __VA_ARGS__);}while(0) +#else +#define DBG(...) #endif #define _U_ __attribute__((__unused__)) @@ -80,6 +80,7 @@ typedef struct { CCbox *cclabel4(unsigned char *I, int W, int H, int W_0, size_t *Nobj); CCbox *cclabel8(unsigned char *I, int W, int H, int W_0, size_t *Nobj); +CCbox *cclabel4_1(unsigned char *I, int W, int H, int W_0, size_t *Nobj); CCbox *cclabel8_1(unsigned char *I, int W, int H, int W_0, size_t *Nobj); #endif // __EROSION_DILATION_H__ diff --git a/erosion-dilation/cclabling.h b/erosion-dilation/cclabling.h index 744831b..7d10ab2 100644 --- a/erosion-dilation/cclabling.h +++ b/erosion-dilation/cclabling.h @@ -24,6 +24,7 @@ double t0 = dtime(); size_t N _U_ = 0, Ncur = 0; size_t *labels = char2st(I, W, H, W_0); int y; +/* #ifdef EBUG for(y = 0; y < H; y++){ size_t *ptr = &labels[y*W]; @@ -35,8 +36,9 @@ for(y = 0; y < H; y++){ } FREE(labels); return ret; #endif -printf("time for char2st: %gs\n", dtime()-t0); -t0 = dtime(); +*/ +//printf("time for char2st: %gs\n", dtime()-t0); +//t0 = dtime(); // Step 1: mark neighbours by strings size_t *ptr = labels; for(y = 0; y < H; y++){ @@ -50,8 +52,8 @@ t0 = dtime(); *ptr = Ncur; } } -printf("\n\ntime for step1: %gs (Ncur=%zd)\n", dtime()-t0, Ncur); -t0 = dtime(); +//printf("\n\ntime for step1: %gs (Ncur=%zd)\n", dtime()-t0, Ncur); +//t0 = dtime(); DBG("Initial mark\n"); #ifdef EBUG for(y = 0; y < H; y++){ @@ -72,11 +74,7 @@ for(y = 0; y < H; y++){ // now we should scan image again to rebuild enumeration // THIS PROCESS AVOID PARALLELISATION??? Ncur = 0; - size_t h = H-1 - #ifdef LABEL_8 - ,w = W-1; - #endif - ; + size_t h = H-1, w = W-1; inline void remark(size_t old, size_t *newv){ size_t new = *newv; if(assoc[old] == new){ @@ -153,6 +151,13 @@ for(y = 0; y < H; y++){ *ptr = 0; // erase this hermit! continue; } + #else + // no neighbour down & neighbour to the right -> hermit + if((y < h && ptr[W] == 0) && (x < w && ptr[1] == 0)){ + *ptr = 0; // erase this hermit! + DBG("hermit!\n"); + continue; + } #endif upmark = ++Ncur; } @@ -174,8 +179,8 @@ for(y = 0; y < H; y++){ remark(curval, &upmark); } } -printf("time for step 2: %gs, found %zd objects\n", dtime()-t0, Ncur); -t0 = dtime(); +//printf("time for step 2: %gs, found %zd objects\n", dtime()-t0, Ncur); +//t0 = dtime(); // Step 3: rename markers DBG("rename markers\n"); // first correct complex assotiations in assoc @@ -188,7 +193,7 @@ t0 = dtime(); *ptr = assoc[p]; } } -printf("time for step 3: %gs\n", dtime()-t0); +//printf("time for step 3: %gs\n", dtime()-t0); #ifdef EBUG printf("\n\n"); for(y = 0; y < H; y++){ @@ -202,3 +207,4 @@ for(y = 0; y < H; y++){ #endif FREE(assoc); FREE(labels); +printf("%6.4f\t%zd\n", dtime()-t0, Ncur); diff --git a/erosion-dilation/cclabling_1.h b/erosion-dilation/cclabling_1.h index e8a1003..7437fb8 100644 --- a/erosion-dilation/cclabling_1.h +++ b/erosion-dilation/cclabling_1.h @@ -23,58 +23,46 @@ double t0 = dtime(); CCbox *ret = NULL; size_t N = 0, // current label - Ntot = 0, // number of found objects Nmax = W*H/4; // max number of labels size_t *labels = char2st(I, W, H, W_0); - int w = W - 1; -printf("time for char2st: %gs\n", dtime()-t0); + int w = W - 1, h = H - 1; +//printf("time for char2st: %gs\n", dtime()-t0); int y; size_t *assoc = Malloc(Nmax, sizeof(size_t)); // allocate memory for "remark" array - inline void remark(size_t old, size_t *newv){ - size_t new = *newv; - if(old == new || assoc[old] == new || assoc[new] == old){ - DBG("(%zd)\n", new); + size_t last_assoc_idx = 0; // last index filled in assoc array + size_t currentnum = 0; // current pixel number + inline void remark(size_t old, size_t new){ // remark in assoc[] pixel with value old to assoc[new] or vice versa + size_t New = assoc[new], Old = assoc[old]; + if(Old == New){ + DBG("components equal (%zd->%zd and %zd->%zd)\n", old, Old, new, New); return; } - DBG("[cur: %zx, tot: %zd], %zx -> %zx ", N, Ntot, old, new); - if(!assoc[old]){ // try to remark non-marked value - assoc[old] = new; - DBG("\n"); - return; + DBG("N=%zd, curr=%zd, old:%zd->%zd <-> new:%zd->%zd ", N, currentnum, old, Old, new, New); + // now we must check Old: if Old we have to remark "new" to assoc[old] - // and decrement all marks, that are greater than "new" - size_t ao = assoc[old]; - DBG("(remarked to %zx) ", ao); - DBG(" {old: %zd, new: %zd, a[o]=%zd, a[n]=%zd} ", old, new, assoc[old], assoc[new]); - // now we must check assoc[old]: if it is < new -> change *newv, else remark assoc[old] - if(ao < new) - *newv = ao; - else{ - size_t x = ao; ao = new; new = x; // swap values - } - int m = (old > new) ? old : new; - int xx = m + W / 2; - if(xx > Nmax) xx = Nmax; - DBG(" [[xx=%d]] ", xx); - OMP_FOR() - for(int i = 1; i <= xx; i++){ + // decrement counters for current value (because we make merging) + --currentnum; + //OMP_FOR() + for(size_t i = 1; i < last_assoc_idx; ++i){ size_t m = assoc[i]; - if(m < new) continue; - if(m == new){ - assoc[i] = ao; - DBG("remark %x (%zd) to %zx ", i, m, ao); - }else{ + DBG("assoc[%zd]=%zd ", i, m); + if(m < Old) continue; // lower values + if(m == Old){ // change all old markers to new + assoc[i] = New; + DBG("remark %zd->%zd to ->%zd ", i, m, New); + }else{ // decrement all higher values + DBG("decr %zd->%zd, ", i, m); assoc[i]--; - DBG("decr %x: %zx, ", i, assoc[i]); } } DBG("\n"); - Ntot--; } - t0 = dtime(); + //t0 = dtime(); size_t *ptr = labels; - for(y = 0; y < H; y++){ // FIXME!!!! throw out that fucking "if" checking coordinates!!! + for(y = 0; y < H; y++){ bool found = false; size_t curmark = 0; // mark of pixel to the left for(int x = 0; x < W; x++, ptr++){ @@ -86,49 +74,58 @@ printf("time for char2st: %gs\n", dtime()-t0); found = true; // now check neighbours in upper string: if(U){ - //#ifdef LABEL_8 + #ifdef LABEL_8 if(x && U[-1]){ // there is something in upper left corner -> use its value upmark = U[-1]; }else // check point above only if there's nothing in left up - //#endif + #endif if(U[0]) upmark = U[0]; - //#ifdef LABEL_8 + #ifdef LABEL_8 if(x < w && U[1]){ // there's something in upper right if(upmark){ // to the left of it was pixels - remark(U[1], &upmark); + remark(U[1], upmark); }else upmark = U[1]; } - //#endif + #endif } if(!upmark){ // there's nothing above - set current pixel to incremented counter + DBG("line #%d (w = %d) ", y, h); #ifdef LABEL_8 // check, whether pixel is not single - size_t *D = (y < w) ? &ptr[W] : NULL; - if( !(x && ((D && D[-1]) || ptr[-1])) // no left neighbours + size_t *D = (y < h) ? &ptr[W] : NULL; + if( !(x && ((D && D[-1]) /*|| ptr[-1]*/)) // no left neighbours && !(x < w && ((D && D[1]) || ptr[1])) // no right neighbours && !(D && D[0])){ // no neighbour down *ptr = 0; // erase this hermit! + DBG("hermit!\n"); + continue; + } + #else + // no neighbour down & neighbour to the right -> hermit + if((y < h && ptr[W] == 0) && (x < w && ptr[1] == 0)){ + *ptr = 0; // erase this hermit! + DBG("hermit!\n"); continue; } #endif upmark = ++N; - Ntot++; - assoc[upmark] = upmark; // refresh "assoc" + assoc[upmark] = ++currentnum; // refresh "assoc" + DBG("assoc[%zd] = %zd\n", upmark, currentnum); + last_assoc_idx = upmark + 1; } *ptr = upmark; curmark = upmark; - //remark(curval, &upmark); }else{ // there was something to the left -> we must chek only U[1] if(U){ if(x < w && U[1]){ // there's something in upper right - remark(U[1], &curmark); + remark(U[1], curmark); } } *ptr = curmark; } } } -printf("time for step 2: %gs, found %zd objects\n", dtime()-t0, Ntot); +//printf("time for step 2: %gs, found %zd objects\n", dtime()-t0, currentnum); DBG("Initial mark\n"); #ifdef EBUG for(y = 0; y < H; y++){ @@ -141,7 +138,7 @@ for(y = 0; y < H; y++){ } #endif -t0 = dtime(); +//t0 = dtime(); // Step 2: rename markers DBG("rename markers\n"); // first correct complex assotiations in assoc @@ -154,7 +151,7 @@ t0 = dtime(); *ptr = assoc[p]; } } -printf("time for step 3: %gs\n", dtime()-t0); +//printf("time for step 3: %gs\n", dtime()-t0); #ifdef EBUG printf("\n\n"); for(y = 0; y < H; y++){ @@ -168,3 +165,4 @@ for(y = 0; y < H; y++){ #endif FREE(assoc); FREE(labels); +printf("%6.4f\t%zd\n", dtime()-t0, currentnum); diff --git a/erosion-dilation/main.c b/erosion-dilation/main.c index da610ca..469e087 100644 --- a/erosion-dilation/main.c +++ b/erosion-dilation/main.c @@ -57,117 +57,58 @@ long throw_random_seed(){ int main(int ac, char **v){ - int i,j, W = 28, H = 28, W_0; + int i,j, W = 500, H = 500, W_0; //double midX = (W - 1.0)/ 4. - 1., midY = (H - 1.) / 4. - 1.; //double ro = sqrt(midX*midY), ri = ro / 1.5; bool *inp = Malloc(W * H, sizeof(bool)); - printf("\n"); srand48(throw_random_seed()); for(i = 0; i < H; i++) for(j = 0; j < W; j++) - inp[i*W+j] = (drand48() > 0.5); - /* - for(i = 0; i < H/2; i++){ - for(j = 0; j < W/2; j++){ - double x = j - midX, y = i - midY; - double r = sqrt(x*x + y*y); - if((r < ro && r > ri) || fabs(x) == fabs(y)) - inp[i*W+j] = inp[i*W+j+W/2] = inp[(i+H/2)*W+j] = inp[(i+H/2)*W+j+W/2] = true; - } - }*/ - unsigned char *b2ch = bool2char(inp, W, H, &W_0); - FREE(inp); - printf("inpt: (%dx%d)\n", W_0, H); - printC(b2ch, W_0, H); - unsigned char *eros = erosion(b2ch, W_0, H); - printf("erosion: (%dx%d)\n", W_0, H); - printC(eros, W_0, H); - unsigned char *dilat = dilation(b2ch, W_0, H); - printf("dilation: (%dx%d)\n", W_0, H); - printC(dilat, W_0, H); - unsigned char *erdilat = dilation(eros, W_0, H); - printf("\n\ndilation of erosion (openinfg: (%dx%d)\n", W_0, H); - printC(erdilat, W_0, H); - unsigned char *dileros = erosion(dilat, W_0, H); - printf("erosion of dilation (closing): (%dx%d)\n", W_0, H); - printC(dileros, W_0, H); - printf("\n\n\n image - opening of original minus original:\n"); - unsigned char *immer = substim(b2ch, erdilat, W_0, H); - printC(immer, W_0, H); - FREE(eros); FREE(dilat); FREE(erdilat); FREE(dileros); - inp = char2bool(immer, W, H, W_0); - printf("\n\nAnd boolean for previous image (%dx%d):\n ",W,H); - printB(inp, W, H); - FREE(immer); - immer = FC_filter(b2ch, W_0, H); - printf("\n\n\nFilter for 4-connected areas searching:\n"); - printC(immer, W_0, H); - FREE(immer); + inp[i*W+j] = (drand48() > 0.7); + unsigned char *b2ch = bool2char(inp, W, H, &W_0);//, *immer; + /*printf("image:\n"); + printC(b2ch, W_0, H);*/ +// immer = FC_filter(b2ch, W_0, H); +// printf("\n\n\nFilter for 4-connected areas searching:\n"); +// printC(immer, W_0, H); +// FREE(immer); size_t NL; - printf("\nmark 8-connected components:\n"); +// printf("\nmark 4-connected components:\n"); +printf("4new\t"); + cclabel4_1(b2ch, W, H, W_0, &NL); +// printf("\nmark 4-connected components (old):\n"); +printf("4old\t"); + cclabel4(b2ch, W, H, W_0, &NL); +// printf("\nmark 8-connected components:\n"); +printf("8new\t"); cclabel8_1(b2ch, W, H, W_0, &NL); - printf("\nmark 8-connected components (old):\n"); +// printf("\nmark 8-connected components (old):\n"); +printf("8old\t"); cclabel8(b2ch, W, H, W_0, &NL); FREE(b2ch); - - return 0; - W = H = 1000; - FREE(inp); - inp = Malloc(W * H, sizeof(bool)); - for(i = 0; i < H; i++) - for(j = 0; j < W; j++) - inp[i*W+j] = (drand48() > 0.5); - b2ch = bool2char(inp, W, H, &W_0); - FREE(inp); - printf("\n\n\n1) 1 cc4 for 2000x2000 .. "); - fflush(stdout); - double t0 = dtime(); - for(i = 0; i < 1; i++){ - CCbox *b = cclabel4(b2ch, W, H, W_0, &NL); - FREE(b); - } - printf("%.3f s\n", dtime() - t0); - printf("\n2) 1 cc8 for 2000x2000 .. "); - fflush(stdout); - t0 = dtime(); - for(i = 0; i < 1; i++){ - CCbox *b = cclabel8(b2ch, W, H, W_0, &NL); - FREE(b); - } - printf("%.3f s\n", dtime() - t0); - printf("\n3) 1 cc8_1 for 2000x2000 .. "); - fflush(stdout); - t0 = dtime(); - for(i = 0; i < 1; i++){ - CCbox *b = cclabel8_1(b2ch, W, H, W_0, &NL); - FREE(b); - } - printf("%.3f s\n", dtime() - t0); - - /* printf("\n\n\n\nSome tests:\n1) 10000 dilations for 2000x2000 .. "); - fflush(stdout); - double t0 = dtime(); - for(i = 0; i < 10000; i++){ - unsigned char *dilat = dilation(b2ch, W, H); - free(dilat); - } - printf("%.3f s\n", dtime() - t0); - printf("2) 10000 erosions for 2000x2000 .. "); - fflush(stdout); - t0 = dtime(); - for(i = 0; i < 10000; i++){ - unsigned char *dilat = erosion(b2ch, W, H); - free(dilat); - } - printf("%.3f s\n", dtime() - t0); - printf("3) 10000 image substitutions for 2000x2000 .. "); - fflush(stdout); - unsigned char *dilat = dilation(b2ch, W, H); - t0 = dtime(); - for(i = 0; i < 10000; i++){ - unsigned char *res = substim(b2ch, dilat, W, H); - free(res); - } - printf("%.3f s\n", dtime() - t0);*/ return 0; } +/* + * bench + * names = ["4new"; "4old"; "8new"; "8old"]; for i = 1:4; nm = names(i,:); time = []; sz = []; for i = 1:52; if(name{i} == nm) time = [time speed(i)]; sz = [sz num(i)]; endif;endfor; ts = time./sz; printf("%s: time/object = %.1f +- %.1f us\n", nm, mean(ts)*1e6, std(ts)*1e6);endfor; + * + * 0.25 megapixels + * 4new: time/object = 1.9 +- 0.4 us + * 4old: time/object = 1.7 +- 0.1 us + * 8new: time/object = 3.9 +- 0.1 us + * 8old: time/object = 13.5 +- 2.1 us + * + * 1 megapixels ---> [name speed num] = textread("1megapixel", "%s %f %f"); + * 4new: time/object = 5.5 +- 0.5 us + * 4old: time/object = 5.3 +- 0.0 us + * 8new: time/object = 13.3 +- 0.1 us + * 8old: time/object = 47.6 +- 2.2 us + * + * 4 megapixels ---> [name speed num] = textread("4megapixels", "%s %f %f"); + * 4new: time/object = 21.3 +- 1.5 us + * 4old: time/object = 22.3 +- 2.2 us + * 8new: time/object = 57.6 +- 1.3 us + * 8old: time/object = 195.5 +- 11.7 us + * + * + */ diff --git a/getopt/cmdlnopts/Makefile b/getopt/cmdlnopts/Makefile new file mode 100644 index 0000000..3a70aa1 --- /dev/null +++ b/getopt/cmdlnopts/Makefile @@ -0,0 +1,22 @@ +PROGRAM = myopt_example +LDFLAGS = -lm +SRCS = $(wildcard *.c) +CC = gcc +DEFINES = -D_XOPEN_SOURCE=1111 +CXX = gcc +CFLAGS = -Wall -Werror -Wextra $(DEFINES) +OBJS = $(SRCS:.c=.o) +all : $(PROGRAM) +$(PROGRAM) : $(OBJS) + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM) + +# some addition dependencies +# %.o: %.c +# $(CC) $(LDFLAGS) $(CFLAGS) $< -o $@ +#$(SRCS) : %.c : %.h $(INDEPENDENT_HEADERS) +# @touch $@ + +clean: + /bin/rm -f *.o *~ +depend: + $(CXX) -MM $(CXX.SRCS) diff --git a/getopt/cmdlnopts/cmdlnopts.c b/getopt/cmdlnopts/cmdlnopts.c new file mode 100644 index 0000000..03eef5a --- /dev/null +++ b/getopt/cmdlnopts/cmdlnopts.c @@ -0,0 +1,264 @@ +/* + * cmdlnopts.c - the only function that parce cmdln args and returns glob parameters + * + * Copyright 2013 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include "cmdlnopts.h" + +#define RAD 57.2957795130823 +#define D2R(x) ((x) / RAD) +#define R2D(x) ((x) * RAD) + +/* + * here are global parameters initialisation + */ +int help; +glob_pars G; +mirPar M; + +int rewrite_ifexists = 0, // rewrite existing files == 0 or 1 + verbose = 0; // each -v increments this value, e.g. -vvv sets it to 3 +// DEFAULTS +// default global parameters +glob_pars const Gdefault = { + NULL, // size of initial array of surface deviations + 100, // size of interpolated S0 + 1000, // resulting image size + 10000, // amount of photons falled to one pixel of S1 by one iteration + 0, // add to mask random numbers + NULL, // amplitude of added random noice + NULL, // mirror + 0, // rest num + NULL, // rest pars + NULL, // str + NULL // filter +}; +//default mirror parameters +mirPar const Mdefault = { + 6., // diameter + 24.024, // focus + 0., // inclination from Z axe (radians) + 0. // azimuth of inclination (radians) +}; + +// here are functions & definitions for complex parameters (with suboptions etc) +bool get_mir_par(void *arg); +const char MirPar[] = "set mirror parameters, arg=[diam=num:foc=num:Zincl=ang:Aincl=ang]\n" \ + "\t\t\tALL DEGREES ARE IN FORMAT [+-][DDd][MMm][SS.S] like -10m13.4 !\n" \ + "\t\tdiam - diameter of mirror\n" \ + "\t\tfoc - mirror focus ratio\n" \ + "\t\tZincl - inclination from Z axe\n" \ + "\t\tAincl - azimuth of inclination"; + +const char FilPar[] = "set filter parameters, arg=[type=type:xsz=num:ysz=num]\n" \ + "\t\ttype - filter type(med, lap, lg)\n" \ + "\t\txsz,ysz - area size (default is 3x3)"; + +/* + * Define command line options by filling structure: + * name has_arg flag val type argptr help +*/ +myoption cmdlnopts[] = { + // set 1 to param despite of its repeating number: + {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"}, + // simple integer parameter with obligatory arg: + {"int-size",NEED_ARG, NULL, 'i', arg_int, APTR(&G.S_interp), "size of interpolated array of surface deviations"}, + {"image-size",NEED_ARG,NULL, 'I', arg_int, APTR(&G.S_image), "resulting image size"}, + {"N-photons",NEED_ARG,NULL, 'N', arg_int, APTR(&G.N_phot), "amount of photons falled to one pixel of matrix by one iteration"}, + // parameter with suboptions parsed directly in parceargs + {"mir-parameters",NEED_ARG,NULL,'M', arg_function,APTR(&get_mir_par),MirPar}, + // another variant of setting parameter without argument + {"add-noice",NO_ARGS, &G.randMask,1, arg_none, NULL, "add random noice to mirror surface deviations"}, + {"force", NO_ARGS, &rewrite_ifexists,1,arg_none,NULL, "rewrite output file if exists"}, + // incremented parameter without args (any -v will increment value of "verbose") + {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&verbose), "verbose level (each -v increase it)"}, + // integer parameter which can occur several times: + {"dev-size",MULT_PAR, NULL, 'd', arg_int, APTR(&G.S_dev), "size of initial array of surface deviations"}, + // double array + {"noice-amp",MULT_PAR, NULL, 'a', arg_double, APTR(&G.randAmp), "amplitude of random noice (default: 1e-8)"}, + // string array + {"str", MULT_PAR, NULL, 's', arg_string, APTR(&G.str), "some string parameters (may meets many times)"}, + // suboptions array that will be parsed outside (the same as string array): + {"filter", MULT_PAR, NULL, 'f', arg_string, APTR(&G.filter), FilPar}, + end_option +}; + + +// suboptions structure for get_mirpars +// in array last MUST BE {0,0,0} +typedef struct{ + double *val; // pointer to result + char *par; // parameter name (CASE-INSENSITIVE!) + bool isdegr; // == TRUE if parameter is an angle in format "[+-][DDd][MMm][SS.S]" +} suboptions; + +/** + * Safely convert data from string to double + * + * @param num (o) - double number read from string + * @param str (i) - input string + * @return TRUE if success + */ +bool myatod(double *num, const char *str){ + double res; + char *endptr; + assert(str); + res = strtod(str, &endptr); + if(endptr == str || *str == '\0' || *endptr != '\0'){ + printf("Wrong double number format!"); + return FALSE; + } + *num = res; + return TRUE; +} + +/** + * Convert string "[+-][DDd][MMm][SS.S]" into radians + * + * @param ang (o) - angle in radians or exit with help message + * @param str (i) - string with angle + * @return TRUE if OK + */ +bool get_radians(double *ret, char *str){ + double val = 0., ftmp, sign = 1.; + char *ptr; + assert(str); + switch(*str){ // check sign + case '-': + sign = -1.; + case '+': + str++; + } + if((ptr = strchr(str, 'd'))){ // found DDD.DDd + *ptr = 0; if(!myatod(&ftmp, str)) return FALSE; + ftmp = fabs(ftmp); + if(ftmp > 360.){ + printf("Degrees should be less than 360"); + return FALSE; + } + val += ftmp; + str = ptr + 1; + } + if((ptr = strchr(str, 'm'))){ // found DDD.DDm + *ptr = 0; if(!myatod(&ftmp, str)) return FALSE; + ftmp = fabs(ftmp); + val += ftmp / 60.; + str = ptr + 1; + } + if(strlen(str)){ // there is something more + if(!myatod(&ftmp, str)) return FALSE; + ftmp = fabs(ftmp); + val += ftmp / 3600.; + } + *ret = D2R(val * sign); // convert degrees to radians + return TRUE; +} + +/** + * Parse string of suboptions (--option=name1=var1:name2=var2... or -O name1=var1,name2=var2...) + * Suboptions could be divided by colon or comma + * + * !!NAMES OF SUBOPTIONS ARE CASE-UNSENSITIVE!!! + * + * @param arg (i) - string with description + * @param V (io) - pointer to suboptions array (result will be stored in sopts->val) + * @return TRUE if success + */ +bool get_mirpars(void *arg, suboptions *V){ + char *tok, *val, *par; + int i; + tok = strtok(arg, ":,"); + do{ + if((val = strchr(tok, '=')) == NULL){ // wrong format + printf("Wrong format: no value for keyword"); + return FALSE; + } + *val++ = '\0'; + par = tok; + for(i = 0; V[i].val; i++){ + if(strcasecmp(par, V[i].par) == 0){ // found parameter + if(V[i].isdegr){ // DMS + if(!get_radians(V[i].val, val)) // wrong angle + return FALSE; + }else{ // simple double + if(!myatod(V[i].val, val)) // wrong number + return FALSE; + } + break; + } + } + if(!V[i].val){ // nothing found - wrong format + printf("Bad keyword!"); + return FALSE; + } + }while((tok = strtok(NULL, ":,"))); + return TRUE; +} + +/** + * functions of subargs parcing can looks as this + */ +/** + * Parse string of mirror parameters (--mir-diam=...) + * + * @param arg (i) - string with description + * @return TRUE if success + */ +bool get_mir_par(void *arg){ + suboptions V[] = { // array of mirror parameters and string keys for cmdln pars + {&M.D, "diam", FALSE}, + {&M.F, "foc", FALSE}, + {&M.Zincl, "zincl", TRUE}, + {&M.Aincl, "aincl", TRUE}, + {0,0,0} + }; + return get_mirpars(arg, V); +} + +/** + * Parce command line options and return dynamically allocated structure + * to global parameters + * @param argc - copy of argc from main + * @param argv - copy of argv from main + * @return allocated structure with global parameters + */ +glob_pars *parce_args(int argc, char **argv){ + int i; + void *ptr; + ptr = memcpy(&G, &Gdefault, sizeof(G)); assert(ptr); + ptr = memcpy(&M, &Mdefault, sizeof(M)); assert(ptr); + G.Mirror = &M; + // format of help: "Usage: progname [args]\n" + change_helpstring("Usage: %s [args]\n\n\tWhere args are:\n"); + // parse arguments + parceargs(&argc, &argv, cmdlnopts); + if(help) showhelp(-1, cmdlnopts); + if(argc > 0){ + G.rest_pars_num = argc; + G.rest_pars = calloc(argc, sizeof(char*)); + for (i = 0; i < argc; i++) + G.rest_pars[i] = strdup(argv[i]); + } + return &G; +} + diff --git a/getopt/cmdlnopts/cmdlnopts.h b/getopt/cmdlnopts/cmdlnopts.h new file mode 100644 index 0000000..f4b1719 --- /dev/null +++ b/getopt/cmdlnopts/cmdlnopts.h @@ -0,0 +1,61 @@ +/* + * cmdlnopts.h - comand line options for parceargs + * + * Copyright 2013 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __CMDLNOPTS_H__ +#define __CMDLNOPTS_H__ + +#include "parceargs.h" + +/* + * here are some typedef's for global data + */ +// parameters of mirror +typedef struct{ + double D; // diameter + double F; // focus + double Zincl; // inclination from Z axe (radians) + double Aincl; // azimuth of inclination (radians) +} mirPar; + +typedef struct{ + int **S_dev; // size of initial array of surface deviations + int S_interp; // size of interpolated S0 + int S_image; // resulting image size + int N_phot; // amount of photons falled to one pixel of S1 by one iteration + int randMask; // add to mask random numbers + double **randAmp;// amplitude of added random noice + mirPar *Mirror; // mirror parameters + int rest_pars_num;// number of rest parameters + char** rest_pars;// the rest parameters: array of char* + char **str; // string parameters + char **filter; // some filter options +} glob_pars; + + +// default & global parameters +extern glob_pars const Gdefault; +extern mirPar const Mdefault; +extern int rewrite_ifexists, verbose; + +glob_pars *parce_args(int argc, char **argv); + +#endif // __CMDLNOPTS_H__ diff --git a/getopt/cmdlnopts/main.c b/getopt/cmdlnopts/main.c new file mode 100644 index 0000000..51cefce --- /dev/null +++ b/getopt/cmdlnopts/main.c @@ -0,0 +1,107 @@ +/* + * main.c + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include "cmdlnopts.h" + +typedef struct{ + char *filtertype; + int xsize; + int ysize; +} filterpars; + + +void parce_filter(char *pars){ + filterpars params = { 0, 3, 3}; + mysuboption filteropts[] = { + {"type", NEED_ARG, arg_string, ¶ms.filtertype}, + {"xsz", NEED_ARG, arg_int, ¶ms.xsize}, + {"ysz", NEED_ARG, arg_int, ¶ms.ysize}, + end_suboption + }; + if(!get_suboption(pars, filteropts)){ + printf("\tbad params\n"); + }else{ + printf("\tfiltertype = %s, sizes: %dx%d\n", params.filtertype, params.xsize, params.ysize); + } +} + +int main(int argc, char **argv){ + glob_pars *G = NULL; // default parameters see in cmdlnopts.c + mirPar *M = NULL; // default mirror parameters + G = parce_args(argc, argv); + M = G->Mirror; + printf("Globals:\n"); + if(!G->S_dev){ + printf("S_dev = 8 (default)\n"); + }else{ + int i = 0, **vals = G->S_dev; + while(*vals){ + printf("S_dev[%d]: %d\n", i++, **vals++); + } + } + if(!G->randAmp){ + printf("randAmp = 1e-8 (default)\n"); + }else{ + int i = 0; + double **a = G->randAmp; + while(*a){ + printf("randAmp[%d]: %g\n", i++, **a++); + } + } + if(G->str){ + printf("meet str args:\n"); + int i = 0; + char **strs = G->str; + if(!*strs) printf("fucn!\n"); + while(*strs) + printf("str[%d] = %s\n", i++, *strs++); + } + printf("S_interp = %d\n", G->S_interp); + printf("S_image = %d\n", G->S_image); + printf("N_phot = %d\n", G->N_phot); + printf("randMask = %d\n", G->randMask); + printf("Mirror =\n"); + printf("\tD = %g\n", M->D); + printf("\tF = %g\n", M->F); + printf("\tZincl = %g\n", M->Zincl); + printf("\tAincl = %g\n", M->Aincl); + printf("rewrite_ifexists = %d\n", rewrite_ifexists); + printf("verbose = %d\n", verbose); + if(G->rest_pars_num){ + int i; + printf("There's also %d free parameters:\n", G->rest_pars_num); + for(i = 0; i < G->rest_pars_num; ++i) + printf("\t%4d: %s\n", i, G->rest_pars[i]); + } + if(G->filter){ + printf("filter parameters:\n"); + char **fpars = G->filter; + int i = 0; + while(*fpars){ + printf("%d:\n", i++); + parce_filter(*fpars); + ++fpars; + } + } + return 0; +} + diff --git a/getopt/cmdlnopts/parceargs.c b/getopt/cmdlnopts/parceargs.c new file mode 100644 index 0000000..2b301b2 --- /dev/null +++ b/getopt/cmdlnopts/parceargs.c @@ -0,0 +1,434 @@ +/* + * parceargs.c - parcing command line arguments & print help + * + * Copyright 2013 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include // printf +#include // getopt_long +#include // calloc, exit, strtoll +#include // assert +#include // strdup, strchr, strlen +#include // strcasecmp +#include // INT_MAX & so on +#include // gettext +#include // isalpha +#include "parceargs.h" + +// macro to print help messages +#ifndef PRNT + #define PRNT(x) gettext(x) +#endif + +char *helpstring = "%s\n"; + +/** + * Change standard help header + * MAY consist ONE "%s" for progname + * @param str (i) - new format + */ +void change_helpstring(char *s){ + int pcount = 0, scount = 0; + char *str = s; + // check `helpstring` and set it to default in case of error + for(; pcount < 2; str += 2){ + if(!(str = strchr(str, '%'))) break; + if(str[1] != '%') pcount++; // increment '%' counter if it isn't "%%" + else{ + str += 2; // pass next '%' + continue; + } + if(str[1] == 's') scount++; // increment "%s" counter + }; + if(pcount > 1 || pcount != scount){ // amount of pcount and/or scount wrong + fprintf(stderr, "Wrong helpstring!\n"); + exit(-1); + } + helpstring = s; +} + +/** + * Carefull atoll/atoi + * @param num (o) - returning value (or NULL if you wish only check number) - allocated by user + * @param str (i) - string with number must not be NULL + * @param t (i) - T_INT for integer or T_LLONG for long long (if argtype would be wided, may add more) + * @return TRUE if conversion sone without errors, FALSE otherwise + */ +static bool myatoll(void *num, char *str, argtype t){ + long long tmp, *llptr; + int *iptr; + char *endptr; + assert(str); + assert(num); + tmp = strtoll(str, &endptr, 0); + if(endptr == str || *str == '\0' || *endptr != '\0') + return FALSE; + switch(t){ + case arg_longlong: + llptr = (long long*) num; + *llptr = tmp; + break; + case arg_int: + default: + if(tmp < INT_MIN || tmp > INT_MAX){ + fprintf(stderr, "Integer out of range\n"); + return FALSE; + } + iptr = (int*)num; + *iptr = (int)tmp; + } + return TRUE; +} + +// the same as myatoll but for double +// There's no NAN & INF checking here (what if they would be needed?) +static bool myatod(void *num, const char *str, argtype t){ + double tmp, *dptr; + float *fptr; + char *endptr; + assert(str); + tmp = strtod(str, &endptr); + if(endptr == str || *str == '\0' || *endptr != '\0') + return FALSE; + switch(t){ + case arg_double: + dptr = (double *) num; + *dptr = tmp; + break; + case arg_float: + default: + fptr = (float *) num; + *fptr = (float)tmp; + break; + } + return TRUE; +} + +/** + * Get index of current option in array options + * @param opt (i) - returning val of getopt_long + * @param options (i) - array of options + * @return index in array + */ +static int get_optind(int opt, myoption *options){ + int oind; + myoption *opts = options; + assert(opts); + for(oind = 0; opts->name && opts->val != opt; oind++, opts++); + if(!opts->name || opts->val != opt) // no such parameter + showhelp(-1, options); + return oind; +} + +/** + * reallocate new value in array of multiple repeating arguments + * @arg paptr - address of pointer to array (**void) + * @arg type - its type (for realloc) + * @return pointer to new (next) value + */ +void *get_aptr(void *paptr, argtype type){ + int i = 1; + void **aptr = *((void***)paptr); + if(aptr){ // there's something in array + void **p = aptr; + while(*p++) ++i; + } + size_t sz; + switch(type){ + default: + case arg_none: + fprintf(stderr, "Can't use multiple args with arg_none!\n"); + exit(-1); + break; + case arg_int: + sz = sizeof(int); + break; + case arg_longlong: + sz = sizeof(long long); + break; + case arg_double: + sz = sizeof(double); + break; + case arg_float: + sz = sizeof(float); + break; + case arg_string: + sz = 0; + break; + /* case arg_function: + sz = sizeof(argfn *); + break;*/ + } + aptr = realloc(aptr, (i + 1) * sizeof(void*)); + *((void***)paptr) = aptr; + aptr[i] = NULL; + if(sz){ + aptr[i - 1] = malloc(sz); + }else + aptr[i - 1] = &aptr[i - 1]; + return aptr[i - 1]; +} + + +/** + * Parce command line arguments + * ! If arg is string, then value will be strdup'ed! + * + * @param argc (io) - address of argc of main(), return value of argc stay after `getopt` + * @param argv (io) - address of argv of main(), return pointer to argv stay after `getopt` + * BE CAREFUL! if you wanna use full argc & argv, save their original values before + * calling this function + * @param options (i) - array of `myoption` for arguments parcing + * + * @exit: in case of error this function show help & make `exit(-1)` + */ +void parceargs(int *argc, char ***argv, myoption *options){ + char *short_options, *soptr; + struct option *long_options, *loptr; + size_t optsize, i; + myoption *opts = options; + // check whether there is at least one options + assert(opts); + assert(opts[0].name); + // first we count how much values are in opts + for(optsize = 0; opts->name; optsize++, opts++); + // now we can allocate memory + short_options = calloc(optsize * 3 + 1, 1); // multiply by three for '::' in case of args in opts + long_options = calloc(optsize + 1, sizeof(struct option)); + opts = options; loptr = long_options; soptr = short_options; + // fill short/long parameters and make a simple checking + for(i = 0; i < optsize; i++, loptr++, opts++){ + // check + assert(opts->name); // check name + if(opts->has_arg){ + assert(opts->type != arg_none); // check error with arg type + assert(opts->argptr); // check pointer + } + if(opts->type != arg_none) // if there is a flag without arg, check its pointer + assert(opts->argptr); + // fill long_options + // don't do memcmp: what if there would be different alignment? + loptr->name = opts->name; + loptr->has_arg = (opts->has_arg < MULT_PAR) ? opts->has_arg : 1; + loptr->flag = opts->flag; + loptr->val = opts->val; + // fill short options if they are: + if(!opts->flag){ + *soptr++ = opts->val; + if(loptr->has_arg) // add ':' if option has required argument + *soptr++ = ':'; + if(loptr->has_arg == 2) // add '::' if option has optional argument + *soptr++ = ':'; + } + } + // now we have both long_options & short_options and can parse `getopt_long` + while(1){ + int opt; + int oindex = 0, optind = 0; // oindex - number of option in argv, optind - number in options[] + if((opt = getopt_long(*argc, *argv, short_options, long_options, &oindex)) == -1) break; + if(opt == '?'){ + opt = optopt; + optind = get_optind(opt, options); + if(options[optind].has_arg == NEED_ARG || options[optind].has_arg == MULT_PAR) + showhelp(optind, options); // need argument + } + else{ + if(opt == 0 || oindex > 0) optind = oindex; + else optind = get_optind(opt, options); + } + opts = &options[optind]; + if(opt == 0 && opts->has_arg == NO_ARGS) continue; // only long option changing integer flag + // now check option + if(opts->has_arg == NEED_ARG || opts->has_arg == MULT_PAR) + if(!optarg) showhelp(optind, options); // need argument + void *aptr; + if(opts->has_arg == MULT_PAR){ + aptr = get_aptr(opts->argptr, opts->type); + }else + aptr = opts->argptr; + bool result = TRUE; + // even if there is no argument, but argptr != NULL, think that optarg = "1" + if(!optarg) optarg = "1"; + switch(opts->type){ + default: + case arg_none: + if(opts->argptr) *((int*)aptr) += 1; // increment value + break; + case arg_int: + result = myatoll(aptr, optarg, arg_int); + break; + case arg_longlong: + result = myatoll(aptr, optarg, arg_longlong); + break; + case arg_double: + result = myatod(aptr, optarg, arg_double); + break; + case arg_float: + result = myatod(aptr, optarg, arg_float); + break; + case arg_string: + result = (*((void**)aptr) = (void*)strdup(optarg)); + break; + case arg_function: + result = ((argfn)aptr)(optarg); + break; + } + if(!result){ + showhelp(optind, options); + } + } + *argc -= optind; + *argv += optind; +} + +/** + * Show help information based on myoption->help values + * @param oindex (i) - if non-negative, show only help by myoption[oindex].help + * @param options (i) - array of `myoption` + * + * @exit: run `exit(-1)` !!! + */ +void showhelp(int oindex, myoption *options){ + // ATTENTION: string `help` prints through macro PRNT(), bu default it is gettext, + // but you can redefine it before `#include "parceargs.h"` + int max_opt_len = 0; // max len of options substring - for right indentation + const int bufsz = 255; + char buf[bufsz+1]; + myoption *opts = options; + assert(opts); + assert(opts[0].name); // check whether there is at least one options + if(oindex > -1){ // print only one message + opts = &options[oindex]; + printf(" "); + if(!opts->flag && isalpha(opts->val)) printf("-%c, ", opts->val); + printf("--%s", opts->name); + if(opts->has_arg == 1) printf("=arg"); + else if(opts->has_arg == 2) printf("[=arg]"); + printf(" %s\n", PRNT(opts->help)); + exit(-1); + } + // header, by default is just "progname\n" + printf("\n"); + if(strstr(helpstring, "%s")) // print progname + printf(helpstring, __progname); + else // only text + printf("%s", helpstring); + printf("\n"); + // count max_opt_len + do{ + int L = strlen(opts->name); + if(max_opt_len < L) max_opt_len = L; + }while((++opts)->name); + max_opt_len += 14; // format: '-S , --long[=arg]' - get addition 13 symbols + opts = options; + // Now print all help + do{ + int p = sprintf(buf, " "); // a little indent + if(!opts->flag && isalpha(opts->val)) // .val is short argument + p += snprintf(buf+p, bufsz-p, "-%c, ", opts->val); + p += snprintf(buf+p, bufsz-p, "--%s", opts->name); + if(opts->has_arg == 1) // required argument + p += snprintf(buf+p, bufsz-p, "=arg"); + else if(opts->has_arg == 2) // optional argument + p += snprintf(buf+p, bufsz-p, "[=arg]"); + assert(p < max_opt_len); // there would be magic if p >= max_opt_len + printf("%-*s%s\n", max_opt_len+1, buf, PRNT(opts->help)); // write options & at least 2 spaces after + }while((++opts)->name); + printf("\n\n"); + exit(-1); +} + +/** + * get suboptions from parameter string + * @param str - parameter string + * @param opt - pointer to suboptions structure + * @return TRUE if all OK + */ +bool get_suboption(char *str, mysuboption *opt){ + int findsubopt(char *par, mysuboption *so){ + int idx = 0; + while(so[idx].name){ + if(strcasecmp(par, so[idx].name) == 0) return idx; + ++idx; + } + return -1; // badarg + } + bool opt_setarg(mysuboption *so, int idx, char *val){ + mysuboption *soptr = &so[idx]; + bool result = FALSE; + void *aptr = soptr->argptr; + switch(soptr->type){ + default: + case arg_none: + if(soptr->argptr) *((int*)aptr) += 1; // increment value + break; + case arg_int: + result = myatoll(aptr, val, arg_int); + break; + case arg_longlong: + result = myatoll(aptr, val, arg_longlong); + break; + case arg_double: + result = myatod(aptr, val, arg_double); + break; + case arg_float: + result = myatod(aptr, val, arg_float); + break; + case arg_string: + result = (*((void**)aptr) = (void*)strdup(val)); + break; + case arg_function: + result = ((argfn)aptr)(val); + break; + } + return result; + } + char *tok, *val; + bool ret = FALSE; + char *tmpbuf; + tok = strtok_r(str, ":,", &tmpbuf); + do{ + val = strchr(tok, '='); + int noarg = 0; + if(val == NULL){ // no args + val = "1"; + noarg = 1; + }else{ + *val++ = '\0'; + if(!*val || *val == ':' || *val == ','){ // no argument - delimeter after = + val = "1"; noarg = 1; + } + } + int idx = findsubopt(tok, opt); + if(idx < 0){ + printf("Wrong parameter: %s", tok); + goto returning; + } + if(noarg && opt[idx].has_arg == NEED_ARG){ + printf("%s: argument needed!\n", tok); + goto returning; + } + if(!opt_setarg(opt, idx, val)){ + printf("Wrong argument \"%s\" of parameter \"%s\"\n", val, tok); + goto returning; + } + }while((tok = strtok_r(NULL, ":,", &tmpbuf))); + ret = TRUE; +returning: + return ret; +} diff --git a/getopt/cmdlnopts/parceargs.h b/getopt/cmdlnopts/parceargs.h new file mode 100644 index 0000000..f069ed6 --- /dev/null +++ b/getopt/cmdlnopts/parceargs.h @@ -0,0 +1,124 @@ +/* + * parceargs.h - headers for parcing command line arguments + * + * Copyright 2013 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __PARCEARGS_H__ +#define __PARCEARGS_H__ + +#include // bool +#include + +#ifndef TRUE + #define TRUE true +#endif + +#ifndef FALSE + #define FALSE false +#endif + +// macro for argptr +#define APTR(x) ((void*)x) + +// if argptr is a function: +typedef bool(*argfn)(void *arg); + +/* + * type of getopt's argument + * WARNING! + * My function change value of flags by pointer, so if you want to use another type + * make a latter conversion, example: + * char charg; + * int iarg; + * myoption opts[] = { + * {"value", 1, NULL, 'v', arg_int, &iarg, "char val"}, ..., end_option}; + * ..(parce args).. + * charg = (char) iarg; + */ +typedef enum { + arg_none = 0, // no arg + arg_int, // integer + arg_longlong, // long long + arg_double, // double + arg_float, // float + arg_string, // char * + arg_function // parce_args will run function `bool (*fn)(char *optarg, int N)` +} argtype; + +/* + * Structure for getopt_long & help + * BE CAREFUL: .argptr is pointer to data or pointer to function, + * conversion depends on .type + * + * ATTENTION: string `help` prints through macro PRNT(), bu default it is gettext, + * but you can redefine it before `#include "parceargs.h"` + * + * if arg is string, then value wil be strdup'ed like that: + * char *str; + * myoption opts[] = {{"string", 1, NULL, 's', arg_string, &str, "string val"}, ..., end_option}; + * *(opts[1].str) = strdup(optarg); + * in other cases argptr should be address of some variable (or pointer to allocated memory) + * + * NON-NULL argptr should be written inside macro APTR(argptr) or directly: (void*)argptr + * + * !!!LAST VALUE OF ARRAY SHOULD BE `end_option` or ZEROS !!! + * + */ +typedef enum{ + NO_ARGS = 0, // first three are the same as in getopt_long + NEED_ARG = 1, + OPT_ARG = 2, + MULT_PAR +} hasarg; + +typedef struct{ + // these are from struct option: + const char *name; // long option's name + hasarg has_arg; // 0 - no args, 1 - nesessary arg, 2 - optionally arg, 4 - need arg & key can repeat (args are stored in null-terminated array) + int *flag; // NULL to return val, pointer to int - to set its value of val (function returns 0) + int val; // short opt name (if flag == NULL) or flag's value + // and these are mine: + argtype type; // type of argument + void *argptr; // pointer to variable to assign optarg value or function `bool (*fn)(char *optarg, int N)` + const char *help; // help string which would be shown in function `showhelp` or NULL +} myoption; + +/* + * Suboptions structure, almost the same like myoption + * used in parce_subopts() + */ +typedef struct{ + const char *name; + hasarg has_arg; + argtype type; + void *argptr; +} mysuboption; + +// last string of array (all zeros) +#define end_option {0,0,0,0,0,0,0} +#define end_suboption {0,0,0,0} + +extern const char *__progname; + +void showhelp(int oindex, myoption *options); +void parceargs(int *argc, char ***argv, myoption *options); +void change_helpstring(char *s); +bool get_suboption(char *str, mysuboption *opt); + +#endif // __PARCEARGS_H__ diff --git a/getopt/cmdlnopts.c b/getopt/cmdlnopts_deprecated/cmdlnopts.c similarity index 100% rename from getopt/cmdlnopts.c rename to getopt/cmdlnopts_deprecated/cmdlnopts.c diff --git a/getopt/cmdlnopts.h b/getopt/cmdlnopts_deprecated/cmdlnopts.h similarity index 100% rename from getopt/cmdlnopts.h rename to getopt/cmdlnopts_deprecated/cmdlnopts.h diff --git a/getopt/parceargs.c b/getopt/cmdlnopts_deprecated/parceargs.c similarity index 100% rename from getopt/parceargs.c rename to getopt/cmdlnopts_deprecated/parceargs.c diff --git a/getopt/parceargs.h b/getopt/cmdlnopts_deprecated/parceargs.h similarity index 100% rename from getopt/parceargs.h rename to getopt/cmdlnopts_deprecated/parceargs.h diff --git a/getopt/getopt.c b/getopt/getopt/getopt.c similarity index 100% rename from getopt/getopt.c rename to getopt/getopt/getopt.c diff --git a/getopt/getopt.h b/getopt/getopt/getopt.h similarity index 100% rename from getopt/getopt.h rename to getopt/getopt/getopt.h diff --git a/med.c b/med.c new file mode 100644 index 0000000..2c59dbd --- /dev/null +++ b/med.c @@ -0,0 +1,245 @@ +//Copyright (c) 2011 ashelly.myopenid.com under +#include +#include +#include + +#define OMP_NUM_THREADS 4 +#define Stringify(x) #x +#define OMP_FOR(x) _Pragma(Stringify(omp parallel for x)) + +//Customize for your data Item type +typedef int Item; +#define ItemLess(a,b) ((a)<(b)) +#define ItemMean(a,b) (((a)+(b))/2) + +typedef struct Mediator_t{ + Item* data; // circular queue of values + int* pos; // index into `heap` for each value + int* heap; // max/median/min heap holding indexes into `data`. + int N; // allocated size. + int idx; // position in circular queue + int ct; // count of items in queue +} Mediator; + +/*--- Helper Functions ---*/ + +#define minCt(m) (((m)->ct-1)/2) //count of items in minheap +#define maxCt(m) (((m)->ct)/2) //count of items in maxheap + +//returns 1 if heap[i] < heap[j] +inline int mmless(Mediator* m, int i, int j){ + return ItemLess(m->data[m->heap[i]],m->data[m->heap[j]]); +} + +//swaps items i&j in heap, maintains indexes +inline int mmexchange(Mediator* m, int i, int j){ + int t = m->heap[i]; + m->heap[i] = m->heap[j]; + m->heap[j] = t; + m->pos[m->heap[i]] = i; + m->pos[m->heap[j]] = j; + return 1; +} + +//swaps items i&j if i1 && i < minCt(m) && mmless(m, i+1, i)) ++i; + if(!mmCmpExch(m,i,i/2)) break; + } +} + +//maintains maxheap property for all items below i/2. (negative indexes) +void maxSortDown(Mediator* m, int i){ + for(; i >= -maxCt(m); i*=2){ + if(i<-1 && i > -maxCt(m) && mmless(m, i, i-1)) --i; + if(!mmCmpExch(m,i/2,i)) break; + } +} + +//maintains minheap property for all items above i, including median +//returns true if median changed +int minSortUp(Mediator* m, int i){ + while (i > 0 && mmCmpExch(m, i, i/2)) i /= 2; + return (i == 0); +} + +//maintains maxheap property for all items above i, including median +//returns true if median changed +int maxSortUp(Mediator* m, int i){ + while (i < 0 && mmCmpExch(m, i/2, i)) i /= 2; + return (i == 0); +} + +/*--- Public Interface ---*/ + + +//creates new Mediator: to calculate `nItems` running median. +//mallocs single block of memory, caller must free. +Mediator* MediatorNew(int nItems){ + int size = sizeof(Mediator) + nItems*(sizeof(Item)+sizeof(int)*2); + Mediator* m = malloc(size); + m->data = (Item*)(m + 1); + m->pos = (int*) (m->data + nItems); + m->heap = m->pos + nItems + (nItems / 2); //points to middle of storage. + m->N = nItems; + m->ct = m->idx = 0; + while (nItems--){ //set up initial heap fill pattern: median,max,min,max,... + m->pos[nItems] = ((nItems+1)/2) * ((nItems&1)? -1 : 1); + m->heap[m->pos[nItems]] = nItems; + } + return m; +} + + +//Inserts item, maintains median in O(lg nItems) +void MediatorInsert(Mediator* m, Item v){ + int isNew=(m->ctN); + int p = m->pos[m->idx]; + Item old = m->data[m->idx]; + m->data[m->idx]=v; + m->idx = (m->idx+1) % m->N; + m->ct+=isNew; + if(p>0){ //new item is in minHeap + if (!isNew && ItemLess(old,v)) minSortDown(m,p*2); + else if (minSortUp(m,p)) maxSortDown(m,-1); + }else if (p<0){ //new item is in maxheap + if (!isNew && ItemLess(v,old)) maxSortDown(m,p*2); + else if (maxSortUp(m,p)) minSortDown(m, 1); + }else{ //new item is at median + if (maxCt(m)) maxSortDown(m,-1); + if (minCt(m)) minSortDown(m, 1); + } +} + +//returns median item (or average of 2 when item count is even) +Item MediatorMedian(Mediator* m, Item *minval, Item *maxval){ + Item v= m->data[m->heap[0]]; + if ((m->ct&1) == 0) v = ItemMean(v,m->data[m->heap[-1]]); + Item min, max; + if(minval){ + min = v; + int i; + for(i = -maxCt(m); i < 0; ++i){ + int v = m->data[m->heap[i]]; + if(v < min) min = v; + } + *minval = min; + } + if(maxval){ + max = v; + int i; + for(i = 0; i <= minCt(m); ++i){ + int v = m->data[m->heap[i]]; + if(v > max) max = v; + } + *maxval = v; + } + return v; +} + + +/*--- Test Code ---*/ +#include +void PrintMaxHeap(Mediator* m){ + int i; + if(maxCt(m)) + printf("Max: %3d",m->data[m->heap[-1]]); + for (i=2;i<=maxCt(m);++i){ + printf("|%3d ",m->data[m->heap[-i]]); + if(++i<=maxCt(m)) printf("%3d",m->data[m->heap[-i]]); + } + printf("\n"); +} +void PrintMinHeap(Mediator* m){ + int i; + if(minCt(m)) + printf("Min: %3d",m->data[m->heap[1]]); + for (i=2;i<=minCt(m);++i){ + printf("|%3d ",m->data[m->heap[i]]); + if(++i<=minCt(m)) printf("%3d",m->data[m->heap[i]]); + } + printf("\n"); +} + +void ShowTree(Mediator* m){ + PrintMaxHeap(m); + printf("Mid: %3d\n",m->data[m->heap[0]]); + PrintMinHeap(m); + printf("\n"); +} + +double dtime(){ + double t; + struct timeval tv; + gettimeofday(&tv, NULL); + t = tv.tv_sec + ((double)tv.tv_usec)/1e6; + return t; +} + +#define SZ (4000) +int main(int argc, char* argv[]) +{ + int siz = SZ * SZ; + int i, *v = malloc(siz * sizeof(int)), *o = malloc(siz*sizeof(int)), + *small = malloc(siz * sizeof(int)), *large = malloc(siz * sizeof(int)); + +for (i=0; i < siz; ++i){ + int s = (rand() & 0xf) + 0xf00, d = rand() & 0xffff; + if(d > 0xefff) s+= 0xf000; + else if(d < 0xfff) s = 0; + v[i] = s; +} +double t0; +void printmas(int *arr){ + int x, y, fst = SZ/2-5, lst = SZ/2+4; + for(y = fst; y < lst; ++y){ + for(x = fst; x < lst; ++x) + printf("%5d ", arr[x + y*SZ]); + printf("\n"); + } +} +void printels(int hsz){ + int fulls = hsz*2+1; + printf("median %dx%d for %dx%d image: %g seconds\n", fulls, fulls, SZ, SZ, dtime()-t0); + printf("mid 10 values\n"); + printf("ori:\n"); + printmas(v); + printf("\nmed:\n"); + printmas(o); + printf("\nmin:\n"); + printmas(small); + printf("\nmax:\n"); + printmas(large); + printf("\n\n"); +} + +int hs; +for(hs = 1; hs < 5; ++hs){ + t0 = dtime(); + int blksz = hs*2+1, fullsz = blksz * blksz; + OMP_FOR(shared(o, v, small, large)) + for(int x = hs; x < SZ - hs; ++x){ + int xx, yy, xm = x+hs+1, y; + Mediator* m = MediatorNew(fullsz); + // initial fill + for(yy = 0; yy < blksz - 1; ++yy) for(xx = x-hs; xx < xm; ++xx) MediatorInsert(m, v[xx+yy*SZ]); + for(y = hs; y < SZ - hs; ++y){ + for(xx = x-hs; xx < xm; ++xx) MediatorInsert(m, v[xx+(y+hs)*SZ]); + int curpos = x+y*SZ; + o[curpos] = MediatorMedian(m, &small[curpos], &large[curpos]); + //ShowTree(m); + //if(y == 2) return 0; + } + free(m); + } + printels(hs); +} +free(o); free(v); + free(small); free(large); +}