/* A second pass of a MUSH 2.0 flat file filter. It consumes a *sorted* file of 'used' attribute numbers, and builds a renumbering map. It then eats a flat file on stdin, and writes another on stdout with the attributes renumbered. The renumbering rewrites +N lines to the next actual available attribute after renumbering, +A lines and > lines as appropriate. The mapping is done crudely, by keeping an ordered array of old attribute numbers, and looking them up via a binary search, and using the index they're found at (+ A_USER_START + 1) as the new attribute number. +F lines are discarded. */ /* Because I am stupid */ /* #define DEBUG_STUPID_BIN_SRCH */ typedef struct mapent { int old; int new; } mapent; #define MAP_FAIL "Could not map attr num %d, not in numbers file.\n" #define MAX(a,b) ((a) > (b) ? (a) : (b)) #include <stdio.h> #include "filter.h" main(ac,av) int ac; char *av[]; { FILE *numfile; int lines = 0; mapent *map; int size = 0; int i,num,new; int attr,newattr; int attrcount; char buff[32],ch; if(ac != 2) exit(usage(av[0])); /* Open the file, and gobble up the attribute numbers */ if((numfile = fopen(av[1],"r")) == (FILE *)0){ fprintf(stderr,"Could not open numbers file %s\n",av[1]); exit(usage(av[0])); } /* Get an initial map */ map = (mapent *)malloc(1024 * sizeof(mapent)); size = 1024; if(!map){ fprintf(stderr,"Initial malloc failed.\n"); exit(1); } i = -1; new = A_USER_START; while(fgets(buff,32,numfile)){ if(buff[strlen(buff) - 1] != '\n'){ fprintf(stderr,"Badly formatted numbers file.\n"); exit(usage(av[0])); } buff[strlen(buff) - 1] = '\0'; num = atoi(buff); if(num >= size){ map = (mapent *)realloc(map,sizeof(mapent) * (num + 1024)); size = num + 1024; if(!map){ fprintf(stderr,"realloc failed.\n"); exit(1); } } if(i >= 0 && num <= map[i].old){ fprintf(stderr,"Unsorted or malformed numbers file.\n"); exit(usage(av[0])); } map[++i].old = num; if((++new & 0x7f) == 0) ++new; map[i].new = new; } fprintf(stderr,"Read %d attributes numbers.\n",i+1); /* Now eat stdin, translating attr numbers on stdout. */ /* This means rewrite '+N', '+A' lines and '>' lines. */ /* Throw '+F' lines away, we'll have no free attr nums */ while((ch = getchar()) != EOF){ if(++lines % 1000 == 0){ fputc('.',stderr); fflush(stderr); } if(ch == '+'){ switch(ch = getchar()){ case 'A': scanf("%d",&attr); if(attr <= A_USER_START) newattr = attr; else newattr = mapattr(attr,i,map); if(newattr != -1){ printf("+A%d\n",newattr); eatline(); } else { eatline(); eatline(); } break; case 'N': scanf("%d",&attrcount); if(attrcount < i){ fprintf(stderr, "New attr count, %d > old, %d\n", i,attrcount); exit(1); } printf("+N%d\n",new+1); eatline(); break; case 'F': eatline(); break; default: putchar('+'); putchar(ch); copyline(); } } else if(ch == '>'){ scanf("%d",&attr); if(attr <= A_USER_START) newattr = attr; else newattr = mapattr(attr,i,map); if(newattr == -1){ fprintf(stderr,MAP_FAIL,attr); exit(1); } printf(">%d\n",newattr); eatline(); /* Next bit is the attribute */ copyattr(); } else if(ch == '!') { /* Next line is the name -- copy it raw! */ ungetc(ch,stdin); copyline(); copyline(); } else { /* Let copyline() deal with the whole thing */ /* Bad juju otherwise, if ch == \n, see.. */ ungetc(ch,stdin); copyline(); } } fflush(stdout); fprintf(stderr,"Done.\n"); } /* Map an old attribute number to a new one with a binary search of our table. */ mapattr(a,siz,map) int a; int siz; mapent map[]; { register int blk,i; #ifdef DEBUG_STUPID_BIN_SRCH fprintf(stderr,"----------->Mapping %d..\n",a); #endif blk = i = siz >> 1; while(a != map[i].old && blk > 2){ #ifdef DEBUG_STUPID_BIN_SRCH fprintf(stderr, "size = %d, a = %d, i = %d, map[i].old = %d, blk = %d\n", siz,a,i,map[i].old,blk); #endif blk = blk >> 1; i = (a > map[i].old ? i + blk : i - blk); } #ifdef DEBUG_STUPID_BIN_SRCH fprintf(stderr, "size = %d, a = %d, i = %d, map[i].old = %d, blk = %d\n", siz,a,i,map[i].old,blk); #endif /* I am Too Dumb. Finish w/a short linear search */ if(a < map[i].old){ while(a < map[i].old && i > 0) i--; } else if (a > map[i].old){ while(a > map[i].old && i < siz) i++; } if(a != map[i].old) return(-1); return(map[i].new); } /* Copy chars stdin->stdout until end of line */ copyline() { int ch; do { ch = getchar(); putchar(ch); } while(ch != '\n' && ch != EOF); } /* Copy an attribute. This is complex -- \n's internal to the attr are escaped with a \r before them. Unlike some other routines, we wanna be positioned so next char is 1st char of attribute. */ copyattr() { char last; int ch = '\0'; /* anything other than a \r */ do { last = ch; ch = getchar(); putchar(ch); } while((ch != '\n' || last == '\r') && ch != EOF); } /* Eat chars on stdin until end of line. */ eatline() { int ch; do { ch = getchar(); } while(ch != '\n' && ch != EOF); } usage(cmd) char *cmd; { fprintf(stderr,"usage: %s <attr_num_file>\n",cmd); return(1); }