diff options
Diffstat (limited to 'funtools/filter/filter.c')
-rw-r--r-- | funtools/filter/filter.c | 1041 |
1 files changed, 1041 insertions, 0 deletions
diff --git a/funtools/filter/filter.c b/funtools/filter/filter.c new file mode 100644 index 0000000..78d5383 --- /dev/null +++ b/funtools/filter/filter.c @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * filter.c -- hi-level management of filters + * + */ + +#include <filter.h> + +#if HAVE_CYGWIN||HAVE_MINGW32 +#include <windows.h> +#endif + +extern int idx_debug; + +/* + * + * private routines + * + */ + +/* this is needed by lex */ +static Filter default_filter = NULL; + +/* null filters return this special record */ +static FilterRec null_filter; + +#ifdef ANSI_FUNC +static void +FiltInitRegions(void) +#else +static void FiltInitRegions() +#endif +{ + initevregions(); + initimregions(); +} + +/* + * + * _FilterImageCmp -- compare routine for qsort + * + */ +#ifdef ANSI_FUNC +static int +_FilterImageCmp(const void *s1, const void *s2) +#else +static int _FilterImageCmp(s1, s2) + const void *s1; + const void *s2; +#endif +{ + FilterMask f1 = (FilterMask)s1; + FilterMask f2 = (FilterMask)s2; + + if( f1->y < f2->y ){ + return -1; + } + else if( f1->y > f2->y ){ + return 1; + } + else{ + if( f1->xstart < f2->xstart ){ + return -1; + } + else{ + return 1; + } + } +} + +/* + * + * semi-public routines, used by other modules + * + */ + +/* + * + * public routines + * + */ + +/* + * + * FilterClip -- save the filter without the enclosing brackets + * + */ +#ifdef ANSI_FUNC +char * +FilterClip(char *filter) +#else +char *FilterClip(filter) + char *filter; +#endif +{ + char *tbuf; + char *tptr; + char *ofilter; + int len; + int i; + + /* check for the obvious */ + if( !filter || (*filter == '\0') ) + return(NULL); + + /* save filter, but without the enclosing brackets */ + tbuf = xstrdup(filter); + nowhite(tbuf, tbuf); + tptr = tbuf; + if( *tbuf == '[' ){ + tptr++; + len = strlen(tptr); + for(i=len-1; i>=0; i-- ){ + if( tptr[i] == ']' ){ + tptr[i] = '\0'; + break; + } + } + } + if( tptr && (*tptr != '\0') ){ + /* we extend the buffer because flex has problems in filt_init_buffer + if its smaller than sizeof(FILE *) */ + ofilter = xcalloc(strlen(tptr)+SZ_LINE, sizeof(char)); + nowhite(tptr, ofilter); + } + else{ + ofilter = NULL; + } + xfree(tbuf); + return(ofilter); +} + +/* + * + * FilterDefault -- get the default filter handle for the parser + * + */ +#ifdef ANSI_FUNC +Filter +FilterDefault(void) +#else +Filter FilterDefault() +#endif +{ + return(default_filter); +} + +/* + * + * FilterNull -- get the null filter pointer + * + */ +#ifdef ANSI_FUNC +Filter +FilterNull(void) +#else +Filter FilterNull() +#endif +{ + return(&null_filter); +} + +/* + * + * FilterNum -- get a unique number associated with an open filter + * + */ +static int filter_num=0; +#ifdef ANSI_FUNC +int +FilterNum(void) +#else +int FilterNum() +#endif +{ + filter_num++; + return(filter_num); +} + +/* + * + * FilterPath -- get the path through which we look for things + * + */ +#ifdef ANSI_FUNC +char * +FilterPath(void) +#else +char *FilterPath() +#endif +{ + static char *filter_path=NULL; + if( filter_path == NULL ){ + filter_path = (char *)getenv("PATH"); + } + return(filter_path); +} + +/* + * + * FilterOpen -- open a filter and initialize the symbol table + * + */ +#ifdef ANSI_FUNC +Filter +FilterOpen(FITSHead header, char *string, char *mode) +#else +Filter FilterOpen(header, string, mode) + FITSHead header; /* fitsy header struct */ + char *string; /* filter string */ + char *mode; /* "C", "f77", "awk", etc. */ +#endif +{ + int lexonly=0; + int got=0; + char *s, *t; + char tbuf[SZ_LINE]; + Filter filter; + char *filtstr; + + /* return if we have no filter */ + if( (string == NULL) || (*string == '\0') || + !strcmp(string, "[]") || !strcmp(string, "\n") ) + return(NOFILTER); + + /* more checks for an essentially blank string */ + for(got=0, s=string; *s; s++){ + if( (*s != ' ') && (*s != '\t') && (*s != '\n') && (*s != ';') ){ + got++; + break; + } + } + if( !got ) + return(NOFILTER); + + /* allocate a new filter record */ + if( (filter = (Filter)xcalloc(1, sizeof(FilterRec))) == NULL ) + return(NULL); + + /* this is the default filter handle for the parser */ + default_filter = filter; + + /* clean up filter */ + s = FilterClip(string); + /* if its not a file, use string directly */ + if( *s != '@' ){ + t = xstrdup(s); + } + /* if it a FITS file, use string directly */ + else if( IsFits(&(s[1])) ){ + t = xstrdup(s); + } + /* replace ASCII file with contents, if possible */ + else if( !(t = FileContents(&(s[1]), 0, NULL)) ){ + t = xstrdup(s); + } + /* set the input filter string for the parser */ + filter->string = FilterClip(t); + if( s ) xfree(s); + if( t ) xfree(t); + /* return if we have no filter */ + if( !filter->string || (*filter->string == '\0') ){ + return(NOFILTER); + } + + /* save mode */ + filter->mode=xstrdup(mode); + + /* assume we will use an index */ +#if HAVE_MINGW32==0 + filter->doidx = 1; +#else + filter->doidx = 0; +#endif + + /* process the mode string */ + if( (s = xstrdup(filter->mode)) ){ + /* set global convert flag */ + if( keyword(s, "convert", tbuf, SZ_LINE) ) + filter->convert = istrue(tbuf); + /* set the event section */ + if( keyword(s, "evsect", tbuf, SZ_LINE) ) + filter->evsect = xstrdup(tbuf); + if( keyword(s, "lexonly", tbuf, SZ_LINE) ) + lexonly = 1; +#if HAVE_MINGW32==0 + if( keyword(s, "idx", tbuf, SZ_LINE) ){ + if( istrue(tbuf) ) + filter->doidx = 1; + else if( isfalse(tbuf) ) + filter->doidx = -1; + } +#endif + } + if( s ) xfree(s); + + /* determine which method of filter processing we will use: + currently we support only the C method */ + filter->method = DEFAULT_FILTER_METHOD; + *tbuf = '\0'; + if( (s=(char *)getenv("FILTER_METHOD")) ){ + strcpy(tbuf, s); + } + if( !*tbuf && (s=xstrdup(filter->mode)) ){ + keyword(s, "method", tbuf, SZ_LINE); + if( s ) xfree(s); + } + if( *tbuf ){ + if( !strcasecmp(tbuf, "c") ) + filter->method = METHOD_C; + } + + /* determine which type of filtering we do: event or image */ + filter->type = DEFAULT_FILTER_TYPE; + *tbuf = '\0'; + if( (s=(char *)getenv("FILTER_TYPE")) ){ + strcpy(tbuf, s); + } + if( !*tbuf && (s=xstrdup(filter->mode)) ){ + keyword(s, "type", tbuf, SZ_LINE); + if( s ) xfree(s); + } + if( *tbuf ){ + if( !strncasecmp(tbuf, "ev", 2) ) + filter->type = TYPE_EVENTS; + else if( !strncasecmp(tbuf, "im", 2) ) + filter->type = TYPE_IMAGE; + } + + /* determine which type of process execution we do */ + switch(filter->method){ + case METHOD_C: + filter->ptype = DEFAULT_FILTER_PTYPE; + *tbuf = '\0'; + if( (s=(char *)getenv("FILTER_PTYPE")) ){ + strcpy(tbuf, s); + } + if( !*tbuf && (s=xstrdup(filter->mode)) ){ + keyword(s, "ptype", tbuf, SZ_LINE); + if( s ) xfree(s); + } + if( *tbuf ){ + if( *tbuf == 'p' ) + filter->ptype = PTYPE_PROCESS; + else if( *tbuf == 'c' ) + filter->ptype = PTYPE_CONTAINED; +#ifdef USE_DL + else if( *tbuf == 'd' ) + filter->ptype = PTYPE_DYNAMIC; +#endif + } + break; + default: + filter->ptype = PTYPE_PROCESS; + break; + } + + /* determine region paint mode */ + *tbuf = '\0'; + if( (s=(char *)getenv("FILTER_PAINT")) ){ + strcpy(tbuf, s); + } + if( !*tbuf && (s=xstrdup(filter->mode)) ){ + keyword(s, "paint", tbuf, SZ_LINE); + if( s ) xfree(s); + } + if( !*tbuf ) + strcpy(tbuf, DEFAULT_PAINT_MODE); + if( *tbuf ){ + if( istrue(tbuf) ) + filter->paint = 1; + else + filter->paint = 0; + } + + /* debugging mode */ + *tbuf = '\0'; + if( (s=(char *)getenv("FILTER_DEBUG")) ){ + strcpy(tbuf, s); + } + if( !*tbuf && (s=xstrdup(filter->mode)) ){ + keyword(s, "debug", tbuf, SZ_LINE); + if( s ) xfree(s); + } + if( *tbuf ){ + if( isdigit((int)*tbuf) ) + filter->debug = atoi(tbuf); + else if( istrue(tbuf) ) + filter->debug = 1; + else if( isfalse(tbuf) ) + filter->debug = 0; + } + + /* save the fits header */ + filter->fhd = header; + + /* init the symbol table */ + if( !FilterSymbolInit(filter) ) + goto error; + + /* init parser variables */ + FiltInitParser(); + + /* init regions */ + FiltInitRegions(); + + /* set up to parse the input filter */ + FiltScanString(filter->string); + + /* parse filter */ + filtlex(); + + /* check for errors while parsing the string */ + if( FilterParseError() ) + goto error; + + /* make sure we have something to filter */ + if( !(filtstr = (char *)_FilterString()) || !strcmp(filtstr, "()") ){ + FilterClose(filter); + return(NOFILTER); + } + + /* imagemask processing of images does not use the compiled process */ + if( filter->nmask && filter->masks && (filter->type == TYPE_IMAGE) ) + goto done; + + /* for event filtering, we can use indexes */ +#if HAVE_MINGW32==0 + if( filter->type == TYPE_EVENTS ){ + /* run index grammar and see if we can get help from indexes */ + if( filter->doidx == 1 ){ + if( !idxinitparser(filtstr) ){ + filter->doidx = -1; + } + else{ + idxparse(); + idxfreeglobals(); + if( !filter->idx || (filter->idx->type == IDX_INDEF) ){ + if( filter->idx ){ + idxendparser(); + filter->idx = NULL; + } + filter->doidx = -1; + } + } + } + /* if we are using an index and we are only processing indexed columns, + we don't need to use compiled filter */ + if( FILTER_INDEX_ONLY(filter) ){ + if( idx_debug ) fprintf(stderr, "idx: skipping compiled filter\n"); + goto done; + } + } +#endif + + /* lexonly means we only wanted to run the lexer */ + if( lexonly ) + goto done; + + /* open the program file that we will compile from the filter */ + if( !FilterProgOpen(filter) ) + goto error; + + /* prepend the to C program as needed */ + if( !FilterProgPrepend(filter) ) + goto error; + + /* write the symbols to the appropriate program */ + if( !FilterProgWrite(filter) ) + goto error; + + /* append the program body to C program */ + if( !FilterProgAppend(filter) ) + goto error; + + /* that is all we need to output */ + if( !FilterProgClose(filter) ) + goto error; + + /* compile the filter program */ + if( !FilterProgCompile(filter) ) + goto error; + + if( filter->debug >= 2 ) goto done; + + switch(filter->method){ + case METHOD_C: + switch(filter->ptype){ + case PTYPE_PROCESS: + case PTYPE_CONTAINED: + switch(filter->pipeos){ + case PIPE_WIN32: +#if HAVE_CYGWIN||HAVE_MINGW32 + if( !WinProcessOpen(filter->prog, + &(filter->ihandle), &(filter->ohandle), &(filter->process)) ) + goto error; +#else + gerror(stderr, "internal error: no WinProcess without Windows"); + goto error; +#endif + break; + default: + if( !ProcessOpen(filter->prog, + &(filter->ichan), &(filter->ochan), &(filter->pid)) ) + goto error; + break; + } + break; +#ifdef USE_DL + case PTYPE_DYNAMIC: + if( !(filter->dl=DLOpen(filter->prog)) ) + goto error; + break; +#endif + default: + goto error; + } + break; + default: + goto error; + } + + /* return the good news */ +done: + return(filter); + +error: + FilterClose(filter); + return(NULL); + +} + +/* + * + * FilterEvents -- filter events by sending them to a co-process, + * which returns a char array of good event flags + * + */ +#ifdef ANSI_FUNC +int +FilterEvents(Filter filter, char *ebuf, int esize, int n, int *vbuf) +#else +int FilterEvents(filter, ebuf, esize, n, vbuf) + Filter filter; + char *ebuf; + int esize; + int n; + int *vbuf; +#endif +{ + int i; + int flag; + int get=0, got=0; + int bytes; + char *eptr; + char *etop; + char *obuf; + char *optr; +#ifdef USE_DL + FilterTableCall evrtn; +#endif + FilterSymbols sp; + + /* make sure we have a valid filter and a valid table */ + if( !filter || (filter == NOFILTER) || !filter->fhd || !filter->fhd->table ) + return(0); + + /* handle fits image mask specially */ + if( filter->nmask && filter->masks && !filter->evsect ){ + gerror(stderr, "event filtering cannot use image masks\n"); + return(0); + } + + /* if the index is enough, just return */ + if( FILTER_INDEX_ONLY(filter) ) + return 0; + + /* we only send the necessary parts of each event record */ + if( (obuf = (char *)xcalloc(n*filter->evsize, sizeof(char))) == NULL ) + return(0); + optr = obuf; + + /* extract (and convert) the necessary columns of the event */ + for(eptr=ebuf, etop=ebuf+(n*esize); eptr<etop; eptr += esize){ + /* loop through the symbol table and process columns */ + for(i=0; i<filter->nsyms; i++){ + sp = &(filter->symtab[i]); + /* skip accidentally empty ones */ + if( (sp->name == NULL) || (*sp->name == '\0') ) + continue; + /* process this type of symbol */ + switch(sp->type){ + case SYM_COL: + if( filter->fhd->table->col[sp->idx].type == 'X' ){ + ColumnLoad(eptr+filter->fhd->table->col[sp->idx].offset, + filter->fhd->table->col[sp->idx].size, + (filter->fhd->table->col[sp->idx].n+7)/8, + filter->convert, optr+sp->offset); + } + else{ + ColumnLoad(eptr+filter->fhd->table->col[sp->idx].offset, + filter->fhd->table->col[sp->idx].size, + filter->fhd->table->col[sp->idx].n, + filter->convert, optr+sp->offset); + } + break; + default: + break; + } + } + /* bump to next output record */ + optr += filter->evsize; + } + + switch(filter->ptype){ + case PTYPE_PROCESS: + case PTYPE_CONTAINED: + switch(filter->pipeos){ + case PIPE_WIN32: +#if HAVE_CYGWIN||HAVE_MINGW32 + /* write events to the filter process */ + bytes = n*filter->evsize; + if((got=WinProcessWrite(filter->ohandle, obuf, bytes)) != bytes){ + gerror(stderr, + "event filter failed: wanted to write %d bytes but wrote %d\n", + bytes, got); + flag = -1; + } + /* read back result flags */ + get = n * sizeof(unsigned int); + WinProcessRead(filter->ihandle, vbuf, get, &got); +#else + gerror(stderr, "internal error: no WinProcess without Windows"); + flag = -1; +#endif + break; + default: + /* write events to the filter process */ + bytes = n*filter->evsize; + if((got=ProcessWrite(filter->ochan, obuf, bytes)) != bytes){ + gerror(stderr, + "event filter failed: wanted to write %d bytes but wrote %d\n", + bytes, got); + flag = -1; + } + /* read back result flags */ + get = n * sizeof(unsigned int); + ProcessRead(filter->ichan, vbuf, get, &got); + break; + } + /* we need one int back for each event we wrote */ + if( get == got ){ + flag = 1; + } + else{ + gerror(stderr, + "event filter failed: wanted to read %d bytes but got %d\n", + get, got); + flag = -1; + } + break; +#ifdef USE_DL + case PTYPE_DYNAMIC: + if( (evrtn=(FilterTableCall)DLSym(filter->dl, filter->pname)) ){ + filter->g = (*evrtn)(filter->g, obuf, n, filter->evsize, vbuf); + flag = 1; + } + else{ + flag = -1; + } + break; +#endif + default: + flag = -1; + break; + } + + /* free up malloc'ed space */ + if( obuf ) xfree(obuf); + /* return the news */ + return flag; +} + +/* + * + * FilterImage -- filter image by sending sections to a co-process, + * which returns segments of valid image data + * + */ +#ifdef ANSI_FUNC +int +FilterImage(Filter filter, int x0, int x1, int y0, int y1, int block, + FilterMask *masks, int *nreg) +#else +int FilterImage(filter, x0, x1, y0, y1, block, masks, nreg) + Filter filter; + int x0, x1, y0, y1, block; + FilterMask *masks; + int *nreg; +#endif +{ + int i, j; + int got; + int fsize; + int mblock; + char tbuf[SZ_LINE]; + FilterMask xmasks; +#ifdef USE_DL + FilterImageCall imrtn; +#endif + + /* make sure we have a valid filter */ + if( !filter || (filter == NOFILTER) ) + return(0); + + /* handle fits image mask specially */ + if( filter->nmask && filter->masks ){ + mblock = (int)(((double)((x1 - x0 + 1)/block)/(double)ft_naxis(filter->maskhd, 1)) + 0.5); + if( mblock < 1 ){ + gerror(stderr, "image mask cannot be larger than blocked image section"); + return(0); + } + /* copy mask records into return buffer */ + fsize = filter->nmask * sizeof(FilterMaskRec) * mblock; + xmasks = xmalloc(fsize); + /* copy all masks and translate x,y positions as needed */ + for(got=0, i=0; i<filter->nmask; i++){ + xmasks[got].region = filter->masks[i].region; + xmasks[got].y = (filter->masks[i].y - 1.0) * mblock + 1.0; + xmasks[got].xstart = (filter->masks[i].xstart - 1.0) * mblock + 1.0; + xmasks[got].xstop = (filter->masks[i].xstop - 1.0) * mblock + 1.0; + /* replicate the segment up to the block factor */ + for(j=1; j<mblock; j++){ + xmasks[got+j].region = xmasks[got].region; + xmasks[got+j].y = xmasks[got].y+j; + xmasks[got+j].xstart = xmasks[got].xstart; + xmasks[got+j].xstop = xmasks[got].xstop; + } + got += mblock; + } + /* sort by y and x */ + qsort(xmasks, got, sizeof(FilterMaskRec), _FilterImageCmp); + /* mask records */ + if( masks ) *masks = xmasks; + /* number of regions */ + if( nreg ) *nreg = filter->nmaskreg; + return(got); + } + + /* if the index is enough, just return */ + if( FILTER_INDEX_ONLY(filter) ) + return(0); + + switch(filter->ptype){ + case PTYPE_PROCESS: + case PTYPE_CONTAINED: + switch(filter->pipeos){ + case PIPE_WIN32: +#if HAVE_CYGWIN||HAVE_MINGW32 + /* write command to process */ + snprintf(tbuf, SZ_LINE-1, "%d %d %d %d %d\n", x0, x1, y0, y1, block); + WinProcessWrite(filter->ohandle, tbuf, (int)strlen(tbuf)); + /* read back mask records */ + *masks = WinProcessRead(filter->ihandle, NULL, -1, &got); + got /= sizeof(FilterMaskRec); +#else + gerror(stderr, "internal error: no WinProcess without Windows"); + return(-1); +#endif + break; + default: + /* write command to process */ + snprintf(tbuf, SZ_LINE-1, "%d %d %d %d %d\n", x0, x1, y0, y1, block); + ProcessWrite(filter->ochan, tbuf, (int)strlen(tbuf)); + /* read back mask records */ + *masks = ProcessRead(filter->ichan, NULL, -1, &got); + got /= sizeof(FilterMaskRec); + break; + } + break; +#ifdef USE_DL + case PTYPE_DYNAMIC: + if( (imrtn=(FilterImageCall)DLSym(filter->dl, filter->pname)) ){ + *masks = (*imrtn)(x0, x1, y0, y1, block, &got); + } + else + return(-1); + break; +#endif + default: + return(-1); + } + + /* how many separate regions? */ + if( nreg ) *nreg = FilterRegionCount(TOK_IREG); + + /* return the news */ + return(got); +} + +/* + * + * FilterClose -- close a filter and free up memory + * + */ +#ifdef ANSI_FUNC +int FilterClose(Filter filter) +#else +int FilterClose(filter) + Filter filter; +#endif +{ + int status=0; + int i, j; + Scan scan, tscan; + + if( !filter || (filter == NOFILTER) ) + return(0); + + /* this is the default filter handle */ + default_filter = filter; + + switch(filter->ptype){ + case PTYPE_PROCESS: + case PTYPE_CONTAINED: + /* close the filter process */ + switch(filter->pipeos){ + case PIPE_WIN32: +#if HAVE_CYGWIN||HAVE_MINGW32 + if( filter->process ) WinProcessClose(filter->process, &status); +#else + gerror(stderr, "internal error: no WinProcess without Windows"); +#endif + break; + default: + if( filter->pid > 0 ) ProcessClose(filter->pid, &status); + break; + } + /* delete program */ + if( filter->prog ) unlink(filter->prog); + break; +#ifdef USE_DL + case PTYPE_DYNAMIC: + if( filter->dl ) + DLClose(filter->dl); + break; +#endif + default: + break; + } + + /* call any method-specific cleanup routines */ + FilterProgClose(filter); + FilterProgEnd(filter); + + /* free alloc'ed memory */ + FilterSymbolFree(filter); + if( filter->pname ) xfree(filter->pname); + if( filter->mode ) xfree(filter->mode); + if( filter->masks ) xfree(filter->masks); + if( filter->cc ) xfree(filter->cc); + if( filter->cflags ) xfree(filter->cflags); + if( filter->objs ) xfree(filter->objs); + if( filter->extra ) xfree(filter->extra); + if( filter->shflags ) xfree(filter->shflags); + if( filter->code ) xfree(filter->code); + if( filter->prog ) xfree(filter->prog); + if( filter->string ) xfree(filter->string); + if( filter->xbin ) xfree(filter->xbin); + if( filter->ybin ) xfree(filter->ybin); + if( filter->symtab ) xfree(filter->symtab); + if( filter->evsect ) xfree(filter->evsect); + if( filter->maskhd ) ft_headfree(filter->maskhd, 1); + /* free region information */ + if( filter->g ){ + for(i=0; i<filter->g->maxshapes; i++){ + if( filter->g->shapes[i].scanlist ){ + for(j=0; j<=filter->g->y1; j++){ + if( filter->g->shapes[i].scanlist[j] ){ + for(scan=filter->g->shapes[i].scanlist[j]; scan; ){ + tscan = scan->next; + xfree(scan); + scan = tscan; + } + } + } + xfree(filter->g->shapes[i].scanlist); + } + if( filter->g->shapes[i].pts ) xfree(filter->g->shapes[i].pts); + if( filter->g->shapes[i].xv ) xfree(filter->g->shapes[i].xv); + } + if( filter->g->shapes ) xfree(filter->g->shapes); + if( filter->g->ybuf ) xfree(filter->g->ybuf); + if( filter->g->x0s ) xfree(filter->g->x0s); + if( filter->g->x1s ) xfree(filter->g->x1s); + if( filter->g->masks ) xfree(filter->g->masks); + if( filter->g ) xfree(filter->g); + } + /* free index information */ +#if HAVE_MINGW32==0 + idxendparser(); +#endif + /* free main struct */ + xfree(filter); + /* return the status from closing the sub-process */ + return(status); +} + + +/* + * + * FilterConcats -- concat n filters, removing enclosing brackets as necessary + * + */ +#ifdef ANSI_FUNC +char * +FilterConcats(char **filters, int n) +#else +char *FilterConcats(filters, n) + char **filters; + int n; +#endif +{ + char *ofilter; + char *optr; + char *clip; + int i; + int len; + + /* need at least 1 string */ + if( n == 0 ) + return(NULL); + + /* get max length of output filter */ + for(len=0, i=0; i<n; i++){ + if( filters[i] && (*filters[i] != '\0') ){ + len += strlen(filters[i]); + } + } + + /* need something to return */ + if( len == 0 ) + return(NULL); + + /* allocate space for the output filter */ + ofilter = (char *)xcalloc(len+1, sizeof(char)); + optr = ofilter; + + /* take each input filter */ + for(i=0; i<n; i++){ + if( filters[i] && (*filters[i] != '\0') ){ + /* clip off the brackets */ + clip = FilterClip(filters[i]); + /* copy the clipped filter to the output */ + if( clip && (*clip != '\0') ){ + strcpy(optr, clip); + xfree(clip); + while( *optr ) + optr++; + } + } + } + + /* this is the concat'ed filter */ + return(ofilter); +} + +/* + * + * FilterConcat -- concat 2 filters, with an optional operation in between + * + */ +#ifdef ANSI_FUNC +char * +FilterConcat(char *f1, char *f2, char *op) +#else +char *FilterConcat(f1, f2, op) + char *f1; + char *f2; + char *op; +#endif +{ + char *nf1, *nf2, *nop; + char *result; + char *filters[4]; + int n=0; + + /* clip the filters and look for null extensions */ + nf1 = FilterClip(f1); + nf2 = FilterClip(f2); + nop = FilterClip(op); + + if( nf1 && (*nf1 != '\0') ){ + filters[n++] = nf1; + } + if( nop && (*nop != '\0') && + nf1 && (*nf1 != '\0') && + nf2 && (*nf2 != '\0') ){ + filters[n++] = nop; + } + if( nf2 && (*nf2 != '\0') ){ + filters[n++] = nf2; + } + + /* get the concated filters */ + result = FilterConcats(filters, n); + + /* free up space */ + if( nf1 ) + xfree(nf1); + if( nf2 ) + xfree(nf2); + if( nop ) + xfree(nop); + + /* return result */ + return(result); +} + +/* + * + * FilterString -- return the filter string used for this filter + * + */ +#ifdef ANSI_FUNC +char * +FilterString(Filter filter) +#else +char *FilterString(filter) + Filter filter; +#endif +{ + if( !filter || (filter == NOFILTER) ) + return NULL; + else + return filter->string; +} |