/* 2 2 {n,cr}=find(xr,value), find value in range */ #define FIND_COUNT i[0] #define FIND_VAL d[0] #define FIND_X dp // find the r,c locations // static void rf_find_get( Data *d) { if( d->cp->used && eval_cell( d->cp, &d->c) == d->FIND_VAL) { ++d->FIND_COUNT; if( d->FIND_X) { *d->FIND_X++ = d->c.col; *d->FIND_X++ = d->c.row; } } } // store the r,c locations // static void rf_find_put( Data *d) { if( d->FIND_COUNT > 0) { if( d->cp->n) { fprintf( out, "find: can't assign cell "); print_cell( &d->c, &cell_00); putc( '\n', out); } else { --d->FIND_COUNT; d->cp->val = *d->FIND_X++; d->cp->state = EVALUATED; // need this in case the actual result range is larger than the specified range: d->cp->used = 1; } } } double rf_find(const Node *e, const Cell *c) { double *x = NULL; // to save col,row positions Data d; int cr_dir = dir, cr_rows = 0, cr_cols = 0; Node *lval = Left(e); Node *cr = lval ? lval->next : NULL; Node *xr = Right(e); Node *val = xr->next; if( (cr && check_range( cr, "find: second return value")) || check_range( xr, "find: first argument") ) return 0; d.FIND_X = NULL; if( cr) // if c,r return range was specified { cr_rows = abs(cr->u.r.end.row - cr->u.r.start.row)+1; cr_cols = abs(cr->u.r.end.col - cr->u.r.start.col)+1; if( cr_rows == 2 && cr_cols != 2) cr_dir = BYCOLS; else if( cr_rows != 2 && cr_cols == 2) cr_dir = BYROWS; else if( cr_rows != 2 && cr_cols != 2) { fprintf( out, "find: result range must have two rows or two cols\n"); return 0; } // else cr is 2x2 and we'll use the default direction if( debug) { fprintf(out,"find: cr_dir = %s\n", cr_dir == BYROWS ? "byrows" : "bycols"); } x = malloc( 2*Rsize(xr)*sizeof(double)); if( x == NULL) { yyerror( "ss_find: malloc failed"); exit(1); } d.FIND_X = x; } d.FIND_COUNT = 0; // count number of c,r pairs found d.FIND_VAL = eval_tree( val, c); ss_traverse_range( &xr->u.r.start, &xr->u.r.end, rf_find_get, &d); int r = d.FIND_COUNT; // return value if( lval) lval_helper( "find", lval, c, r); if( cr && r > 0) // assign c,r result values { Range dr = cr->u.r; // destination range, adjust to correct size if( cr_dir == BYROWS) { if( cr_rows != r) { if( dr.start.row <= dr.end.row) dr.end.row = dr.start.row + r - 1; else dr.end.row = dr.start.row + 1 - r; } } else // BYCOLS { if( cr_cols != r) { if( dr.start.col <= dr.end.col) dr.end.col = dr.start.col + r - 1; else dr.end.col = dr.start.col + 1 - r; } } if( debug) { fprintf( out, "find: %d %d %d %d %d\n", dr.start.row, dr.start.col, dr.end.row, dr.end.col, r); } int save_dir = dir; dir = cr_dir; d.FIND_X = x; d.FIND_COUNT *= 2; // number of values to store = 2 * number of c,r pairs ss_traverse_range( &dr.start, &dr.end, rf_find_put, &d); free(x); dir = save_dir; } return r; }