1 /*******************************************************************************
2 * Reverse Polish Notation calculator. *
3 * Copyright (c) 2007-2008, Samuel Fredrickson <kinghajj@gmail.com> *
4 * All rights reserved. *
6 * Redistribution and use in source and binary forms, with or without *
7 * modification, are permitted provided that the following conditions are met: *
8 * * Redistributions of source code must retain the above copyright *
9 * notice, this list of conditions and the following disclaimer. *
10 * * Redistributions in binary form must reproduce the above copyright *
11 * notice, this list of conditions and the following disclaimer in the *
12 * documentation and/or other materials provided with the distribution. *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS *
15 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
17 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY *
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
25 ******************************************************************************/
27 /*******************************************************************************
28 * tokens.c -- splits a string into tokens. *
30 * this doesn't use strtok(), which would work, because I personally dislike *
31 * it. however, the gettok() function is equivalent. *
32 ******************************************************************************/
41 // returns true if c occurs in delims.
42 static inline bool is_delim(char c
, char *delims
)
47 while(*delims
&& !(is
= (*delims
++ == c
)));
52 #endif // DOXYGEN_SKIP
55 * @param start A pointer to a string; keeps track of current position in
57 * @param delims Characters that will deliminate tokens.
58 * @return A pointer to the first found token, or NULL if none found.
60 * gettok() works by taking in a pointer to a string, searching through that
61 * string for deliminators, then updating that string so that on the next call,
62 * it will return the next token.
64 * Like strtok(), gettok() modifies the original string by inserting NULs where
65 * it finds deliminators.
70 * char *start = str, *tok;
72 * while((tok = gettok(&start, " ")))
77 char *gettok(char **start
, char *delims
)
81 if(start
&& *start
&& **start
&& delims
) {
82 // start searching from the start, and assume the token will be here.
83 search
= token
= *start
;
86 while(*search
&& !is_delim(*search
, delims
))
89 // nullify all consecutive delims.
90 while(*search
&& is_delim(*search
, delims
))
93 // the next token is right after the end of the delims.
98 // if token is NULL, let it pass. if token is not NULL but points to a '\0',
99 // then the token hasn't really been found, so recurse to find it.
100 return (!token
|| *token
) ? token
: gettok(start
, delims
);
104 * Creates a new tokens array with the default initial size.
106 * @returns The new tokens array structure.
108 static RPNTokens
*newTokens()
110 RPNTokens
*tokens
= new(RPNTokens
);
113 RPN_error("could not allocate memory for tokens");
115 tokens
->alloc_size
= RPN_TOKENS_ALLOC_SIZE
;
116 tokens
->tokens
= RPN_malloc(tokens
->alloc_size
* sizeof(char**));
119 RPN_error("could not allocate memory for tokens");
128 * Adds a token to a tokens array structure. Automatically resizes the array if
131 * @param tokens The array to which to add the token.
132 * @param token The token to add.
134 static void addToken(RPNTokens
*tokens
, char *token
)
137 RPN_error("attempted to add token to a NULL token array.");
139 RPN_error("attempted to add a NULL token to token array.");
141 // Check the tokens array for resizing.
142 if(tokens
->size
>= tokens
->alloc_size
)
144 RPN_dprintf("tokens->size: %u", tokens
->size
);
145 RPN_dprintf("tokens->alloc_size: %u", tokens
->alloc_size
);
146 RPN_dprintf("tokens->tokens: %p", tokens
->tokens
);
147 RPN_dprintf("token: \"%s\" (%u)", token
, strlen(token
));
149 tokens
->alloc_size
+= RPN_TOKENS_ALLOC_SIZE
;
150 tokens
->tokens
= realloc(tokens
->tokens
,
151 tokens
->alloc_size
* sizeof(char**));
153 RPN_error("could not resize tokens");
156 // store token in token structure
157 tokens
->tokens
[tokens
->size
++] = token
;
161 * Splits a string into tokens using whitespace as the delimeter.
163 * @param str The string to split.
164 * @return A RPNTokens structure with the tokens.
166 RPNTokens
*RPN_splitString(char *str
)
168 char *start
= str
, *tok
;
172 RPN_error("tried to split a null string");
174 tokens
= newTokens();
176 while((tok
= gettok(&start
, " \t\n")))
177 addToken(tokens
, tok
);
179 // don't try to resize the tokens to null.
181 tokens
->tokens
= realloc(tokens
->tokens
, tokens
->size
* sizeof(char**));
183 RPN_error("could not resize tokens");
191 * @param tokens The tokens to free.
193 void RPN_freeTokens(RPNTokens
*tokens
)
195 if(!tokens
|| !tokens
->tokens
)
196 RPN_error("tried to free a null tokens structure");
198 RPN_free(tokens
->tokens
);