Exemple #1
0
void
del_range(struct ent *left, struct ent *right)
{
    struct range *r;
    int minr, minc, maxr, maxc;

    minr = left->row < right->row ? left->row : right->row;
    minc = left->col < right->col ? left->col : right->col;
    maxr = left->row > right->row ? left->row : right->row;
    maxc = left->col > right->col ? left->col : right->col;

    left = lookat(minr, minc);
    right = lookat(maxr, maxc);

    if (find_range((char *)0, 0, left, right, &r)) 
	return;

    if (r->r_next)
        r->r_next->r_prev = r->r_prev;
    if (r->r_prev)
        r->r_prev->r_next = r->r_next;
    else
	rng_base = r->r_next;
    scxfree((char *)(r->r_name));
    scxfree((char *)r);
    modflg++;
}
Exemple #2
0
// Funcion que elimina todos los yank ents guardados y libera la memoria asignada
void free_yanklist () {
    if (yanklist == NULL) return;
    int c;
    struct ent * r = yanklist;
    struct ent * e;
    while (r != NULL) {
        e = r->next;

        if (r->format) scxfree(r->format);
        if (r->label) scxfree(r->label);
        if (r->expr) efree(r->expr);
        if (r->ucolor) free(r->ucolor);

        free(r);
        r = e;
    }

    for (c = 0; c < COLFORMATS; c++) {
        if (colformat[c] != NULL)
            scxfree(colformat[c]);
        colformat[c] = NULL;
    }

    yanklist = NULL;
    return;
}
Exemple #3
0
// Free memory of entire filters structure
void free_filters() {
    if (filters == NULL) return;
    int i;
    for (i=0; i < howmany; i++)
        if (filters[i].eval != NULL) scxfree((char *) filters[i].eval);
    scxfree((char *) filters);
    filters = NULL;
    return;
}
Exemple #4
0
void
clean_range()
{
    register struct range *r;
    register struct range *nextr;

    r = rng_base;
    rng_base = (struct range *)0;

    while (r) {
	nextr = r->r_next;
	scxfree((char *)(r->r_name));
	scxfree((char *)r);
	r = nextr;
    }
}
Exemple #5
0
void
del_abbr(char *abbrev)
{
    struct abbrev *a;
    struct abbrev *prev;

    if (!(a = find_abbr(abbrev, strlen(abbrev), &prev))) 
	return;

    if (a->a_next)
        a->a_next->a_prev = a->a_prev;
    if (a->a_prev)
        a->a_prev->a_next = a->a_next;
    else
	abbr_base = a->a_next;
    scxfree((char *)(a->abbr));
    scxfree((char *)a);
}
Exemple #6
0
// Remove a filter, freeing its memory
void del_filter(int id) {
    if (filters == NULL || id < 0 || id > howmany) {
        scerror("Cannot delete the filter");
        return;
    }
    if (filters[id].eval != NULL) {
        scxfree((char *) filters[id].eval);
        filters[id].eval = NULL;
    }
    return;
}
Exemple #7
0
void
clean_crange(void) {
    register struct crange *cr;
    register struct crange *nextcr;

    cr = color_base;
    color_base = (struct crange *)0;

    while (cr) {
	nextcr = cr->r_next;
	scxfree((char *)cr);
	cr = nextcr;
    }
}
Exemple #8
0
void
clean_frange()
{
    register struct frange *fr;
    register struct frange *nextfr;

    fr = frame_base;
    frame_base = (struct frange *)0;

    while (fr) {
	nextfr = fr->r_next;
	scxfree((char *)fr);
	fr = nextfr;
    }
    lastfr = 0;
}
Exemple #9
0
void
add_crange(struct ent *r_left, struct ent *r_right, int pair)
{
    struct crange *r;
    int minr, minc, maxr, maxc;

    minr = r_left->row < r_right->row ? r_left->row : r_right->row;
    minc = r_left->col < r_right->col ? r_left->col : r_right->col;
    maxr = r_left->row > r_right->row ? r_left->row : r_right->row;
    maxc = r_left->col > r_right->col ? r_left->col : r_right->col;

    if (!pair) {
	if (color_base)
	    for (r = color_base; r; r = r->r_next)
		if (    (r->r_left->row == r_left->row) &&
			(r->r_left->col == r_left->col) &&
			(r->r_right->row == r_right->row) &&
			(r->r_right->col == r_right->col)) {
		    if (r->r_next)
			r->r_next->r_prev = r->r_prev;
		    if (r->r_prev)
			r->r_prev->r_next = r->r_next;
		    else
			color_base = r->r_next;
		    scxfree((char *)r);
		    modflg++;
		    FullUpdate++;
		    return;
		}
	error("Color range not defined");
	return;
    }

    r = (struct crange *)scxmalloc((unsigned)sizeof(struct crange));
    r->r_left = lookat(minr, minc);
    r->r_right = lookat(maxr, maxc);
    r->r_color = pair;

    r->r_next = color_base;
    r->r_prev = (struct crange *)0;
    if (color_base)
	color_base->r_prev = r;
    color_base = r;

    modflg++;
    FullUpdate++;
}
Exemple #10
0
void doseval (struct enode *e, int row, int col, int fd)
{
    char *s;

    gmyrow = row;
    gmycol = col;

    s = seval(e);
    if (s)
	write(fd, s, strlen(s));
    write(fd, "\n", 1);
    linelim = -1;

    efree(e);
    if (s)
	scxfree(s);
}
Exemple #11
0
void doquery (char *s, char *data, int fd)
{
    goraw();
    query(s, data);
    deraw(0);
    if (linelim >= 0) {
	write(fd, line, strlen(line));
	write(fd, "\n", 1);
    }

    line[0] = '\0';
    linelim = -1;
    error(" ");
    update(0);

    if (s) scxfree(s);
}
Exemple #12
0
void doeval (struct enode *e, char *fmt, int row, int col, int fd)
{
    double v;

    gmyrow = row;
    gmycol = col;

    v = eval(e);
    if (fmt) {
	if (*fmt == ctl('d')) {
	    time_t tv = v;
	    strftime(line, FBUFLEN, fmt + 1, localtime(&tv));
	} else
	    format(fmt, precision[col], v, line, FBUFLEN);
    } else
	sprintf(line, "%.15g", v);
    strcat(line, "\n");
    write(fd, line, strlen(line));
    linelim = -1;

    efree(e);
    if (fmt) scxfree(fmt);
}
Exemple #13
0
void
add_frange(struct ent *or_left, struct ent *or_right, struct ent *ir_left,
	struct ent *ir_right, int toprows, int bottomrows, int leftcols,
	int rightcols)
{
    struct frange *r;
    int minr, minc, maxr, maxc;

    minr = or_left->row < or_right->row ? or_left->row : or_right->row;
    minc = or_left->col < or_right->col ? or_left->col : or_right->col;
    maxr = or_left->row > or_right->row ? or_left->row : or_right->row;
    maxc = or_left->col > or_right->col ? or_left->col : or_right->col;

    or_left = lookat(minr, minc);
    or_right = lookat(maxr, maxc);

    if (ir_left) {
	minr = ir_left->row < ir_right->row ? ir_left->row : ir_right->row;
	minc = ir_left->col < ir_right->col ? ir_left->col : ir_right->col;
	maxr = ir_left->row > ir_right->row ? ir_left->row : ir_right->row;
	maxc = ir_left->col > ir_right->col ? ir_left->col : ir_right->col;

	ir_left = lookat(minr, minc);
	ir_right = lookat(maxr, maxc);

	if (ir_left->row < or_left->row ||
		ir_left->col < or_left->col ||
		ir_right->row > or_right->row ||
		ir_right->col > or_right->col) {
	    error("Invalid parameters");
	    return;
	}
    }

    if (frame_base) {
	/*
	 * Has this frange already been created?  If so, any negative
	 * parameters mean "don't change this value."
	 */
	for (r = frame_base; r; r = r->r_next) {
	    if ((r->or_left == or_left) && (r->or_right == or_right)) {
		if (ir_left) {
		    r->ir_left = ir_left;
		    r->ir_right = ir_right;
		} else {
		    if (toprows < 0)
			toprows = r->ir_left->row - r->or_left->row;
		    if (bottomrows < 0)
			bottomrows = r->or_right->row - r->ir_right->row;
		    if (leftcols < 0)
			leftcols = r->ir_left->col - r->or_left->col;
		    if (rightcols < 0)
			rightcols = r->or_right->col - r->ir_right->col;
		    r->ir_left = lookat(r->or_left->row + toprows,
			    r->or_left->col + leftcols);
		    r->ir_right = lookat(r->or_right->row - bottomrows,
			    r->or_right->col - rightcols);
		}

		/* If all frame sides are 0, delete the frange */
		if (r->ir_left == r->or_left && r->ir_right == r->or_right) {
		    if (r->r_next)
			r->r_next->r_prev = r->r_prev;
		    if (r->r_prev)
			r->r_prev->r_next = r->r_next;
		    else
			frame_base = r->r_next;
		    scxfree((char *)r);
		}
		modflg++;
		FullUpdate++;
		return;
	    }
	}
	/*
	 * See if the specified range overlaps any previously created frange.
	 */
	for (r = frame_base; r; r = r->r_next) {
	    if (  !(r->or_left->row  > or_right->row ||
		    r->or_right->row < or_left->row  ||
		    r->or_left->col  > or_right->col ||
		    r->or_right->col < or_left->col)) {
		error("Framed ranges may not be nested or overlapping");
		return;
	    }
	}
    }

    if (ir_left != or_left || ir_right != or_right) {
	r = (struct frange *)scxmalloc((unsigned)sizeof(struct frange));
	r->or_left = or_left;
	r->or_right = or_right;

	if (ir_left) {
	    r->ir_left  = ir_left;
	    r->ir_right = ir_right;
	} else {
	    if (toprows    < 0) toprows    = 0;
	    if (bottomrows < 0) bottomrows = 0;
	    if (leftcols   < 0) leftcols   = 0;
	    if (rightcols  < 0) rightcols  = 0;
	    r->ir_left = lookat(r->or_left->row + toprows,
		    r->or_left->col + leftcols);
	    r->ir_right = lookat(r->or_right->row - bottomrows,
		    r->or_right->col - rightcols);
	}

	r->r_next = frame_base;
	r->r_prev = (struct frange *)0;
	if (frame_base)
	    frame_base->r_prev = r;
	frame_base = r;
	modflg++;
	FullUpdate++;
    }
}
Exemple #14
0
/* erase the database (tbl, etc.) */
void erasedb() {
    int  r, c;
    char * home;

    for (c = 0; c <= maxcol; c++) {
        fwidth[c] = DEFWIDTH;
        precision[c] = DEFPREC;
        realfmt[c] = DEFREFMT;
    }

    for (r = 0; r <= maxrow; r++) {
        register struct ent ** pp = ATBL(tbl, r, 0);
        for (c = 0; c++ <= maxcol; pp++)
            if (*pp != NULL) {
                //(*pp)->next = freeents;    /* save [struct ent] for reuse */
                //freeents = *pp;
                
                clearent(*pp);
            }
    }

    for (c = 0; c < COLFORMATS; c++)
        if (colformat[c]) {
            scxfree(colformat[c]);
            colformat[c] = NULL;
        }

    maxrow = 0;
    maxcol = 0;

    clean_range();

    propagation = 10;
    calc_order = BYROWS;
    prescale = 1.0;
    tbl_style = 0;
    optimize = 0;
    currow = curcol = 0;

    if (usecurses && has_colors())
        color_set(0, NULL);

    if (mdir) {
        scxfree(mdir);
        mdir = NULL;
    }
    if (autorun) {
        scxfree(autorun);
        autorun = NULL;
    }
    for (c = 0; c < FKEYS; c++)
        if (fkey[c]) {
            scxfree(fkey[c]);
            fkey[c] = NULL;
        }

    // Load $HOME/.scrc if present.
    if ((home = getenv("HOME"))) {
        strcpy(curfile, home);
        strcat(curfile, "/.scimrc");
        if ((c = open(curfile, O_RDONLY)) > -1) {
            close(c);
            (void) readfile(curfile, 0);
        }
    }

    /*
    // Load ./.scimrc if present and $HOME/.scimrc contained `set scrc'.
    if (scrc && strcmp(home, getcwd(curfile, PATHLEN)) &&
        (c = open(".scimrc", O_RDONLY)) > -1) {
    close(c);
    (void) readfile(".scimrc", 0);
    }
     */

    * curfile = '\0';
}
Exemple #15
0
Fichier : lex.c Projet : recalcc/sc
int
yylex()
{
    char *p = line + linelim;
    int ret=0;
    static int isfunc = 0;
    static bool isgoto = 0;
    static bool colstate = 0;
    static int dateflag;
    static char *tokenst = NULL;
    static int tokenl;

    while (isspace(*p)) p++;
    if (*p == '\0') {
	isfunc = isgoto = 0;
	ret = -1;
    } else if (isalpha(*p) || (*p == '_')) {
	register char *la;	/* lookahead pointer */
	register struct key *tblp;

	if (!tokenst) {
	    tokenst = p;
	    tokenl = 0;
	}
	/*
	 *  This picks up either 1 or 2 alpha characters (a column) or
	 *  tokens made up of alphanumeric chars and '_' (a function or
	 *  token or command or a range name)
	 */
	while (isalpha(*p) && isascii(*p)) {
	    p++;
	    tokenl++;
	}
	la = p;
	while (isdigit(*la) || (*la == '$'))
	    la++;
	/*
	 * A COL is 1 or 2 char alpha with nothing but digits following
	 * (no alpha or '_')
	 */
	if (!isdigit(*tokenst) && tokenl && tokenl <= 2 && (colstate ||
		(isdigit(*(la-1)) && !(isalpha(*la) || (*la == '_'))))) {
	    ret = COL;
	    yylval.ival = atocol(tokenst, tokenl);
	} else {
	    while (isalpha(*p) || (*p == '_') || isdigit(*p)) {
		p++;
		tokenl++;
	    }
	    ret = WORD;
	    if (!linelim || isfunc) {
		if (isfunc) isfunc--;
		for (tblp = linelim ? experres : statres; tblp->key; tblp++)
		    if (((tblp->key[0]^tokenst[0])&0137)==0
			    && tblp->key[tokenl]==0) {
			int i = 1;
			while (i<tokenl && ((tokenst[i]^tblp->key[i])&0137)==0)
			    i++;
			if (i >= tokenl) {
			    ret = tblp->val;
			    colstate = (ret <= S_FORMAT);
			    if (isgoto) {
				isfunc = isgoto = 0;
				if (ret != K_ERROR && ret != K_INVALID)
				    ret = WORD;
			    }
			    break;
			}
		    }
	    }
	    if (ret == WORD) {
		struct range *r;
		char *path;
		if (!find_range(tokenst, tokenl,
			(struct ent *)0, (struct ent *)0, &r)) {
		    yylval.rval.left = r->r_left;
		    yylval.rval.right = r->r_right;
		    if (r->r_is_range)
		        ret = RANGE;
		    else
			ret = VAR;
		} else if ((path = scxmalloc((unsigned)PATHLEN)) &&
			plugin_exists(tokenst, tokenl, path)) {
		    strcat(path, p);
		    yylval.sval = path;
		    ret = PLUGIN;
		} else {
		    scxfree(path);
		    linelim = p-line;
		    yyerror("Unintelligible word");
		}
	    }
	}
    } else if ((*p == '.') || isdigit(*p)) {
#ifdef SIGVOID
	void (*sig_save)();
#else
	int (*sig_save)();
#endif
	double v = 0.0;
	int temp;
	char *nstart = p;

	sig_save = signal(SIGFPE, fpe_trap);
	if (setjmp(fpe_buf)) {
	    (void) signal(SIGFPE, sig_save);
	    yylval.fval = v;
	    error("Floating point exception\n");
	    isfunc = isgoto = 0;
	    tokenst = NULL;
	    return FNUMBER;
	}

	if (*p=='.' && dateflag) {  /* .'s in dates are returned as tokens. */
	    ret = *p++;
	    dateflag--;
	} else {
	    if (*p != '.') {
		tokenst = p;
		tokenl = 0;
		do {
		    v = v*10.0 + (double) ((unsigned) *p - '0');
		    tokenl++;
		} while (isdigit(*++p));
		if (dateflag) {
		    ret = NUMBER;
		    yylval.ival = (int)v;
		/*
		 *  If a string of digits is followed by two .'s separated by
		 *  one or two digits, assume this is a date and return the
		 *  .'s as tokens instead of interpreting them as decimal
		 *  points.  dateflag counts the .'s as they're returned.
		 */
		} else if (*p=='.' && isdigit(*(p+1)) && (*(p+2)=='.' ||
			(isdigit(*(p+2)) && *(p+3)=='.'))) {
		    ret = NUMBER;
		    yylval.ival = (int)v;
		    dateflag = 2;
		} else if (*p == 'e' || *p == 'E') {
		    while (isdigit(*++p)) /* */;
		    if (isalpha(*p) || *p == '_') {
			linelim = p - line;
			return (yylex());
		    } else
			ret = FNUMBER;
		} else if (isalpha(*p) || *p == '_') {
		    linelim = p - line;
		    return (yylex());
		}
	    }
	    if ((!dateflag && *p=='.') || ret == FNUMBER) {
		ret = FNUMBER;
		yylval.fval = strtod(nstart, &p);
		if (!finite(yylval.fval))
		    ret = K_ERR;
		else
		    decimal = TRUE;
	    } else {
		/* A NUMBER must hold at least MAXROW and MAXCOL */
		/* This is consistent with a short row and col in struct ent */
		if (v > (double)32767 || v < (double)-32768) {
		    ret = FNUMBER;
		    yylval.fval = v;
		} else {
		    temp = (int)v;
		    if((double)temp != v) {
			ret = FNUMBER;
			yylval.fval = v;
		    } else {
			ret = NUMBER;
			yylval.ival = temp;
		    }
		}
	    }
	}
	(void) signal(SIGFPE, sig_save);
    } else if (*p=='"') {
	char *ptr;
        ptr = p+1;	/* "string" or "string\"quoted\"" */
        while (*ptr && ((*ptr != '"') || (*(ptr-1) == '\\')))
	    ptr++;
        ptr = scxmalloc((unsigned)(ptr-p));
	yylval.sval = ptr;
	p++;
	while (*p && ((*p != '"') ||
		(*(p-1) == '\\' && *(p+1) != '\0' && *(p+1) != '\n')))
	    *ptr++ = *p++;
	*ptr = '\0';
	if (*p)
	    p++;
	ret = STRING;
    } else if (*p=='[') {
	while (*p && *p!=']')
	    p++;
	if (*p)
	    p++;
	linelim = p-line;
	tokenst = NULL;
	return yylex();
    } else ret = *p++;
    linelim = p-line;
    if (!isfunc) isfunc = ((ret == '@') + (ret == S_GOTO) - (ret == S_SET));
    if (ret == S_GOTO) isgoto = TRUE;
    tokenst = NULL;
    return ret;
}
Exemple #16
0
void
add_range(char *name, struct ent_ptr left, struct ent_ptr right, int is_range)
{
    struct range *r;
    register char *p;
    int minr, minc, maxr, maxc;
    int minrf, mincf, maxrf, maxcf;
    register struct ent *rcp;
    struct range *prev = 0;

    if (left.vp->row < right.vp->row) {
	minr = left.vp->row; minrf = left.vf & FIX_ROW;
	maxr = right.vp->row; maxrf = right.vf & FIX_ROW;
    } else {
	minr = right.vp->row; minrf = right.vf & FIX_ROW;
	maxr = left.vp->row; maxrf = right.vf & FIX_ROW;
    } 

    if (left.vp->col < right.vp->col) {
	minc = left.vp->col; mincf = left.vf & FIX_COL;
	maxc = right.vp->col; maxcf = right.vf & FIX_COL;
    } else {
	minc = right.vp->col; mincf = right.vf & FIX_COL;
	maxc = left.vp->col; maxcf = left.vf & FIX_COL;
    } 

    left.vp = lookat(minr, minc);
    left.vf = minrf | mincf;
    right.vp = lookat(maxr, maxc);
    right.vf = maxrf | maxcf;

    if (!find_range(name, strlen(name), (struct ent *)0, (struct ent *)0,
	    &prev)) {
	error("Error: range name \"%s\" already defined", name);
	scxfree(name);
	return;
    }

    for (p = name; *p; p++)
	if (!(isalpha(*p) || isdigit(*p) || *p == '_')) {
	    error("Invalid range name \"%s\" - illegal combination", name);
	    scxfree(name);
	    return;
	}
 
    p = name;
    if (isdigit(*p) || (isalpha(*p++) && (isdigit(*p) ||
		(isalpha(*p++) && isdigit(*p))))) {
	if (*name == '0' && (name[1] == 'x' || name[1] == 'X')) {
	    ++p;
	    while (isxdigit(*++p)) /* */;
	    if (*p == 'p' || *p == 'P')
		while (isxdigit(*++p)) /* */;
	} else {
	    while (isdigit(*++p)) /* */;
	    if (isdigit(*name) && (*p == 'e' || *p == 'E'))
		while (isdigit(*++p)) /* */;
	}
	if (!(*p)) {
	    error("Invalid range name \"%s\" - ambiguous", name);
	    scxfree(name);
	    return;
	}
    }
 
    if (autolabel && minc>0 && !is_range) {
	rcp = lookat(minr, minc-1);
	if (rcp->label==0 && rcp->expr==0 && rcp->v==0)
		label(rcp, name, 0);
    }

    r = (struct range *)scxmalloc((unsigned)sizeof(struct range));
    r->r_name = name;
    r->r_left = left;
    r->r_right = right;
    r->r_is_range = is_range;
    if (prev) {
	r->r_next = prev->r_next;
	r->r_prev = prev;
	prev->r_next = r;
	if (r->r_next)
	    r->r_next->r_prev = r;
    } else {
	r->r_next = rng_base;
	r->r_prev = (struct range *)0;
	if (rng_base)
	    rng_base->r_prev = r;
	rng_base = r;
    }
    modflg++;
}
Exemple #17
0
void
add_abbr(char *string)
{
    struct abbrev *a;
    register char *p;
    struct abbrev *prev = NULL;
    char *expansion;
    
    if (!string || *string == '\0') {
	if (!are_abbrevs()) {
	    error("No abbreviations defined");
	    return;
	} else {
	    FILE *f;
	    int pid;
	    char px[MAXCMD];
	    char *pager;
	    struct abbrev *a;
	    struct abbrev *nexta;

	    strlcpy(px, "| ", sizeof px);
	    if (!(pager = getenv("PAGER")))
		pager = DFLT_PAGER;
	    strlcat(px, pager, sizeof px);
	    f = openfile(px, sizeof px, &pid, NULL);
	    if (!f) {
		error("Can't open pipe to %s", pager);
		return;
	    }
	    (void) fprintf(f, "\n%-15s %s\n","Abbreviation","Expanded");
	    if (!brokenpipe) (void) fprintf(f, "%-15s %s\n", "------------",
		    "--------");

	    for (a = nexta = abbr_base; nexta; a = nexta, nexta = a->a_next)
		;
	    while (a) {
		(void) fprintf(f, "%-15s %s\n", a->abbr, a->exp);
		if (brokenpipe) return;
		a = a->a_prev;
	    }
	    closefile(f, pid, 0);
	    return;
	}
    }

    if ((expansion = strchr(string, ' ')))
	*expansion++ = '\0';

    if (isalpha((int)*string) || isdigit((int)*string) || *string == '_') {
	for (p = string; *p; p++)
	    if (!(isalpha((int)*p) || isdigit((int)*p) || *p == '_')) {
		error("Invalid abbreviation: %s", string);
		scxfree(string);
		return;
	    }
    } else {
	for (p = string; *p; p++)
	    if ((isalpha((int)*p) || isdigit((int)*p) || *p == '_') && *(p+1)) {
		error("Invalid abbreviation: %s", string);
		scxfree(string);
		return;
	    }
    }
    
    if (expansion == NULL) {
	if ((a = find_abbr(string, strlen(string), &prev))) {
	    error("abbrev \"%s %s\"", a->abbr, a->exp);
	    return;
	} else {
	    error("abreviation \"%s\" doesn't exist", string);
	    return;
	}
    }

    if (find_abbr(string, strlen(string), &prev))
	del_abbr(string);

    a = scxmalloc(sizeof(struct abbrev));
    a->abbr = string;
    a->exp = expansion;

    if (prev) {
	a->a_next = prev->a_next;
	a->a_prev = prev;
	prev->a_next = a;
	if (a->a_next)
	    a->a_next->a_prev = a;
    } else {
	a->a_next = abbr_base;
	a->a_prev = NULL;
	if (abbr_base)
	    abbr_base->a_prev = a;
	abbr_base = a;
    }
}
Exemple #18
0
void sortrange (struct ent *left, struct ent *right, char *criteria)
{
    int minr, minc, maxr, maxc, r, c;
    int *rows, col = 0;
    int cp = 0;
    struct ent *p;

    minr = left->row < right->row ? left->row : right->row;
    minc = left->col < right->col ? left->col : right->col;
    maxr = left->row > right->row ? left->row : right->row;
    maxc = left->col > right->col ? left->col : right->col;

    sort = (struct sortcrit *)scxmalloc((2 * sizeof(struct sortcrit)));
    rows = (int *)scxmalloc((maxr - minr + 1) * sizeof(int));
    for (r = minr, c = 0; r <= maxr; r++, c++)
	rows[c] = r;

    if (!criteria) {
	sort[0].direction = 1;
	sort[0].type = 1;
	sort[0].column = minc;
	sort[1].direction = 1;
	sort[1].type = 0;
	sort[1].column = minc;
	howmany = 2;
    } else {
	for (howmany = 0; criteria[cp]; howmany++) {
	    if (howmany > 1)
		sort = (struct sortcrit *)scxrealloc((char *)sort,
			(howmany + 1) * (sizeof(struct sortcrit)));
	    switch (criteria[cp++]) {
		case '+':
		    sort[howmany].direction = 1;
		    break;
		case '-':
		    sort[howmany].direction = -1;
		    break;
		default:
		    error("Invalid sort criteria");
		    return;
	    }
	    switch (criteria[cp++]) {
		case '#':
		    sort[howmany].type = 0;
		    break;
		case '$':
		    sort[howmany].type = 1;
		    break;
		default:
		    error("Invalid sort criteria");
		    return;
	    }
	    if (criteria[cp])
		col = toupper(criteria[cp++]) - 'A';
	    else {
		error("Invalid sort criteria");
		return;
	    }
	    if (criteria[cp] && criteria[cp] != '+' && criteria[cp] != '-')
		col = (col + 1) * 26 + toupper(criteria[cp++]) - 'A';
	    sort[howmany].column = col;
	    if (col < minc || col > maxc) {
		error("Invalid sort criteria");
		return;
	    }
	}
    }

    qsort(rows, maxr - minr + 1, sizeof(int), compare);
    erase_area(minr, minc, maxr, maxc, 1);
    sync_ranges();
    for (c = 0, p = delbuf[dbidx]; p; p = p->next) {
	if (rows[c] != p->row) {
	    for (c = 0; c <= maxr - minr && rows[c] != p->row; c++) ;
	    if (c > maxr - minr) {
		error("sort error");
		return;
	    }
	}
	p->row = minr + c;
    }
    scxfree((char *)sort);
    scxfree((char *)rows);
    if (criteria) scxfree(criteria);

    r = currow;
    c = curcol;
    currow = minr;
    curcol = minc;

    pullcells('m');
    flush_saved();

    currow = r;
    curcol = c;
}