v21i029: String function to do sed(1)/tr(1) manipulations, Part02/03

Rich Salz rsalz at uunet.uu.net
Sat Mar 24 06:11:11 AEST 1990


Submitted-by: Terry Jones <terry at pcsbst.pcs.com>
Posting-number: Volume 21, Issue 29
Archive-name: strsed/part02

#!/bin/sh
# this is part 2 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file strsed.c continued
#
CurArch=2
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file strsed.c"
sed 's/^X//' << 'SHAR_EOF' >> strsed.c
X                    more_space(1);
X                    new_str[new_pos++] = *tmp++;
X                }
X            }
X
X            /*
X             * Move forward over the matched text.
X             *
X             */
X            str += regs.end[0];
X            str_len -= regs.end[0];
X        }
X    } while (global && match != -1 && *str);
X
X    /*
X     * Copy the final portion of the string. This is the section that
X     * was not matched (and hence which remains unchanged) by the last
X     * match. Then we head off home.
X     *
X     */
X    more_space(str_len);
X    (void) strcpy(new_str + new_pos, str);
X    RETURN(new_str);
X}
X
X#define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
X
Xstatic char *
Xbackslash_eliminate(str, type, who)
Xchar *str;
Xint type;
Xint who;
X{
X    /*
X     * Remove backslashes from the strings. Turn \040 etc. into a single
X     * character (we allow eight bit values). Currently NUL is not
X     * allowed.
X     *
X     * Turn "\n" and "\t" into '\n' and '\t' characters. Etc.
X     *
X     * The string may grow slightly here. Under normal circumstances
X     * it will stay the same length or get shorter. It is only in the 
X     * case where we have to turn {a-z}{A-Z} into \0{a-z}{A-Z} that
X     * we add two chars. This only happens when we are doing a REPLACEMENT.
X     * So we can't overwrite str, and we have to 
X     * malloc. Sad, but the only ways I could find around it (at this
X     * late stage) were really gross. I allowed an extra 
X     * 100 bytes which should cover most idiotic behaviour.
X     * I count the extra space and exit nicely if they do do something
X     * extremely silly.
X     *
X     * 'i' is an index into new_str.
X     *
X     * 'type' tells us how to interpret escaped characters.
X     *
X     * type = REGEX 
X     *        if the pattern is a regular expression. If it is then
X     *        we leave escaped things alone (except for \n and \t and 
X     *        friends).
X     *
X     * type = REPLACEMENT
X     *        if this is a replacement pattern. In this case we change
X     *        \( and \) to ( and ), but leave \1 etc alone as they are
X     *        register references. - becomes a metacharacter between
X     *        { and }.
X     *
X     * type = NORMAL
X     *        We do \n and \t elimination, as well as \040 etc, plus
X     *        all other characters that we find quoted we unquote.
X     *        type = NORMAL when we do a backslash elimination on the
X     *        string argument to strsed.
X     *
X     * who tells us where to tell mem where to stick the new string.
X     *
X     * \{m,n\} syntax (see ed(1)) is not supported.
X     *
X     */
X
X    static char *mem();
X    char *new_str;
X    int extra = 100;
X    int seenlb = 0;
X    register int i = 0;
X    register int seenbs = 0;
X    int first_half = 0;
X
X    if (type == REPLACEMENT){
X	if (!(new_str = mem(who, strlen(str) + 1 + extra))){
X	    return 0;
X	}
X    }
X    else{
X	new_str = str;
X    }
X
X    while (*str){
X        if (seenbs){
X            seenbs = 0;
X            switch (*str){
X                case '\\':{
X                    new_str[i++] = '\\';
X                    str++;
X                    break;
X                }
X
X                case '-':{
X                    if (seenlb){
X                        /* Keep it quoted. */
X                        new_str[i++] = '\\';
X                    }
X                    new_str[i++] = '-';
X                    str++;
X                    break;
X                }
X
X                case '}':{
X                    if (seenlb){
X                        /* Keep it quoted. */
X                        new_str[i++] = '\\';
X                    }
X                    new_str[i++] = '}';
X                    str++;
X                    break;
X                }
X
X                case 'n':{
X                    new_str[i++] = '\n';
X                    str++;
X                    break;
X                }
X
X                case 't':{
X                    new_str[i++] = '\t';
X                    str++;
X                    break;
X                }
X
X                case 's':{
X                    new_str[i++] = ' ';
X                    str++;
X                    break;
X                }
X
X                case 'r':{
X                    new_str[i++] = '\r';
X                    str++;
X                    break;
X                }
X
X                case 'f':{
X                    new_str[i++] = '\f';
X                    str++;
X                    break;
X                }
X
X                case 'b':{
X                    new_str[i++] = '\b';
X                    str++;
X                    break;
X                }
X
X                case 'v':{
X                    new_str[i++] = '\13';
X                    str++;
X                    break;
X                }
X
X                case 'z':{
X                    str++;
X                    break;
X                }
X
X                case '0': case '1': case '2': case '3': case '4':
X                case '5': case '6': case '7': case '8': case '9':{
X
X                    char val;
X
X                    /*
X                     * Three digit octal constant.
X                     *
X                     */
X                    if (*str >= '0' && *str <= '3' && 
X                        *(str + 1) >= '0' && *(str + 1) <= '7' &&
X                        *(str + 2) >= '0' && *(str + 2) <= '7'){
X
X                        val = (DIGIT(*str) << 6) + 
X                              (DIGIT(*(str + 1)) << 3) + 
X                               DIGIT(*(str + 2));
X
X                        if (!val){
X                            /*
X                             * NUL is not allowed.
X                             */
X                            return 0;
X                        }
X
X                        new_str[i++] = val;
X                        str += 3;
X                        break;
X                    }
X
X                    /*
X                     * One or two digit hex constant.
X                     * If two are there they will both be taken.
X                     * Use \z to split them up if this is not wanted.
X                     *
X                     */
X                    if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X') && isxdigit(*(str + 2))){
X                        val = DIGIT(*(str + 2));
X                        if (isxdigit(*(str + 3))){
X                            val = (val << 4) + DIGIT(*(str + 3));
X                            str += 4;
X                        }
X                        else{
X                            str += 3;
X                        }
X
X                        if (!val){
X                            return 0;
X                        }
X
X                        new_str[i++] = val;
X                        break;
X                    }
X
X                    /*
X                     * Two or three decimal digits.
X                     * (One decimal digit is taken as either a register reference
X                     * or as a decimal digit if NORMAL is true below.)
X                     *
X                     */
X                    if (isdigit(*(str + 1))){
X                        val = DIGIT(*str) * 10 + DIGIT(*(str + 1));
X                        if (isdigit(*(str + 2))){
X                            val = 10 * val + DIGIT(*(str + 2));
X                            str += 3;
X                        }
X                        else{
X                            str += 2;
X                        }
X
X                        if (!val){
X                            return 0;
X                        }
X
X                        new_str[i++] = val;
X                        break;
X                    }
X
X                    /*
X                     * A register reference or else a single decimal digit if this
X                     * is a normal string..
X                     *
X                     * Emit \4 (etc) if we are not NORMAL (unless the digit is a 0 
X                     * and we are processing an r.e. This is because \0 makes no 
X                     * sense in an r.e., only in a replacement. If we do have \0 
X                     * and it is an r.e. we return.)
X                     *
X                     */
X                    if (*str == '0' && type == REGEX){
X                        return 0;
X                    }
X
X                    if (type == NORMAL){
X                        if (!(val = DIGIT(*str))){
X                            return 0;
X                        }
X                        new_str[i++] = val;
X                        str++;
X                    }
X                    else{
X                        new_str[i++] = '\\';
X                        new_str[i++] = *str++;
X                    }
X                    break;
X                }
X
X                default:{
X                    if (type == REGEX){
X                        new_str[i++] = '\\';
X                    }
X                    new_str[i++] = *str++;
X                    break;
X                }
X            }
X        }
X        else{
X            if (*str == '\\'){
X                seenbs = 1;
X                str++;
X            }
X            else if (type == REPLACEMENT && *str == '}'){
X                if (*(str + 1) == '{' && first_half){
X                    new_str[i++] = *str++;
X                    new_str[i++] = *str++;
X		    first_half = 0;
X                }
X                else{
X                    seenlb = 0;
X                    new_str[i++] = *str++;
X                }
X            }
X            else if (type == REPLACEMENT && !seenlb && *str == '{'){
X                /*
X                 * Within { and }, \- should be left as such. So we can differentiate
X                 * between s/fred/\-/ and s/fred/{\-a-z}{+A-Z}
X                 *
X                 * We stick in a "\0" here in the case that \X has not just been
X                 * seen. (X = 0..9) Which is to say, {a-z}{A-Z} defaults to 
X                 * \0{a-z}{A-Z}
X                 *
X                 */
X
X                seenlb = 1;
X		first_half = 1;
X
X                if (i < 2 || new_str[i - 2] != '\\' || !(new_str[i - 1] >= '0' && new_str[i - 1] <= '9')){
X                    if ((extra -= 2) < 0){
X                        /* ran out of extra room. */
X                        return 0;
X                    }
X                    new_str[i++] = '\\';
X                    new_str[i++] = '0';
X                }
X                new_str[i++] = *str++;
X            }
X            else{
X                /* 
X                 * A normal char.
X                 *
X                 */
X                new_str[i++] = *str++;
X            }
X        }
X    }
X
X    if (seenbs){
X        /*
X         * The final character was a '\'. Ignore it.
X         *
X         */
X    }
X
X    new_str[i] = '\0';
X    return new_str;
X}
X
Xstatic char *
Xbuild_map(s, map)
Xchar *s;
Xchar *map;
X{
X    /*
X     * Produce a mapping table for the given transliteration.
X     * We are passed something that looks like "{a-z}{A-Z}"
X     * Look out for \ chars, these are used to quote } and -.
X     *
X     * Return a pointer to the char after the closing }.
X     * We cannot clobber s.
X     *
X     * The building of maps is somewhat optimised.
X     * If the string is the same as the last one we were 
X     * called with then we don't do anything. It would be better
X     * to remember all the transliterations we have seen, in
X     * order (because in a global substitution we will
X     * apply them in the same order repeatedly) and then we
X     * could do the minimum amount of building. This is a 
X     * compromise because it is a fairly safe bet that there will 
X     * not be more than one transliteration done.
X     *
X     */
X
X    char *in;
X    char *out;
X    char *str;
X    char *tmp;
X    char c;
X    static char *mem();
X    static char nextch();
X    int i = 0;
X    int range_count = 0;
X    int seenbs = 0;
X    static char *last = 0;
X    static int last_len;
X
X    if (!s){
X        return 0;
X    }
X
X    if (last && !strncmp(s, last, last_len)){
X        /* Re-use the map. */
X        return s + last_len;
X    }
X    else{
X	/*
X	 * Make a copy of s in both 'last' and 'str'
X	 */
X	int len = strlen(s) + 1;
X        if (!(str = mem(MEM_MAP, len)) || !(last = mem(MEM_MAP_SAVE, len))){
X            return 0;
X        }
X	str[0] = last[0] = '\0';
X	strcat(str, s);
X	strcat(last, s);
X    }
X
X    tmp = str + 1;
X    in = str;
X
X    while (*tmp){
X        if (seenbs){
X            if (*tmp == '-'){
X                /* 
X                 * Keep the \ before a - since this is the range
X                 * separating metacharacter. We don't keep } quoted,
X                 * we just put it in. Then it is passed as a normal
X                 * char (no longer a metachar) to nextch().
X                 *
X                 */
X                str[i++] = '\\';
X            }
X            str[i++] = *tmp++;
X            seenbs = 0;
X        }
X        else{
X            if (*tmp == '\\'){
X                seenbs = 1;
X                tmp++;
X            }
X            else if (*tmp == '}'){
X                if (!range_count){
X                    /* seen first range. */
X                    range_count = 1;
X                    str[i++] = '\0';
X                    tmp++;
X                    while (*tmp == ' ' || *tmp == '\t'){
X                        tmp++;
X                    }
X                    if (*tmp != '{'){
X                        return 0;
X                    }
X                    out = str + i;
X                    tmp++;
X                }
X                else{
X                    /* seen both ranges. */
X                    str[i++] = '\0';
X                    tmp++;
X                    range_count = 2; 
X                    break;
X                }
X            }
X            else{
X                /* A plain defenceless character. */
X                str[i++] = *tmp++;
X            }
X        }
X    }
X
X    if (range_count != 2){
X        return 0;
X    }
X
X    last_len = tmp - str;
X
X    /*
X     * Now 'out' and 'in' both point to character ranges.
X     * These will look something like "A-Z" but may be 
X     * more complicated and have {} and - in them elsewhere.
X     *
X     */
X    
X    for (i = 0; i < 1 << BYTEWIDTH; i++){
X        map[i] = i;
X    }
X
X    /*
X     * Ready the range expanding function.
X     *
X     */
X    (void) nextch(in, 0);
X    (void) nextch(out, 1);
X
X    /*
X     * For each char in 'in', assign it a value in
X     * 'map' corresponding to the next char in 'out'.
X     *
X     */
X
X    while ((c = nextch(0, 0))){
X        map[c] = nextch(0, 1);
X    }
X
X    return tmp;
X}
X
Xstatic char
Xnextch(str, who)
Xchar *str;
Xint who;
X{
X    /*
X     * Given a range like {a-z0237-9}
X     * return successive characters from the range on
X     * successive calls. The first call (when str != 0)
X     * sets things up.
X     *
X     * We must handle strange things like
X     * {a-b-c-z}            = {a-z}
X     * and {z-l-a}          = {z-a}
X     * and {f-f-f-f-h}      = {f-h}
X     * and {a-z-f-h-y-d-b}  = {a-b}
X     *
X     * and so on.
X     *
X     * This function will remember two strings and will return
X     * the next charcter in the range specified by 'who'. This
X     * makes the building of the transliteration table above
X     * a trivial loop.
X     *
X     * I can't be bothered to comment this as much as it
X     * deserves right now... 8-)
X     *
X     */
X
X    static char *what[2] = {0, 0};
X    static char last[2] = {0, 0};
X    static int increment[2];
X    static int pos[2];
X
X    if (who < 0 || who > 1){
X        return 0;
X    }
X
X    if (str){
X        /* Set up for this string. */
X        what[who] = str;
X        pos[who] = 0;
X        return 1;
X    }
X    else if (!what[who]){
X        return 0;
X    }
X
X    if (!pos[who] && what[who][0] == '-'){
X        return 0;
X    }
X
X    switch (what[who][pos[who]]){
X        
X        case '-':{
X            /* we're in mid-range. */
X            last[who] += increment[who];
X            if (what[who][pos[who] + 1] == last[who]){
X                pos[who] += 2;
X            }
X            return last[who];
X        }
X
X        case '\0':{
X            /* 
X             * We've finished. Keep on returning the
X             * last thing you saw if who = 1.
X             */
X            if (who){
X                return last[1];
X            }
X            return 0;
X        }
X
X        /* FALLTHROUGH */
X        case '\\':{
X            pos[who]++;
X        }
X
X        default:{
X            last[who] = what[who][pos[who]++];
X            /*
X             * If we have reached a '-' then this is the start of a
X             * range. Keep on moving forward until we see a sensible 
X             * end of range character. Then set up increment so that
X             * we do the right thing next time round. We leave pos
X             * pointing at the '-' sign.
X             *
X             */
X
X            while (what[who][pos[who]] == '-'){
X                int inc = 1;
X                if (what[who][pos[who] + inc] == '\\'){
X                    inc++;
X                }
X                if (!what[who][pos[who] + inc]){
X                    return 0;
X                }
X                if (what[who][pos[who] + inc + 1] == '-'){
X                    pos[who] += inc + 1;
X                    continue;
X                }
X                increment[who] = what[who][pos[who] + inc] - last[who];
X                if (!increment[who]){
X                    pos[who] += 2;
X                    continue;
X                }
X                if (increment[who] > 0){
X                    increment[who] = 1;
X                    break;
X                }
X                else if (increment[who] < 0){
X                    increment[who] = -1;
X                    break;
X                }
X            }
X            return last[who];
X        }
X    }
X}
X
Xstatic char *
Xmem(who, size)
Xint who;
Xint size;
X{
X    /*
X     * Get 'size' bytes of memeory one way or another.
X     *
X     * The 'mem_slots' array holds currently allocated hunks.
X     * If we can use one that's already in use then do so, otherwise
X     * try and find a hunk not in use somewhere else in the table.
X     * As a last resort call malloc. All a bit specialised and
X     * not too clear. Seems to works fine though.
X     */
X    
X    static void mem_save();
X
X    if (who < 0 || who >= MEM_SLOTS){
X	return 0;
X    }
X    
X    if (mem_slots[who].used){
X	/*
X	 * There is already something here. Either move/free it or
X	 * return it if it is already big enough to hold this request.
X	 */
X	if (mem_slots[who].size >= size){
X	    /* It is already big enough. */
X	    return mem_slots[who].s;
X	}
X	else{
X	    mem_save(who);
X	}
X    }
X    else{
X	/*
X	 * The slot was not in use. Check to see if there is space
X	 * allocated here already that we can use. If there is and
X	 * we can, use it, if there is and it's not big enough try to
X	 * save it. if there isn't then try to find it in another free slot,
X	 * otherwise don't worry, the malloc below will get us some.
X	 */
X	if (mem_slots[who].s && mem_slots[who].size >= size){
X	    /* We'll take it. */
X	    mem_slots[who].used = 1;
X	    return mem_slots[who].s;
X	}
X	
X	if (mem_slots[who].s){
X	    mem_save(who);
X	}
X	else{
X	    static int mem_find();
X	    int x = mem_find(size);
X	    if (x != -1){
X		mem_slots[who].s = mem_slots[x].s;
X		mem_slots[who].size = mem_slots[x].size;
X		mem_slots[who].used = 1;
X		mem_slots[x].s = (char *)0;
X		return mem_slots[who].s;
X	    }
X	}
X    }
X    
X    /*
X     * Have to use malloc 8-(
X     */
X
X    if (!(mem_slots[who].s = malloc((unsigned)size))){
X	return 0;
X    }
X    mem_slots[who].size = size;
X    mem_slots[who].used = 1;
X    
X    return mem_slots[who].s;
X}
X
Xstatic int
Xmem_find(size)
Xint size;
X{
X    /*
X     * See if we can find an unused but allocated slot with 'size' 
X     * (or more) space available. Return the index, or -1 if not.
X     */
X     
X    register int i;
X    
X    for (i = 0; i < MEM_SLOTS; i++){
X	if (!mem_slots[i].used && mem_slots[i].s && mem_slots[i].size >= size){
X	    return i;
X	}
X    }
X    return -1;
X}
X
Xstatic void
Xmem_save(x)
Xint x;
X{
X    /*
X     * There is some memory in mem_slots[x] and we try to save it rather
X     * than free it. In order we try to
X     *
X     * 1) put it in an unused slot that has no allocation.
X     * 2) put it in an unused slot that has an allocation smaller than x's
X     * 3) free it since there are no free slots and all the full ones are bigger.
X     *
X     */
X
X    register int i;
X    register int saved = 0;
X    
X    /*
X     * First we try to find somewhere unused and with no present allocation.
X     */
X    for (i = 0; i < MEM_SLOTS; i++){
X	if (!mem_slots[i].used && !mem_slots[i].s){
X	    saved = 1;
X	    mem_slots[i].s = mem_slots[x].s;
X	    mem_slots[i].size = mem_slots[x].size;
X	    mem_slots[i].used = 0;
X	    break;
X	}
X    }
X    
X    /*
X     * No luck yet. Try for a place that is not being used but which has
X     * space allocated, and which is smaller than us (and all other such spots). 
X     * Pick on the smallest, yeah.
X     */
X    if (!saved){
X	register int small = -1;
X	register int small_val = 1000000;
X	for (i = 0; i < MEM_SLOTS; i++){
X	    if (!mem_slots[i].used && mem_slots[i].size < mem_slots[x].size && mem_slots[i].size < small_val){
X		small_val = mem_slots[i].size;
X		small = i;
X	    }
X	}
X	
X	if (small != -1){
X	    saved = 1;
X	    /* We got one, now clobber it... */
X	    free(mem_slots[small].s);
X	    /* and move on in. */
X	    mem_slots[small].s = mem_slots[x].s;
X	    mem_slots[small].size = mem_slots[x].size;
X	    mem_slots[small].used = 0;
X	}
X    }
X    
X    if (!saved){
X	/* Have to toss it away. */
X	free(mem_slots[x].s);
X    }
X}
X
Xstatic void
Xmem_init()
X{
X    /*
X     * Clear all the memory slots.
X     */
X
X    register int i;
X    
X    for (i = 0; i < MEM_SLOTS; i++){
X	mem_slots[i].s = (char *)0;
X	mem_slots[i].used = 0;
X    }
X}
X
Xstatic void
Xmem_free(except)
Xchar *except;
X{
X    /*
X     * "Clear out" all the memory slots. Actually we do no freeing since
X     * we may well be called again. We just mark the slots as unused. Next
X     * time round they might be useful - the addresses and sizes are still there.
X     *
X     * For the slot (if any) whose address is 'except', we actually set the
X     * address to 0. This is done because we are called ONLY from the macro
X     * RETURN() in strsed() and we intend to return the value in 'except'.
X     * Once this is done, strsed should (in theory) have no knowledge at all
X     * of the address it passed back last time. That way we won't clobber it
X     * and cause all sorts of nasty problems.
X     */
X
X    register int i;
X    
X    for (i = 0; i < MEM_SLOTS; i++){
X	mem_slots[i].used = 0;
X	if (mem_slots[i].s == except){
X	    mem_slots[i].s = (char *)0;
X	    mem_slots[i].size = 0;
X	}
X    } 
X}
X
SHAR_EOF
echo "File strsed.c is complete"
chmod 0644 strsed.c || echo "restore of strsed.c fails"
set `wc -c strsed.c`;Sum=$1
if test "$Sum" != "36532"
then echo original size 36532, current size $Sum;fi
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X# Makefile for strsed
X#
X
X#
X# Use gcc if you have it...
X# (The MIPS cc produces a regex.o which dumps core).
X#
X
X#CC = cc
X
XCC = gcc
XCFLAGS = -O
X
X
Xall : check
X
Xcheck : check1 check2
X	cat examples1 | ./check1
X	cat examples2 | ./check2
X
Xcheck1 : strsed.o regex.o check1.o
X	$(CC) $(CFLAGS) -o check1 strsed.o regex.o check1.o
X
Xcheck2 : strsed.o regex.o check2.o
X	$(CC) $(CFLAGS) -o check2 strsed.o regex.o check2.o
X
Xstrsed.o : regex.h
Xregex.o : regex.h
X
Xclean :
X	rm -f check?.o
X
Xclobber : clean
X	rm -f strsed.o check[12] MANIFEST
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
set `wc -c Makefile`;Sum=$1
if test "$Sum" != "526"
then echo original size 526, current size $Sum;fi
echo "x - extracting check1.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > check1.c &&
X#include <stdio.h>
X
Xint
Xmain()
X{
X	/*
X	 * Check simple searching.
X	 *
X	 * Input consists of sets of three lines containing
X	 *
X	 *      text
X	 *      pattern
X	 *      expected new text
X	 *
X	 * See the file examples1
X	 *
X	 */
X
X	extern int strcmp();
X	extern char *strsed();
X
X	char text[1024];
X	char pat[1024];
X	char ans[1024];
X	register char *result;
X	register int testno = 0;
X	int error = 0;
X
X	while (gets(text) && gets(pat) && gets(ans)){
X		testno++;
X		result = strsed(text, pat, 0);
X		if (strcmp(ans, result)){
X			error = 1;
X			printf("WARNING (test %d)... strsed(%s, %s) returns '%s'\nExpected '%s'\n", 
X				testno, text, pat, result, ans);
X			fflush(stdout);
X		}
X	}
X
X	if (!error){
X		printf("Substitution and transliteration tests passed successfully.\n");
X	}
X
X	return 0;
X}
SHAR_EOF
chmod 0644 check1.c || echo "restore of check1.c fails"
set `wc -c check1.c`;Sum=$1
if test "$Sum" != "775"
then echo original size 775, current size $Sum;fi
echo "x - extracting check2.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > check2.c &&
X#include <stdio.h>
X
Xint
Xmain()
X{
X	/*
X	 * Check simple searching.
X	 *
X	 * Input consists of sets of four lines containing
X	 *
X	 *      text
X	 *      pattern
X	 *      expected start of match
X	 *      expected end of match
X	 *
X	 * See the file examples2
X	 *
X	 */
X
X	extern int atoi();
X	extern char *strsed();
X
X	char text[1024];
X	char pat[1024];
X	char ans1[10];
X	char ans2[10];
X	int range[2];
X	int low;
X	int high;
X	register int testno = 0;
X	int error = 0;
X
X	while (gets(text) && gets(pat) && gets(ans1) && gets(ans2)){
X		testno++;
X		strsed(text, pat, range);
X		low = atoi(ans1);
X		high = atoi(ans2);
X		if (low != range[0] || high != range[1]){
X			error = 1;
X			printf("WARNING (test %d)... strsed(%s, %s) returns range %d-%d (Expected %d-%d)\n", 
X				testno, text, pat, range[0], range[1], low, high);
X			fflush(stdout);
X		}
X	}
X
X	if (!error){
X		printf("Searching tests passed successfully.\n");
X	}
X
X	return 0;
X}
SHAR_EOF
chmod 0644 check2.c || echo "restore of check2.c fails"
set `wc -c check2.c`;Sum=$1
if test "$Sum" != "907"
then echo original size 907, current size $Sum;fi
echo "x - extracting examples1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > examples1 &&
Xabcdef
Xs/bx?m?m?m?1?2?3?c/BC/
XaBCdef
Xabcdef
Xs/bx?c/BC/
XaBCdef
X/initial/slash
X/^\///
Xinitial/slash
Xfunny ranges
X/.*/{n-a-\--\040-\0xd-\d-n}{1-\x-\--\--p-7-1}/
Xfu11y ra1ges
Xfunny ranges
X/.*/{n-a-\--\040-\0xd-\d-n}{1-\x-\--\--p-7-4}/
Xfu11y ra1ges
Xfunny ranges
X/.*/{r-a-\--\040-\0xd-\d-u}{1-\x-\--\--p-7-4}/
Xf4nny 1ange2
Xfunny ranges
X/.*/{r-a-\--\d-u}{1-\x-\--\--p-7-4}/
Xf4nny 1ange2
Xfunny ranges
X/.*/{r-a-l-d-u}{1-x-p-7-4}/
Xf4nny 1ange2
Xfunny ranges
X/.*/{a-f-c}{1-9}/
Xfunny r1nges
Xhere we go
X/.*/{e}{\}}/
Xh}r} w} go
Xhere we go
X/.*/{e}{\-}/
Xh-r- w- go
Xhere we go
X/.*/{hre}{{\}\-}/
X{-}- w- go
X  this is a line  
Xg/\([\t\s]*\)\(.\)\([^\t\s]*\)/\1\2{a-z}{A-Z}\3/
X  This Is A Line  
Xjooooneees         waaaassss     heeeerrrrrreeeee
Xg/\([a-z\s]\)\1+/\1/
Xjones was here
Xtry an inverse range
Xg/[^e]/X/
XXXXXXXXXXXeXXeXXXXXe
Xtry an inverse range
Xg/[^a-z]/X/
XtryXanXinverseXrange
Xcapitalise    first       letters of    words, preserving whitespace
Xg/\([\t\s]*\)\(.\)\([a-z]*\)/\1\2{a-z}{A-Z}\3/
XCapitalise    First       Letters Of    Words, Preserving Whitespace
Xthis is a test of squeezing
Xg/\([a-z]\)\1*/\1/
Xthis is a test of squezing
Xjooooneees         waaaassss     heeeerrrrrreeeee
Xg/\([a-z\s]\)\1*/\1/
Xjones was here
Xmary had a little lamb
X/\(.*\) \(h.*\) \(a.*\)/"\0" becomes "\1{a-z}{A-Z} fucked \3{a-z}{A-C-E-XYZ}"/
X"mary had a little lamb" becomes "MARY fucked A LITTLE LAMB"
Xmary had a little lamb
X/\(.*\) \(.*\) \(.*\)/"\0" becomes "\1{a-z}{A-Z} fucked \3{a-z}{A-C-E-XYZ}"/
X"mary had a little lamb" becomes "MARY HAD A fucked LAMB"
Xmary had a little lamb
X/\(mary \(had\).*\)/{a-z}{A-Z}\1{had}{sex}/
XMARY HAD A LITTLE LAMBmery sex e little lemb
Xjones
Xg/ones/{a-c-f-n-qr-v-z}{A-J-Z}/
XjONES
Xa string an a another a ay?
Xg/a/{a-a-a-a-a-a-a-a-a-a-a-a}{X-X-X-X-Z}/
XX string Xn X Xnother X Xy?
Xa string an a another a ay?
X/.*/{a-a-a-a-a-a-a-a-a-a-a-ast}{X-X-X-X-Z}/
XX YZring Xn X XnoZher X Xy?
Xfred
X/\(.*\)/\1\s\1{a-z}{A-Z}\s\1{fred}{0123}\sjoe/
Xfred FRED 0123 joe
Xjordan k. hubbard
Xg/r/{a-z}{R}/
XjoRdan k. hubbaRd
Xjordan k. hubbard
Xg/r/{a-z}{A-Z}/
XjoRdan k. hubbaRd
Xjordan k. hubbard
Xg/r/R/
XjoRdan k. hubbaRd
Xterry jones was here
Xs/.*/{a-z}{A-Z}/
XTERRY JONES WAS HERE
Xfred he's dead
Xs/.* \(.*\) .*/\1{a-z}{1-9}/
X85'9
Xthis is a test line
Xg/\(.\)./{a-z}{A-Z}/
XTHIS IS A TEST LINe
Xthis is a test line
Xg/\(.\)./\1{a-z}{A-Z}/
XTI SATS Ie
Xthis is a test line
Xg/\(.\)\(.\)/\1{a-z}{A-Z}\2/
XThIs iS A TeSt lIne
Xthis is a test linex
Xg/\(.\)\(.\)/\1{a-z}{A-Z}\2/
SHAR_EOF
echo "End of part 2"
echo "File examples1 is continued in part 3"
echo "3" > s2_seq_.tmp
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list