/* * extract2 is the word extractor that is used when its important to us * that 'firstword' get special treatment if it is negative (specifically, * that it refer to the "firstword"th word from the END). This is used * basically by the ${n}{-m} expandos and by function_rightw(). * * Note that because of a lot of flak, if you do an expando that is * a "range" of words, unless you #define STRIP_EXTRANEOUS_SPACES, * the "n"th word will be backed up to the first character after the * first space after the "n-1"th word. That apparantly is what everyone * wants, so thats whatll be the default. Those of us who may not like * that behavior or are at ambivelent can just #define it. */ char * real_extract2 (const char *start, int firstword, int lastword, int extended) { /* * If firstword or lastword is negative, then * we take those values from the end of the string */ const char * mark; const char * mark2; char * booya = NULL; CHECK_EXTENDED_SUPPORT /* If firstword is EOS, then the user wants the last word */ if (firstword == EOS) { mark = start + strlen(start); mark = move_word_rel(start, &mark, -1, extended); #ifndef NO_CHEATING /* * Really. the only case where firstword == EOS is * when the user wants $~, in which case we really * dont need to do all the following crud. Of * course, if there ever comes a time that the * user would want to start from the EOS (when?) * we couldnt make this assumption. */ return m_strdup(mark); #endif } /* * SOS is used when the user does $-n, all leading spaces * are retained */ else if (firstword == SOS) mark = start; /* If the firstword is positive, move to that word */ /* Special treatment for $X-, where X is out of range * added by Colten Edwards, fixes the $1- bug.. */ else if (firstword >= 0) { real_move_to_abs_word(start, &mark, firstword, extended); if (!*mark) return m_strdup(empty_string); } /* Otherwise, move to the firstwords from the end */ else { mark = start + strlen(start); move_word_rel(start, &mark, firstword, extended); } #ifndef STRIP_EXTRANEOUS_SPACES /* IF the user did something like this: * $n- $n-m * then include any leading spaces on the 'n'th word. * this is the "old" behavior that we are attempting * to emulate here. */ #ifndef NO_CHEATING if (lastword == EOS || (lastword > firstword)) #else if (((lastword == EOS) && (firstword != EOS)) || (lastword > firstword)) #endif { while (mark > start && my_isspace(mark[-1])) mark--; if (mark > start) mark++; } #endif /* * When we find the last word, we need to move to the * END of the word, so that word 3 to 3, would include * all of word 3, so we sindex to the space after the word */ if (lastword == EOS) mark2 = mark + strlen(mark); else { if (lastword >= 0) real_move_to_abs_word(start, &mark2, lastword+1, extended); else { mark2 = start + strlen(start); move_word_rel(start, &mark2, lastword, extended); } while (mark2 > start && my_isspace(mark2[-1])) mark2--; } /* * If the end is before the string, then there is nothing * to extract (this is perfectly legal, btw) */ if (mark2 < mark) booya = m_strdup(empty_string); else { /* * This is kind of tricky, because the string we are * copying out of is const. So we cant just null off * the trailing character and m_strdup it. */ booya = strext(mark, mark2); } return booya; }
/* * extract is a simpler version of extract2, it is used when we dont * want special treatment of "firstword" if it is negative. This is * typically used by the word/list functions, which also dont care if * we strip out or leave in any whitespace, we just do what is the * fastest. */ char * real_extract (char *start, int firstword, int lastword, int extended) { /* * firstword and lastword must be zero. If they are not, * then they are assumed to be invalid However, please note * that taking word set (-1,3) is valid and contains the * words 0, 1, 2, 3. But word set (-1, -1) is an empty_string. */ char * mark; char * mark2; char * booya = NULL; CHECK_EXTENDED_SUPPORT /* * Before we do anything, we strip off leading and trailing * spaces. * * ITS OK TO TAKE OUT SPACES HERE, AS THE USER SHOULDNT EXPECT * THAT THE WORD FUNCTIONS WOULD RETAIN ANY SPACES. (That is * to say that since the word/list functions dont pay attention * to the whitespace anyhow, noone should have any problem with * those ops removing bothersome whitespace when needed.) */ while (my_isspace(*start)) start++; remove_trailing_spaces(start); if (firstword == EOS) { mark = start + strlen(start); mark = (char *)move_word_rel(start, (const char **)&mark, -1, extended); } /* If the firstword is positive, move to that word */ else if (firstword >= 0) real_move_to_abs_word(start, (const char **)&mark, firstword, extended); /* Its negative. Hold off right now. */ else mark = start; /* * When we find the last word, we need to move to the * END of the word, so that word 3 to 3, would include * all of word 3, so we sindex to the space after the word */ /* EOS is a #define meaning "end of string" */ if (lastword == EOS) mark2 = start + strlen(start); else { if (lastword >= 0) real_move_to_abs_word(start, (const char **)&mark2, lastword+1, extended); else /* its negative -- thats not valid */ return m_strdup(empty_string); while (mark2 > start && my_isspace(mark2[-1])) mark2--; } /* * Ok.. now if we get to here, then lastword is positive, so * we sanity check firstword. */ if (firstword < 0) firstword = 0; if (firstword > lastword) /* this works even if fw was < 0 */ return m_strdup(empty_string); /* * If the end is before the string, then there is nothing * to extract (this is perfectly legal, btw) */ if (mark2 < mark) return m_strdup(empty_string); booya = strext(mark, mark2); return booya; }
/* * extract2 is the word extractor that is used when its important to us * that 'firstword' get special treatment if it is negative (specifically, * that it refer to the "firstword"th word from the END). This is used * basically by the ${n}{-m} expandos and by function_rightw(). */ char * real_extract2 (const char *start, int firstword, int lastword, int extended) { const char * mark; const char * mark2; char * retval; /* * 'firstword == EOS' means we should return the last word * This is used for $~. Handle the whole shebang here. */ if (firstword == EOS) { /* Mark to the end of the string... */ mark = start + strlen(start); /* And move to the start of that word */ move_word_rel(start, &mark, -1, extended, "\""); return malloc_strdup(mark); } /* * 'firstword == SOS' means the user did $-<num>. * The start of retval is start of string. */ else if (firstword == SOS) mark = start; /* * 'firstword is not negative' means user wants to start at * the <firstword>th word. Move the mark to that position. * * If the mark does not exist (ie, $10- when there are not * 10 words), fail by returning the empty string. */ else if (firstword >= 0) { real_move_to_abs_word(start, &mark, firstword, extended, "\""); if (!*mark) return malloc_strdup(empty_string); } /* * 'firstword is negative' means user wants to start at the * <firstword>th word from the end. Move the mark to that * position. This is used for $rightw() and stuff. */ else { mark = start + strlen(start); move_word_rel(start, &mark, firstword, extended, "\""); } /*****************************************************************/ /* * So now 'mark' points at the start of the string we want to * return; this should include the spaces that lead up to the word. * * Now we need to find the end of the string to return. */ /* * 'lastword is EOS' means the user did $<num>-, so cheat by * just returning the mark */ if (lastword == EOS) return malloc_strdup(mark); /* * 'lastword is nonnegative' means the user did $<num1>-<num2>, * so we need to move to the start of the <num2 + 1> and go back * one position -- easy, eh? */ else if (lastword >= 0) real_move_to_abs_word(start, &mark2, lastword + 1, extended, "\""); /* * 'lastword is negative' means the user wants all but the last * <num> words, so we move to the start of the <num>th word from * the end, and go back one character! */ else { mark2 = start + strlen(start); move_word_rel(start, &mark2, lastword, extended, "\""); } /* * move back one position, because we are the start of the NEXT word. */ if (*mark2 && mark2 > start) mark2--; /* * If the end is before the string, then there is nothing * to extract (this is perfectly legal, btw) */ if (mark2 < mark) return malloc_strdup(empty_string); /* * XXX Backwards compatability requires that $<num> not * have any leading spaces. */ if (firstword == lastword) { while (mark && *mark && isspace(*mark)) mark++; } /* * This is kind of tricky, because the string we are * copying out of is const. So we cant just null off * the trailing character and malloc_strdup it. */ retval = strext(mark, mark2); /* * XXX Backwards compatability requires that $<num> not have * any trailing spaces, even if it is the last word. */ if (firstword == lastword) remove_trailing_spaces(retval, 0); return retval; }