368 lines
9.7 KiB
C
368 lines
9.7 KiB
C
/*
|
|
* words.c -- right now it just holds the stuff i wrote to replace
|
|
* that beastie arg_number(). Eventually, i may move all of the
|
|
* word functions out of ircaux and into here. Now wouldnt that
|
|
* be a beastie of a patch! Beastie! Beastie!
|
|
*
|
|
* Oh yea. This file is beastierighted (C) 1994 by the beastie author.
|
|
* Right now the only author is Jeremy "Beastie" Nelson. See the
|
|
* beastieright file for beastie info.
|
|
*/
|
|
|
|
#include "irc.h"
|
|
static char cvsrevision[] = "$Id$";
|
|
CVS_REVISION(words_c)
|
|
#include "ircaux.h"
|
|
#include "modval.h"
|
|
|
|
/* strsearch()
|
|
*
|
|
* If how > 0, returns a pointer to the how'th matching character forwards
|
|
* from the beginning of the string starting at start.
|
|
* If how < 0, returns a pointer to the -how'th matching character backwards
|
|
* from the end of the string starting at start.
|
|
* If how == 0, returns NULL.
|
|
*
|
|
* A matching character is any character in chars, unless chars starts with ^,
|
|
* in which case a matching character is any character NOT in chars.
|
|
*
|
|
* If there are insufficient matching characters, NULL is returned.
|
|
*/
|
|
extern char *BX_strsearch(const char *start, const char *chars, int how)
|
|
{
|
|
const char *ptr = NULL;
|
|
|
|
if (how > 0) /* forward search */
|
|
{
|
|
const char *mark = start;
|
|
|
|
for (; how > 0 && mark; how--)
|
|
{
|
|
ptr = sindex(mark, chars);
|
|
if (ptr)
|
|
mark = ptr + 1;
|
|
else
|
|
mark = NULL;
|
|
}
|
|
}
|
|
else if (how < 0)
|
|
{
|
|
ptr = start + strlen(start);
|
|
|
|
for (; how < 0 && ptr; how++)
|
|
ptr = rsindex(ptr, start, chars);
|
|
}
|
|
|
|
return (char *)ptr;
|
|
}
|
|
|
|
/* move_to_word()
|
|
*
|
|
* Return a pointer to the first character of the Nth word in a string.
|
|
* The first word is always numbered zero.
|
|
*/
|
|
extern char *BX_move_to_word(const char *start, int word)
|
|
{
|
|
const char *pointer = start;
|
|
|
|
/* This fixes a bug that counted leading spaces as
|
|
* a word, when they're really not a word....
|
|
* (found by Genesis K.)
|
|
*
|
|
* The stock client strips leading spaces on both
|
|
* the cases $0 and $-0. I personally think this
|
|
* is not the best choice, but I'm not going to stick
|
|
* my foot in this one... I'm just going to go with
|
|
* what the stock client does...
|
|
*/
|
|
while (*pointer && my_isspace(*pointer))
|
|
pointer++;
|
|
|
|
for (; word > 0 && *pointer; word--)
|
|
{
|
|
while (*pointer && !my_isspace(*pointer))
|
|
pointer++;
|
|
while (*pointer && my_isspace(*pointer))
|
|
pointer++;
|
|
}
|
|
|
|
return (char *)pointer;
|
|
}
|
|
|
|
/* move_word_rel()
|
|
*
|
|
* Take a string and return a pointer offset a number of words relative to a given mark.
|
|
* Positive offset N returns a pointer to Nth next word (not counting the current word,
|
|
* if the mark is within a word). Negative offset -N returns a pointer to the Nth
|
|
* previous word, counting the current word. Offset 0 leaves the mark unchanged.
|
|
*/
|
|
extern char *BX_move_word_rel (const char *start, char **mark, int word)
|
|
{
|
|
const char *pointer = *mark;
|
|
|
|
if (!*start) /* null string, return it */
|
|
return (char *)start;
|
|
|
|
if (word >= 0)
|
|
{
|
|
for (;word > 0 && *pointer;word--)
|
|
{
|
|
/* Move pointer to first space after current word */
|
|
while (*pointer && !my_isspace(*pointer))
|
|
pointer++;
|
|
/* Move pointer to first character of next word */
|
|
while (*pointer && my_isspace(*pointer))
|
|
pointer++;
|
|
}
|
|
}
|
|
else /* word < 0 */
|
|
{
|
|
/* If we are in between words, find the previous word */
|
|
while (pointer > start && my_isspace(pointer[0]))
|
|
pointer--;
|
|
/* Move pointer to first character of current word */
|
|
while (pointer > start && !my_isspace(pointer[-1]))
|
|
pointer--;
|
|
|
|
for (word++; word < 0 && pointer > start; word++)
|
|
{
|
|
/* Move pointer to first space after previous word. */
|
|
while (pointer > start && my_isspace(pointer[-1]))
|
|
pointer--;
|
|
|
|
/* Move pointer to first character of word */
|
|
while (pointer > start && !my_isspace(pointer[-1]))
|
|
pointer--;
|
|
}
|
|
}
|
|
|
|
return *mark = (char *)pointer;
|
|
}
|
|
|
|
/*
|
|
* 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 apparently is what everyone
|
|
* wants, so that will be the default. Those of us who may not like
|
|
* that behavior or are at ambivalent can just #define it.
|
|
*/
|
|
#undef STRIP_EXTRANEOUS_SPACES
|
|
extern char *BX_extract2(const char *start, int firstword, int lastword)
|
|
{
|
|
/* If firstword or lastword is negative, then
|
|
we take those values from the end of the string */
|
|
char *mark;
|
|
char *mark2;
|
|
char *booya = NULL;
|
|
|
|
/* If firstword is EOS, then the user wants the last word */
|
|
if (firstword == EOS)
|
|
{
|
|
mark = (char *)start + strlen(start);
|
|
mark = move_word_rel(start, &mark, -1);
|
|
#ifndef NO_CHEATING
|
|
/*
|
|
* Really. the only case where firstword == EOS is
|
|
* when the user wants $~, in which case we really
|
|
* don't 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 = (char *)start;
|
|
|
|
/* If the firstword is positive, move to that word */
|
|
else if (firstword >= 0)
|
|
{
|
|
mark = move_to_word(start, firstword);
|
|
if (!*mark)
|
|
return m_strdup(empty_string);
|
|
}
|
|
/* Otherwise, move to the firstwords from the end */
|
|
else
|
|
{
|
|
mark = (char *)start + strlen((char *)start);
|
|
move_word_rel(start, &mark, firstword);
|
|
}
|
|
|
|
#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)
|
|
mark2 = move_to_word(start, lastword + 1);
|
|
else
|
|
{
|
|
mark2 = (char *)start + strlen(start);
|
|
move_word_rel(start, &mark2, lastword);
|
|
}
|
|
|
|
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
|
|
{
|
|
#if 0
|
|
/* Otherwise, copy off the string we just isolated */
|
|
char tmp;
|
|
tmp = *mark2;
|
|
*mark2 = '\0';
|
|
booya = m_strdup(mark);
|
|
*mark2 = tmp;
|
|
#endif
|
|
booya = new_malloc(mark2 - mark + 1);
|
|
strlcpy(booya, mark, mark2 - mark + 1);
|
|
}
|
|
|
|
return booya;
|
|
}
|
|
|
|
/*
|
|
* extract is a simpler version of extract2, it is used when we don't
|
|
* want special treatment of "firstword" if it is negative. This is
|
|
* typically used by the word/list functions, which also don't care if
|
|
* we strip out or leave in any whitespace, we just do what is the
|
|
* fastest.
|
|
*/
|
|
extern char *BX_extract(char *start, int firstword, int lastword)
|
|
{
|
|
/*
|
|
* 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;
|
|
|
|
/*
|
|
* 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 don't 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 = move_word_rel(start, &mark, -1);
|
|
}
|
|
|
|
/* If the firstword is positive, move to that word */
|
|
else if (firstword >= 0)
|
|
mark = move_to_word(start, firstword);
|
|
|
|
/* 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)
|
|
mark2 = move_to_word(start, lastword + 1);
|
|
else
|
|
/* it's negative -- that's 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 0
|
|
booya = NULL;
|
|
#endif
|
|
if (mark2 < mark)
|
|
return m_strdup(empty_string);
|
|
|
|
booya = new_malloc(mark2 - mark + 1);
|
|
strlcpy(booya, mark, mark2 - mark + 1);
|
|
#if 0
|
|
malloc_strcpy(&booya, empty_string);
|
|
else
|
|
{
|
|
/* Otherwise, copy off the string we just isolated */
|
|
char tmp;
|
|
tmp = *mark2;
|
|
*mark2 = '\0';
|
|
malloc_strcpy(&booya, mark);
|
|
*mark2 = tmp;
|
|
}
|
|
#endif
|
|
return booya;
|
|
}
|