Exemplo n.º 1
0
/* The output function for an ELF hash table. The hash table is an
 * array of 32-bit values. The first two array elements indicate the
 * length of the following subsections. Line breaks are inserted to
 * indicate where the subsections start and end.
 */
static void outhashtable(void const *ptr, long size, int ndx)
{
    Elf64_Word const *entries = ptr;
    long count = size / sizeof *entries;
    long i;

    (void)ndx;
    beginblock(TRUE);
    if (count <= 2 || (long)(entries[0] + entries[1] + 2) != count) {
	for (i = 0 ; i < count ; ++i)
	    outdec(entries[i]);
    } else {
	outdec(entries[0]);
	outdec(entries[1]);
	linebreak();
	i = 2;
	if (entries[0] > 0) {
	    for ( ; i < (long)(2 + entries[0]) ; ++i)
		outdec(entries[i]);
	    linebreak();
	}
	for ( ; i < count ; ++i)
	    outdec(entries[i]);
    }
    endblock();
}
Exemplo n.º 2
0
/*
 * NAME:	cmdbuf->shift()
 * DESCRIPTION:	shift a range of lines left or right
 */
static int cb_shift(cmdbuf *cb)
{
    cb_do(cb, cb->first);
    startblock(cb);
    cb->lineno = cb->first - 1;
    cb->flags |= CB_CHANGE;
    eb_range(cb->edbuf, cb->first, cb->last, shift, FALSE);
    endblock(cb);

    return RET_FLAGS;
}
Exemplo n.º 3
0
/*
 * NAME:	shift()
 * DESCRIPTION:	shift a line left or right
 */
static void shift(const char *text)
{
    cmdbuf *cb;
    int idx;

    cb = ccb;

    /* first determine the number of leading spaces */
    idx = 0;
    while (*text == ' ' || *text == HT) {
	if (*text++ == ' ') {
	    idx++;
	} else {
	    idx = (idx + 8) & ~7;
	}
    }

    if (*text == '\0') {
	/* don't shift lines with ws only */
	addblock(cb, text);
	cb->lineno++;
    } else {
	idx += cb->shift;
	if (idx < MAX_LINE_SIZE) {
	    char buffer[MAX_LINE_SIZE];
	    char *p;

	    p = buffer;
	    /* fill with leading ws */
	    while (idx >= 8) {
		*p++ = HT;
		idx -= 8;
	    }
	    while (idx > 0) {
		*p++ = ' ';
		--idx;
	    }
	    if (p - buffer + strlen(text) < MAX_LINE_SIZE) {
		strcpy(p, text);
		addblock(cb, buffer);
		cb->lineno++;
		return;
	    }
	}

	/* Error: line too long. Finish block of lines already shifted. */
	cb->last = cb->lineno;
	endblock(cb);
	error("Result of shift would be too long");
    }
}
Exemplo n.º 4
0
/* The output function for pieces of type P_UNCLAIMED, P_SECTION,
 * P_BYTES, or P_STRINGS. The contents are output either as a literal
 * string, an array of character values, or an array of hexadecimal
 * byte values. The last will be used if the contents contain an
 * excess of non-graphic, non-ASCII characters. Otherwise, one of the
 * first two representations will be selected based on whether or not
 * the contents appear to be null-terminated.
 */
static void outbytes(void const *ptr, long size, int ndx)
{
    unsigned char const *bytes = ptr;
    long zeroes, n;
    long i;

    (void)ndx;
    for (zeroes = 0 ; zeroes < size && !bytes[size - zeroes - 1] ; ++zeroes) ;
    if (zeroes == size) {
	out("{ 0 }");
	return;
    }
    if (zeroes < 255 || zeroes * 4 < size)
	zeroes = 0;
    zeroes &= ~7;

    n = outstringsize((signed char const*)bytes, size);

    if (n * 2 > size * 3) {
	beginblock(TRUE);
	for (i = 0 ; i < size - zeroes ; ++i)
	    outf("0x%02X", bytes[i]);
	if (zeroes)
	    outcomment(strf("0x00 x %d", zeroes));
	endblock();
    } else if (zeroes || bytes[size - 1]) {
	beginblock(TRUE);
	for (i = 0 ; i < size - zeroes ; ++i)
	    outchar(bytes[i]);
	if (zeroes)
	    outcomment(strf("0x00 x %ld", zeroes));
	endblock();
    } else {
	outstring((char const*)bytes, size - 1);
    }
}
Exemplo n.º 5
0
/*
 * NAME:	sub()
 * DESCRIPTION:	add a string to the current substitute buffer
 */
static void sub(cmdbuf *cb, const char *text, unsigned int size)
{
    char *p;
    const char *q;
    unsigned int i;

    i = size;
    if (cb->buflen + i >= MAX_LINE_SIZE) {
	if (cb->flags & CB_CURRENTBLK) {
	    /* finish already processed block */
	    endblock(cb);
	}
	cb->cthis = cb->othis = cb->lineno;
	error("Line overflow in substitute");
    }

    p = cb->buffer + cb->buflen;
    q = text;
    if (cb->flags & CB_TLOWER) {	/* lowercase one letter */
	*p++ = tolower(*q);
	q++;
	cb->flags &= ~CB_TLOWER;
	--i;
    } else if (cb->flags & CB_TUPPER) {	/* uppercase one letter */
	*p++ = toupper(*q);
	q++;
	cb->flags &= ~CB_TUPPER;
	--i;
    }

    if (cb->flags & CB_LOWER) {		/* lowercase string */
	while (i > 0) {
	    *p++ = tolower(*q);
	    q++;
	    --i;
	}
    } else if (cb->flags & CB_UPPER) {		/* uppercase string */
	while (i > 0) {
	    *p++ = toupper(*q);
	    q++;
	    --i;
	}
    } else if (i > 0) {		/* don't change case */
	memcpy(p, q, i);
    }
    cb->buflen += size;
}
Exemplo n.º 6
0
/* The GNU hash table is an array of 32-bit values. (Although in a
 * 64-bit ELF file the mask subpart consists of 64-bit values. But an
 * array cannot change its type midway through, so in this case the
 * mask values are split across two array entries.)
 */
static void outgnuhash(void const *ptr, long size, int ndx)
{
    Elf64_Word const *entries = ptr;
    long count = size / sizeof *entries;
    int buckets, masks;
    int i, n;

    (void)ndx;
    if (count < 4) {
	outwords(ptr, size, ndx);
	return;
    }
    buckets = entries[0];
    masks = entries[2];
    if (iself64())
	masks *= 2;
    if (4 + masks + buckets > count) {
	outwords(ptr, size, ndx);
	return;
    }

    beginblock(TRUE);
    for (i = 0 ; i < 4 ; ++i)
	outdec(entries[i]);
    n = i;
    if (masks) {
	linebreak();
	for (i = 0 ; i < masks ; ++i)
	    outf("0x%08lX", entries[n + i]);
	n += i;
    }
    if (buckets) {
	linebreak();
	for (i = 0 ; i < buckets ; ++i)
	    outdec(entries[n + i]);
	n += i;
    }
    if (n < count) {
	linebreak();
	for (i = n ; i < count ; ++i)
	    outf("0x%08lX", entries[i]);
    }
    endblock();
}
Exemplo n.º 7
0
/* The output function for an array of 64-bit values.
 */
static void outxwords(void const *ptr, long size, int ndx)
{
    Elf64_Xword const *xwords = ptr;
    long count = size / sizeof *xwords;
    char fmtbuf[16];
    char const *fmt = NULL;
    unsigned long max;
    long zeroes, i;

    (void)ndx;
    for (zeroes = 0 ; zeroes < count ; ++zeroes)
	if (xwords[count - zeroes - 1])
	    break;
    if (zeroes == count) {
	out("{ 0 }");
	return;
    }
    if (zeroes < 255 || zeroes * 4 < count)
	zeroes = 0;
    zeroes &= ~3;
    count -= zeroes;

    max = 0;
    for (i = 0 ; i < count ; ++i) {
	if (max < xwords[i])
	    max = xwords[i];
    }
    fmt = max > 0xFFFFFFFF ? "0x%016lX" :
	  max > 0x0000FFFF ? "0x%08lX"  :
	  max > 0x000000FF ? "0x%04lX"  : max > 99 ? "0x%02lX" : "%lu";

    beginblock(TRUE);
    for (i = 0 ; i < count ; ++i)
	outf(fmt, xwords[i]);
    if (zeroes) {
	sprintf(fmtbuf, "%s x %%ld", fmt);
	outcomment(strf(fmtbuf, 0, zeroes));
    }
    endblock();
}
Exemplo n.º 8
0
/* The output function for note sections. The format of a note section
 * varies with the type of note, the only constant part being that it
 * starts with an Elf*_Nhdr struct, and is usually followed by a
 * string. However, each subpart is guaranteed to be a multiple of 4
 * bytes, so notes are displayed as arrays of 32-bit values. Line
 * breaks are inserted to indicate the beginning of a note header.
 * Note sections in core files are rather different, so in that case a
 * completely different function is called instead.
 */
void outnote(void const *ptr, long size, int ndx)
{
    Elf64_Word const *words = ptr;
    long count = size / sizeof *words;
    long i;
    int namesize, descsize, tag;

    (void)ndx;
    if (iscorefile()) {
	iself64() ? outnote64(ptr, size, ndx)
		  : outnote32(ptr, size, ndx);
	return;
    }

    beginblock(TRUE);
    i = 0;
    while (i < count) {
	namesize = (words[i] + 3) / 4;
	descsize = (words[i + 1] + 3) / 4;
	linebreak();
	outdec(words[i++]);
	outdec(words[i++]);
	tag = words[i++];
	outdefint(tag, "NT_GNU_");
	while (namesize-- && i < count)
	    outhex(words[i++]);
	if (descsize == 0)
	    continue;
#ifdef NT_GNU_ABI_TAG
	if (tag == NT_GNU_ABI_TAG) {
	    outdefint(words[i++], "ELF_NOTE_OS_");
	    --descsize;
	}
#endif
	while (descsize-- && i < count)
	    outhex(words[i++]);
    }
    endblock();
}
Exemplo n.º 9
0
/* The output function for an array of 16-bit values. The values are
 * printed in hexadecimal unless they are all relatively small.
 */
static void outhalves(void const *ptr, long size, int ndx)
{
    Elf64_Half const *halves = ptr;
    long count = size / sizeof *halves;
    char fmtbuf[16];
    char const *fmt = NULL;
    unsigned int max;
    long zeroes, i;

    (void)ndx;
    for (zeroes = 0 ; zeroes < count ; ++zeroes)
	if (halves[count - zeroes - 1])
	    break;
    if (zeroes == count) {
	out("{ 0 }");
	return;
    }
    if (zeroes < 255 || zeroes * 4 < count)
	zeroes = 0;
    zeroes &= ~3;
    count -= zeroes;

    max = 0;
    for (i = 0 ; i < count ; ++i) {
	if (max < halves[i])
	    max = halves[i];
    }
    fmt = max > 0xFF ? "0x%04X" : max > 99 ? "0x%02X" : "%u";

    beginblock(TRUE);
    for (i = 0 ; i < count ; ++i)
	outf(fmt, halves[i]);
    if (zeroes) {
	sprintf(fmtbuf, "%s x %%ld", fmt);
	outcomment(strf(fmtbuf, 0, zeroes));
    }
    endblock();
}
Exemplo n.º 10
0
/*
 * NAME:	cmdbuf->indent()
 * DESCRIPTION:	indent a range of lines
 */
int cb_indent(cmdbuf *cb)
{
    char s[STACKSZ];
    int i[STACKSZ];

    /* setup stacks */
    cb->stackbot = s;
    cb->stack = s + STACKSZ - 1;
    cb->stack[0] = EOT;
    cb->ind = i + STACKSZ - 1;
    cb->ind[0] = 0;
    cb->quote = '\0';

    cb_do(cb, cb->first);
    startblock(cb);
    cb->lineno = cb->first - 1;
    cb->flags |= CB_CHANGE;
    cb->flags &= ~(CB_PPCONTROL | CB_COMMENT | CB_JSKEYWORD);
    eb_range(cb->edbuf, cb->first, cb->last, indent, FALSE);
    endblock(cb);

    return 0;
}
Exemplo n.º 11
0
/*
 * NAME:	cmdbuf->join()
 * DESCRIPTION:	join a range of lines in the edit buffer
 */
int cb_join(cmdbuf *cb)
{
    char buf[MAX_LINE_SIZE + 1];
    Int *m;

    if (cb->edbuf->lines == 0) {
	error("No lines in buffer");
    }
    if (cb->first < 0) {
	cb->first = cb->cthis;
    }
    if (cb->last < 0) {
	cb->last = (cb->first == cb->edbuf->lines) ? cb->first : cb->first + 1;
    }

    cb_do(cb, cb->first);

    cb->cthis = cb->othis = cb->first;
    buf[0] = '\0';
    cb->buffer = buf;
    cb->buflen = 0;
    eb_range(cb->edbuf, cb->first, cb->last, join, FALSE);

    /* erase marks for joined lines */
    for (m = cb->mark; m < &cb->mark[26]; m++) {
	if (*m > cb->first && *m <= cb->last) {
	    *m = 0;
	}
    }

    cb->flags |= CB_CHANGE;
    startblock(cb);
    addblock(cb, buf);
    endblock(cb);

    return RET_FLAGS;
}
Exemplo n.º 12
0
/*
 * NAME:	subst()
 * DESCRIPTION:	do substitutions in a line. If something is substituted on line
 *		N, and the next substitution happens on line N + 2, line N + 1
 *		is joined in the new block also.
 */
static void subst(const char *text)
{
    char line[MAX_LINE_SIZE];
    cmdbuf *cb;
    int idx, size;
    char *p;
    Int *k, *l;
    Int newlines;
    bool found;

    cb = ccb;

    found = FALSE;
    newlines = 0;
    idx = 0;

    /*
     * Because the write buffer might be flushed, and the text would
     * not remain in memory, use a local copy.
     */
    text = strcpy(line, text);
    while (rx_exec(cb->regexp, text, idx, IGNORECASE(cb->vars)) > 0) {
	if (cb->flags & CB_SKIPPED) {
	    /*
	     * add the previous line, in which nothing was substituted, to
	     * the block. Has to be done here, before the contents of the buffer
	     * are changed.
	     */
	    addblock(cb, cb->buffer);
	    cb->flags &= ~CB_SKIPPED;
	    /*
	     * check if there were newlines in the last substitution. If there
	     * are, marks on the previous line (without substitutions) will
	     * also have to be changed.
	     */
	    if (cb->offset > 0) {
		for (k = cb->mark, l = cb->moffset; k < &cb->mark[26]; k++, l++)
		{
		    if (*k == cb->lineno - 1 && *l == 0) {
			*l = *k + cb->offset;
		    }
		}
	    }
	}
	found = TRUE;
	cb->flags &= ~(CB_UPPER | CB_LOWER | CB_TUPPER | CB_TLOWER);
	size = cb->regexp->start - text - idx;
	if (size > 0) {
	    /* copy first unchanged part of line to buffer */
	    sub(cb, text + idx, size);
	}
	p = cb->replace;
	while (*p != '\0') {
	    switch (*p) {
	    case '&':
		/* insert matching string */
		sub(cb, cb->regexp->start, cb->regexp->size);
		break;

	    case '\\':		/* special substitute characters */
		switch (*++p) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		    /* insert subexpression between \( \) */
		    if (cb->regexp->se[*p - '1'].start != (char*) NULL) {
			sub(cb, cb->regexp->se[*p - '1'].start,
			    cb->regexp->se[*p - '1'].size);
			break;
		    }
		    /* if no subexpression, fall though */
		default:
		    sub(cb, p, 1);	/* ignore preceding backslash */
		    break;

		case 'n':
		    cb->buffer[cb->buflen++] = '\0';
		    newlines++;		/* insert newline */
		    break;

		case 'U':
		    /* convert string to uppercase */
		    cb->flags |= CB_UPPER;
		    cb->flags &= ~(CB_LOWER | CB_TUPPER | CB_TLOWER);
		    break;

		case 'L':
		    /* convert string to lowercase */
		    cb->flags |= CB_LOWER;
		    cb->flags &= ~(CB_UPPER | CB_TUPPER | CB_TLOWER);
		    break;

		case 'e':
		case 'E':
		    /* end case conversion */
		    cb->flags &= ~(CB_UPPER | CB_LOWER | CB_TUPPER | CB_TLOWER);
		    break;

		case 'u':
		    /* convert char to uppercase */
		    cb->flags |= CB_TUPPER;
		    cb->flags &= ~CB_TLOWER;
		    break;

		case 'l':
		    /* convert char to lowercase */
		    cb->flags &= ~CB_TUPPER;
		    cb->flags |= CB_TLOWER;
		    break;

		case '\0':	/* sigh */
		    continue;
		}
		break;

	    default:		/* normal char */
		sub(cb, p, 1);
		break;
	    }
	    p++;
	}

	idx = cb->regexp->start + cb->regexp->size - text;
	if (!(cb->flags & CB_GLOBSUBST) || text[idx] == '\0' ||
	    (cb->regexp->size == 0 && text[++idx] == '\0')) {
	    break;
	}
    }

    if (found) {
	if (text[idx] != '\0') {
	    /* concatenate unchanged part of line after found pattern */
	    cb->flags &= ~(CB_UPPER | CB_LOWER | CB_TUPPER | CB_TLOWER);
	    sub(cb, text + idx, strlen(text + idx));
	}
	if (!(cb->flags & CB_CURRENTBLK)) {
	    /* start a new block of lines with substitutions in them */
	    cb->flags |= CB_CHANGE;
	    cb->first = cb->lineno;
	    startblock(cb);
	    cb->flags |= CB_CURRENTBLK;
	}
	/* add this changed line to block */
	cb->buffer[cb->buflen] = '\0';
	if (newlines == 0) {
	    addblock(cb, cb->buffer);
	} else {
	    /*
	     * There were newlines in the substituted string. Add all
	     * lines to the current block, and save the marks in range.
	     */
	    p = cb->buffer;
	    do {
		addblock(cb, p);
		p += strlen(p) + 1;
	    } while (p <= cb->buffer + cb->buflen);

	    for (k = cb->mark, l = cb->moffset; k < &cb->mark[26]; k++, l++) {
		if (*k == cb->lineno && *l == 0) {
		    *l = *k + cb->offset;
		}
	    }
	    cb->offset += newlines;
	}
	cb->buflen = 0;
	cb->last = cb->lineno;
    } else {
	if (cb->flags & CB_SKIPPED) {
	    /* two lines without substitutions now. Finish previous block. */
	    endblock(cb);
	    cb->lineno += cb->offset;
	    cb->offset = 0;
	    cb->flags &= ~(CB_CURRENTBLK | CB_SKIPPED);
	} else if (cb->flags & CB_CURRENTBLK) {
	    /*
	     * no substitution on this line, but there was one on the previous
	     * line. mark this line as skipped, so it can still be added to
	     * the block of changed lines if the next line has substitutions.
	     */
	    strcpy(cb->buffer, text);
	    cb->flags |= CB_SKIPPED;
	}
    }
    cb->lineno++;
}
Exemplo n.º 13
0
/*
 * NAME:	indent()
 * DESCRIPTION:	Parse and indent a line of text. This isn't perfect, as
 *		keywords could be defined as macros, comments are very hard to
 *		handle properly, (, [ and ({ will match any of ), ] and }),
 *		and last but not least everyone has his own taste of
 *		indentation.
 */
static void indent(const char *text)
{
    static char f[] = { 7, 1, 7, 1, 2, 1, 6, 4, 2, 6, 7, 2, 0, };
    static char g[] = { 2, 2, 1, 7, 1, 5, 1, 3, 6, 2, 2, 2, 0, };
    char ident[MAX_LINE_SIZE];
    char line[MAX_LINE_SIZE];
    cmdbuf *cb;
    const char *p;
    char *sp;
    int *ip, idx;
    int top, token;
    const char *start;
    bool do_indent;

    cb = ccb;

    do_indent = FALSE;
    idx = 0;
    p = text = strcpy(line, text);

    /* process status vars */
    if (cb->quote != '\0') {
	cb->shift = 0;	/* in case a comment starts on this line */
	noshift(cb, p);
    } else if ((cb->flags & CB_PPCONTROL) || *p == '#') {
	noshift(cb, p);
	while (*p != '\0') {
	    if (*p == '\\' && *++p == '\0') {
		cb->flags |= CB_PPCONTROL;
		return;
	    }
	    p++;
	}
	cb->flags &= ~CB_PPCONTROL;
	return;
    } else {
	/* count leading ws */
	while (*p == ' ' || *p == HT) {
	    if (*p++ == ' ') {
		idx++;
	    } else {
		idx = (idx + 8) & ~7;
	    }
	}
	if (*p == '\0') {
	    noshift(cb, p);
	    return;
	} else if (cb->flags & CB_COMMENT) {
	    shift(text);	/* use previous shift */
	} else {
	    do_indent = TRUE;
	}
    }

    /* process this line */
    start = p;
    while (*p != '\0') {

	/* lexical scanning: find the next token */
	ident[0] = '\0';
	if (cb->flags & CB_COMMENT) {
	    /* comment */
	    while (*p != '*') {
		if (*p == '\0') {
		    return;
		}
		p++;
	    }
	    while (*p == '*') {
		p++;
	    }
	    if (*p == '/') {
		cb->flags &= ~CB_COMMENT;
		p++;
	    }
	    continue;

	} else if (cb->quote != '\0') {
	    /* string or character constant */
	    for (;;) {
		if (*p == cb->quote) {
		    cb->quote = '\0';
		    p++;
		    break;
		} else if (*p == '\0') {
		    cb->last = cb->lineno;
		    endblock(cb);
		    error("Unterminated string");
		} else if (*p == '\\' && *++p == '\0') {
		    break;
		}
		p++;
	    }
	    token = TOKEN;

	} else {
	    switch (*p++) {
	    case ' ':	/* white space */
	    case HT:
		continue;

	    case '\'':	/* start of string */
	    case '"':
		cb->quote = p[-1];
		continue;

	    case '/':
		if (*p == '*') {	/* start of comment */
		    cb->flags |= CB_COMMENT;
		    if (do_indent) {
			/* this line hasn't been indented yet */
			cb->shift = cb->ind[0] - idx;
			shift(text);
			do_indent = FALSE;
		    } else {
			const char *q;
			int idx2;

			/*
			 * find how much the comment has shifted, so the same
			 * shift can be used if the comment continues on the
			 * next line
			 */
			idx2 = cb->ind[0];
			for (q = start; q < p - 1;) {
			    if (*q++ == HT) {
				idx = (idx + 8) & ~7;
				idx2 = (idx2 + 8) & ~7;
			    } else {
				idx++;
				idx2++;
			    }
			}
			cb->shift = idx2 - idx;
		    }
		    p++;
		    continue;
		}
		token = TOKEN;
		break;

	    case '{':
		token = LBRACKET;
		break;

	    case '(':
		if (cb->flags & CB_JSKEYWORD) {
		    /*
		     * LOPERATOR & ROPERATOR are a kludge. The operator
		     * precedence parser that is used could not work if
		     * parenthesis after keywords was not treated specially.
		     */
		    token = LOPERATOR;
		    break;
		}
		if (*p == '{') {
		    p++;	/* ({ is one token */
		}
	    case '[':
		token = LHOOK;
		break;

	    case '}':
		if (*p != ')') {
		    token = RBRACKET;
		    break;
		}
		p++;
		/* }) is one token; fall through */
	    case ')':
	    case ']':
		token = RHOOK;
		break;

	    case ';':
		token = SEMICOLON;
		break;

	    default:
		if (isalpha(*--p) || *p == '_') {
		    char *q;

		    /* Identifier. See if it's a keyword. */
		    q = ident;
		    do {
			*q++ = *p++;
		    } while (isalnum(*p) || *p == '_');
		    *q = '\0';

		    if      (strcmp(ident, "if") == 0)		token = IF;
		    else if (strcmp(ident, "else") == 0)	token = ELSE;
		    else if (strcmp(ident, "for") == 0 ||
			     strcmp(ident, "while") == 0 ||
			     strcmp(ident, "rlimits") == 0)	token = FOR;
		    else if (strcmp(ident, "do") == 0)		token = DO;
		    else    /* not a keyword */			token = TOKEN;
		} else {
		    /* anything else is a "token" */
		    p++;
		    token = TOKEN;
		}
		break;
	    }
	}

	/* parse */
	sp = cb->stack;
	ip = cb->ind;
	for (;;) {
	    top = *sp;
	    if (top == LOPERATOR && token == RHOOK) {
		/* ) after LOPERATOR is ROPERATOR */
		token = ROPERATOR;
	    }

	    if (f[top] <= g[token]) {	/* shift the token on the stack */
		int i;

		if (sp == cb->stackbot) {
		    /* out of stack. Finish already indented block. */
		    cb->last = cb->lineno;
		    endblock(cb);
		    error("Nesting too deep");
		}

		/* handle indentation */
		i = *ip;
		/* if needed, reduce indentation prior to shift */
		if ((token == LBRACKET &&
		  (*sp == ROPERATOR || *sp == ELSE || *sp == DO)) ||
		  token == RBRACKET ||
		  (token == IF && *sp == ELSE)) {
		    /* back up */
		    i -= SHIFTWIDTH(cb->vars);
		}
		/* shift the current line, if appropriate */
		if (do_indent) {
		    cb->shift = i - idx;
		    if (i > 0 && token != RHOOK &&
		      (*sp == LOPERATOR || *sp == LHOOK)) {
			/* half indent after ( [ ({ (HACK!) */
			cb->shift += SHIFTWIDTH(cb->vars) / 2;
		    } else if (token == TOKEN && *sp == LBRACKET &&
		      (strcmp(ident, "case") == 0 ||
		      strcmp(ident, "default") == 0)) {
			/* back up if this is a switch label */
			cb->shift -= SHIFTWIDTH(cb->vars);
		    }
		    shift(text);
		    do_indent = FALSE;
		}
		/* change indentation after current token */
		if (token == LBRACKET || token == ROPERATOR || token == ELSE ||
		  token == DO) {
		    /* add indentation */
		    i += SHIFTWIDTH(cb->vars);
		} else if (token == SEMICOLON &&
		  (*sp == ROPERATOR || *sp == ELSE)) {
		    /* in case it is followed by a comment */
		    i -= SHIFTWIDTH(cb->vars);
		}

		*--sp = token;
		*--ip = i;
		break;
	    }

	    /* reduce handle */
	    do {
		top = *sp++;
		ip++;
	    } while (f[*sp] >= g[top]);
	}
	cb->stack = sp;
	cb->ind = ip;
	if (token >= IF) {	/* but not ELSE */
	    cb->flags |= CB_JSKEYWORD;
	} else {
	    cb->flags &= ~CB_JSKEYWORD;
	}
    }
}
Exemplo n.º 14
0
/*
 * NAME:	cmdbuf->substitute()
 * DESCRIPTION:	do substitutions on a range of lines
 */
int cb_subst(cmdbuf *cb)
{
    char buf[MAX_LINE_SIZE], delim;
    Int m[26];
    Int edit;
    const char *p;
    Int *k, *l;

    delim = cb->cmd[0];
    if (delim == '\0' || strchr("0123456789gpl#-+", delim) != (char*) NULL) {
	/* no search pattern & replace string specified */
	if (cb->search[0] == '\0') {
	    error("No previous substitute to repeat");
	}
    } else if (!isalpha(delim)) {
	char *q;

	/* get search pattern */
	p = pattern(cb->cmd + 1, delim, cb->search);
	/* get replace string */
	q = cb->replace;
	while (*p != '\0') {
	    if (*p == delim) {
		p++;
		break;
	    }
	    if (q == cb->replace + STRINGSZ - 1) {
		cb->search[0] = '\0';
		error("Replace string too large");
	    }
	    if ((*q++ = *p++) == '\\' && *p != '\0') {
		*q++ = *p++;
	    }
	}
	*q = '\0';
	cb->cmd = p;
    } else {
	/* cause error */
	cb->search[0] = '\0';
    }

    if (cb->search[0] == '\0') {
	error("Missing regular expression for substitute");
    }

    /* compile regexp */
    p = rx_comp(cb->regexp, cb->search);
    if (p != (char *) NULL) {
	error(p);
    }

    cb_count(cb);	/* get count */
    /* handle global flag */
    if (cb->cmd[0] == 'g') {
	cb->flags |= CB_GLOBSUBST;
	cb->cmd++;
    } else {
	cb->flags &= ~CB_GLOBSUBST;
    }

    /* make a blank mark table */
    cb->moffset = m;
    for (l = m; l < &m[26]; ) {
	*l++ = 0;
    }
    cb->offset = 0;

    /* do substitutions */
    cb_do(cb, cb->first);
    cb->lineno = cb->first;
    edit = cb->edit;
    cb->buffer = buf;
    cb->buflen = 0;
    cb->flags &= ~(CB_CURRENTBLK | CB_SKIPPED);
    eb_range(cb->edbuf, cb->first, cb->last, subst, FALSE);
    if (cb->flags & CB_CURRENTBLK) {
	/* finish current block, if needed */
	endblock(cb);
    }

    cb->othis = cb->uthis;
    if (edit != cb->edit) {
	/* some marks may have been messed up. fix them */
	for (l = m, k = cb->mark; l < &m[26]; l++, k++) {
	    if (*l != 0) {
		*k = *l;
	    }
	}
    } else if (!(cb->flags & CB_GLOBAL)) {
	error("Substitute pattern match failed");
    }

    return RET_FLAGS;
}