/* * Move a relative number of words from the present mark */ static const char * move_word_rel (const char *start, const char **mark, int word, int extended) { int counter = word; const char * pointer = *mark; const char * end = start + strlen(start); if (end == start) /* null string, return it */ return start; CHECK_EXTENDED_SUPPORT if (counter > 0) { for (;counter > 0 && pointer;counter--) { if (extended && *pointer == '"') { const char * after; if (!(after = find_forward_quote(pointer, start))) nappanic("find_forward returned NULL [2]"); if (*after) after++; pointer = after; } else while (*pointer && !my_isspace(*pointer)) pointer++; while (*pointer && my_isspace(*pointer)) pointer++; } } else if (counter == 0) pointer = *mark; else /* counter < 0 */ { for (; counter < 0 && pointer > start; counter++) { if (extended && *pointer == '"') { const char * before; if (!(before = find_backward_quote(pointer, start))) nappanic("find_backward returned NULL [2]"); if (before > start) before--; pointer = before; } else while (pointer >= start && !my_isspace(*pointer)) pointer--; while (pointer > start && my_isspace(*pointer)) pointer--; } pointer++; /* bump up to the word we just passed */ } if (mark) *mark = pointer; return pointer; }
/* * 'move_to_prev_word': Move a "mark" from its current position to the * beginning of the "previous" word. * * Arguments: * 'str' - a pointer to a character pointer -- The initial value is the * "mark", and it will be changed upon return to the beginning * of the previous word. * 'start' - The start of the string that (*str) points to. * 'extended' - Whether double quoted words shall be supported * 'delims' - The types of double quoets to honor (if applicable) * * Return value: * If (*str) points to 'start' or is NULL (there is no previous word) * the return value is 0. * Otherwise, the return value is 1. * * Notes: * Regardless of whether 'start' is actually the start of the string that * '*str' points to, this function will treat it as such and will never go * backwards further than 'start'. * If (*str) points to the nul that terminates 'start', then (*str) shall * be set to the first character in the last word in 'start'. * If (*str) points to the first character in any word, then (*str) shall * be set to the first character in the full word BEFORE (*str). * If (*str) points to the middle of a string, then (*str) shall be set to * the first character IN THAT WORD (*str) points to. * If (*str) points to a space, then (*str) shall be set to the first * character in the word before the space. * A "word" always begins on the second character after the end of a word * because the first character after a word is a space (which is reserved * because we might want to change it to a nul). That means if there is * more than one space between words, the first space belongs to the "left" * word and all the rest of the spaces belong to the "right" word! * * XXX - The debugging printfs are ugly. */ static int move_to_prev_word (const char **str, const char *start, int extended, const char *delims) { char what; int simple; const char *pos; if (!str || *str <= start) return 0; /* Overhead -- work out if "" support will be cheap or expensive */ if (delims && delims[0] && delims[1] == 0) { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Simple processing"); simple = 1; what = delims[0]; } else { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Expensive processing"); simple = 0; what = 255; } /* Overhead -- work out if we're doing "" support or not. */ CHECK_EXTENDED_SUPPORT /* Start at the mark the user provided us */ pos = *str; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Starting at [%s] (in [%s])", pos, start); /* * XXX This is a hack, but what do i care? * If we are pointing at the start of a string, then * we want to go to the PREVIOUS word, so cheat by * stepping off the word. This means if you want the * last word, you need to point to the nul, not the last * character before the nul! */ if (pos > start && isspace(pos[-1])) pos--; /* * Skip over whitespace */ while (pos >= start && ((*pos == 0) || my_isspace(*pos))) pos--; /* * In the above 'mark1' case (the normal case), we would be pointing * at the last character in 'two'. If this were a double quoted word * then this would be a double quote of some sort, and this code * checks for that. If it finds a double quote, then it moves to the * "matching" double quote. */ if (pos > start && extended == DWORD_YES && ( (simple == 1 && *pos == what) || (simple == 0 && strchr(delims, *pos)) ) ) { const char * before; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Handling extended word."); if (!(before = find_backward_quote(pos, start, delims))) panic("find_backward returned NULL [2]"); if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Extended word begins at [%s] (of [%s])", before, start); /* * "Before" either points at a double quote or it points * at the start of the string. If it points at a double * quote, move back one position so it points at a space. */ if (before > start) before--; /* So our new mark is the space before the double quoted word */ pos = before; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: So the position before the extended word is [%s] (of [%s])", pos, start); } /* * If this is not a double quoted word, keep moving backwards until * we find a space -- so our new mark is the space before the start * of the word. */ else { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Handling simple word."); while (pos >= start && !my_isspace(*pos)) pos--; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: So the position before the simple word is [%s] (of [%s])", pos, start); } /* * If we hit the front of the string (*gulp*), set the return value * (*str) to the start of the string and just punt right here. */ if (pos <= start) { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Ooops. we hit the start " "of the string. Stopping here."); *str = start; return 1; } /* * Slurp up spaces. */ else { while (*pos && isspace(*pos)) pos++; while (pos > start && isspace(pos[0]) && isspace(pos[-1])) pos--; } if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: And after we're done, [%s] is " "the start of the previous word!", pos); *str = pos; return 1; }