Last active
February 24, 2016 21:52
-
-
Save wowczarek/7c8121696f7373e126d0 to your computer and use it in GitHub Desktop.
Simple C (C99) re-entrant "foreach" loop macro to split a string into tokens separated by delimiter and loop over them
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> | |
/* (c) 2015 Wojciech Owczarek - BSD Clause 2 licence - I'm too lazy to paste it */ | |
#ifndef __FOREACH_TOKEN_H | |
#define __FOREACH_TOKEN_H | |
/* handy default delimiter - space, comma, semicolon or tab */ | |
#define DEFAULT_TOKEN_DELIM ", ;\t" | |
/* | |
* foreach loop across substrings from @var, delimited by @delim, placing | |
* each token in @targetvar on iteration, using @id variable name prefix | |
* to allow nesting (each loop uses an individual set of variables). | |
* @id is only a string identifier, so the end macro can identify which | |
* helper pointer to free. We need to duplicate the string, because strtok | |
* functions alter it. We also need to free the duplicate. A counter variable | |
* (counter_@id) is defined and incremented from zero, so we know which token we | |
* are processing. The counter is incremented once again when ending the loop, | |
* so in the end contains the total number of tokens found. | |
* | |
* Note: because this is a macro, if you forget the end call, you're missing | |
* a closing bracket and compiler errors will not clearly show what happened. | |
*/ | |
#define foreach_token_begin(id, var, targetvar, delim) \ | |
int counter_##id = -1; /* iteration counter - start from -1 because we increment at the top of the loop */ \ | |
char* stash_##id = NULL; /* temporary pointer for strtok_r() - in strtok() this is static */ \ | |
char* text_##id; /* copy of our string */ \ | |
char* text__##id; /* pointer to our copy, which has to be used once only */ \ | |
char* targetvar; /* our target variable for the token */ \ | |
text_##id=strdup(var); \ | |
for(text__##id = text_##id;;text__##id = NULL) { /* why nullify? because strtoks require this */ \ | |
targetvar = strtok_r(text__##id, delim, &stash_##id); \ | |
if(targetvar == NULL) break; /* no (more) tokens */ \ | |
counter_##id++; | |
#define foreach_token_end(id) } \ | |
if(text_##id != NULL) { \ | |
free(text_##id); /* thou shall free what thou strdupeth */ \ | |
} \ | |
counter_##id++; /* because the for loop does no incrementing here */ | |
/* example usage (semicolons are not necessary when invoking begin_ and end_) */ | |
/* | |
foreach_token_begin(names, "Bob, Jake Steve; Norman Lucy", name, DEFAULT_TOKEN_DELIM); | |
foreach_token_begin(animals, "frog:cougar:fruit bat:tarsier", animal, ":"); | |
printf("%s\'s animal number %d is a %s.\n", name, counter_animals + 1, animal); | |
foreach_token_end(animals); | |
printf("this was a list of %s\'s %d animals.\n", name, counter_animals); | |
foreach_token_end(names); | |
printf("a total of %d people have animals\n.", counter_names); | |
*/ | |
#endif /* __FOREACH_TOKEN_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment