#include #include #include #include #include #include #include "cards.h" extern const char *__progname; typedef struct ops OPS; struct ops { void (*save_cmap)(void); void (*save_bw)(const unsigned char *); void (*save_col)(const unsigned char *); } ; #define SPLITOPS(name) {\ &save_cmap_##name, \ &save_bw_##name, \ &save_col_##name, \ } static char *deckdir; static char *path; static char *pathsuf; static DECK deck; // chars used on write static char cvwrite[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; #define MAXWCOLOURS (sizeof(cvwrite)/sizeof(cvwrite[0])) static int ncvread; static char *cvread; static unsigned short int (*colours)[3]; // card_vals must match the order in the file static const char card_rank[] = { 'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K' }; #define NRANK (sizeof(card_rank)/sizeof(card_rank[0])) // card_suit must match the order in the file static const char card_suit[] = { 'C', 'D', 'H', 'S', 'R', 'B' }; #define NSUIT (sizeof(card_suit)/sizeof(card_suit[0])) static const char *card_xdeck[] = { "UR", "UB", "j" }; static void allocpath(void) { int len; len = strlen(deckdir); path = malloc(len+64); bcopy(deckdir,path,len); pathsuf = path + len; *pathsuf++ = '/'; } static FILE *xfopen(const char *path, const char *mode) { FILE *rv; rv = fopen(path,mode); if (rv) return(rv); fprintf(stderr,"%s: can't open %s for %s\n",__progname,path,('w'==*mode)?"write":"read"); exit(1); } static void nlscan(FILE *f) { int c; while (1) { c = getc(f); if (c == '\n') break; if (c == EOF) { fprintf(stderr,"%s: premature EOF on %s\n",__progname,path); exit(1); } } } static void text_load_colours(int *ncp, char **ccv, unsigned short int (**cvp)[3]) { char *cc; unsigned short int (*cv)[3]; int ac; int nc; FILE *f; int c; unsigned int r; unsigned int g; unsigned int b; cc = 0; cv = 0; ac = 0; nc = 0; strcpy(pathsuf,"c"); f = xfopen(path,"r"); while (1) { c = getc(f); if (c == EOF) break; if (c == '\n') { fprintf(stderr,"%s: blank line in colour list %s\n",__progname,path); exit(1); } if (isspace(c)) { fprintf(stderr,"%s: whitespace instead of colour character in colour list %s\n",__progname,path); exit(1); } if (nc >= ac) { ac += 8; cc = realloc(cc,ac); cv = realloc(cv,ac*sizeof(*cv)); } cc[nc] = c; if (fscanf(f,"%x%x%x",&r,&g,&b) != 3) break; if ((r > 0xffff) || (g > 0xffff) || (b > 0xffff)) { fprintf(stderr,"%s: out-of-range RGB triple (%x,%x,%x) in %s\n",__progname,r,g,b,path); exit(1); } cv[nc][0] = r; cv[nc][1] = g; cv[nc][2] = b; nc ++; nlscan(f); } fclose(f); *ncp = nc; *ccv = cc; *cvp = cv; } static void text_count_backs(int *nbp) { int n; int fd; n = 1; while (1) { sprintf(pathsuf,"bb%d",n); fd = open(path,O_RDONLY,0); if (fd < 0) break; close(fd); sprintf(pathsuf,"cb%d",n); fd = open(path,O_RDONLY,0); if (fd < 0) break; close(fd); n ++; } n --; if (n < 1) { fprintf(stderr,"%s: no back designs!\n",__progname); exit(1); } *nbp = n; } static void text_find_size(int *xsp, int *ysp) { int xs; int ys; FILE *f; int c; int x; strcpy(pathsuf,"bb1"); f = xfopen(path,"r"); xs = -1; ys = 0; x = 0; while (1) { c = getc(f); switch (c) { case EOF: if (x) { fprintf(stderr,"%s: unexpected EOF reading %s\n",__progname,path); exit(1); } *xsp = xs; *ysp = ys; return; break; case '\n': if (x != xs) { if (xs < 0) { xs = x; } else { fprintf(stderr,"%s: inconsistent X size in %s\n",__progname,path); exit(1); } } ys ++; x = 0; break; case '.': case '*': x ++; break; default: fprintf(stderr,"%s: unexpected character `%c' in %s\n",__progname,c,path); exit(1); break; } } } static void text_load_bw(unsigned char *dp) { FILE *f; int x; int y; int c; unsigned char b; f = xfopen(path,"r"); for (y=0;y= ncvread)) abort(); *dp++ = c; } c = getc(f); if (c == EOF) fprintf(stderr,"%s: unexpected EOF on %s\n",__progname,path); if (c != '\n') fprintf(stderr,"%s: line too long in %s\n",__progname,path); } c = getc(f); if (c != EOF) fprintf(stderr,"%s: junk following card image in %s\n",__progname,path); fclose(f); } static void domake(void) { int nb; int xs; int ys; int i; const char *em; text_load_colours(&ncvread,&cvread,&colours); text_count_backs(&nb); text_find_size(&xs,&ys); if ( (ncvread > CARD_MAX_NCOL) || (nb > CARD_MAX_NBACKS) || (xs > CARD_MAX_XSIZE) || (ys > CARD_MAX_YSIZE) ) { fprintf(stderr,"%s: values out of range:\n",__progname); if (ncvread > CARD_MAX_NCOL) fprintf(stderr,"%s: # colours > %d\n",__progname,CARD_MAX_NCOL); if (nb > CARD_MAX_NBACKS) fprintf(stderr,"%s: # backs > %d\n",__progname,CARD_MAX_NBACKS); if (xs > CARD_MAX_XSIZE) fprintf(stderr,"%s: X size > %d\n",__progname,CARD_MAX_XSIZE); if (ys > CARD_MAX_YSIZE) fprintf(stderr,"%s: Y size > %d\n",__progname,CARD_MAX_YSIZE); exit(1); } deck.xsize = xs; deck.ysize = ys; deck.ncol = ncvread; deck.nbacks = nb; card_allocdeck(&deck); for (i=ncvread-1;i>=0;i--) { deck.cmap[i][0] = colours[i][0]; deck.cmap[i][1] = colours[i][1]; deck.cmap[i][2] = colours[i][2]; } for (i=0;i=0;i--) { sprintf(pathsuf,"b%c%c",card_rank[CARD_RANK(i)],card_suit[CARD_SUIT(i)]); text_load_bw(deck.face_bw+CARD_BW_INDEX(&deck,i)); pathsuf[0] = 'c'; text_load_c(deck.face_c+CARD_C_INDEX(&deck,i)); } for (i=CARD_DECK;i MAXWCOLOURS) { fprintf(stderr,"%s: can't handle decks with more than %d colors\n",__progname,(int)MAXWCOLOURS); exit(1); } (*ops->save_cmap)(); for (i=deck.nbacks-1;i>=0;i--) { sprintf(pathsuf,"bb%d",i+1); (*ops->save_bw)(deck.back_bw+CARD_BW_INDEX(&deck,i)); sprintf(pathsuf,"cb%d",i+1); (*ops->save_col)(deck.back_c+CARD_C_INDEX(&deck,i)); } sprintf(pathsuf,"bb%d",deck.nbacks+1); unlink(path); sprintf(pathsuf,"cb%d",deck.nbacks+1); unlink(path); for (i=CARD_XDECK-1;i>=0;i--) { if (i < CARD_DECK) { sprintf(pathsuf,"b%c%c",card_rank[CARD_RANK(i)],card_suit[CARD_SUIT(i)]); } else { sprintf(pathsuf,"b%s",card_xdeck[i-CARD_DECK]); } (*ops->save_bw)(deck.face_bw+CARD_BW_INDEX(&deck,i)); pathsuf[0] = 'c'; (*ops->save_col)(deck.face_c+CARD_C_INDEX(&deck,i)); } } static void save_cmap_text(void) { int i; FILE *f; strcpy(pathsuf,"c"); f = xfopen(path,"w"); for (i=0;i>= 1; } putc('\n',f); } fclose(f); } static void save_col_text(const unsigned char *dp) { FILE *f; int x; int y; int c; f = xfopen(path,"w"); for (y=0;y= deck.ncol) abort(); putc(cvwrite[c],f); } putc('\n',f); } fclose(f); } static const OPS splitops_text = SPLITOPS(text); static void save_cmap_ppm(void) { } static void save_bw_ppm(const unsigned char *dp) { FILE *f; int x; int y; int c; int b; f = xfopen(path,"w"); fprintf(f,"P1\n%d %d\n",deck.xsize,deck.ysize); for (y=0;y>= 1; } putc('\n',f); } fclose(f); } static void save_col_ppm(const unsigned char *dp) { FILE *f; int x; int y; int c; f = xfopen(path,"w"); fprintf(f,"P6\n%d %d\n255\n",deck.xsize,deck.ysize); for (y=0;y>8,f); putc(deck.cmap[c][1]>>8,f); putc(deck.cmap[c][2]>>8,f); } else { fprintf(stderr,"%s: invalid colour %d in %s\n",__progname,c,pathsuf); exit(1); } } } fclose(f); } static const OPS splitops_ppm = SPLITOPS(ppm); static void usage(void) { fprintf(stderr,"Usage: %s -[make|text|ppm] deck-directory\n",__progname); fprintf(stderr,"(-make uses the -text file format)\n"); exit(1); } int main(int, char **); int main(int ac, char **av) { if ( (NRANK != CARD_NRANK) || (NSUIT != CARD_NSUIT) || (sizeof(card_xdeck)/sizeof(card_xdeck[0]) != CARD_XDECK-CARD_DECK) ) { fprintf(stderr,"Sizes don't match the .h - fix the code!\n"); exit(1); } if (ac != 3) usage(); deckdir = av[2]; allocpath(); if (!strcmp(av[1],"-make")) domake(); else if (!strcmp(av[1],"-text")) dosplit(&splitops_text); else if (!strcmp(av[1],"-ppm" )) dosplit(&splitops_ppm); else usage(); exit(0); }