Tuesday, September 16, 2008

C - Explode.

15.09.2011 Sources can be found from svn repository at
http://xp-dev.com/svn/MazBotV4/trunk/generic/src/ CExplode functions are nowadays part of the helpers.c and helpers.h files.

Some kind of an API doc can be found from
http://xp-dev.com/svn/MazBotV4/trunk/docs/html/helpers_8h.html. Api doc may be opened as plain text so you may need to save it to your computer, and open it with web browser from there - sorry.
http://xp-dev.com/svn/MazBotV4/trunk/docs/


06.08.2009 NOTE: Another bug found, put up "correction release" v0.1-1
(svn repository at here , full checkout can be done if svn client is installed with: "svn checkout http://xp-dev.com/svn/Mazzie-mazbot/" ), but if you only wish to get the Cexplode, you can simply go there with web browswe, and save files generic/src/helpers.h and generic/src/helpers.c There propably is also some other helper functions, which may be dependant to other bot project sources, If that is the case, just erase everything except the Cexplode related stuff, and files should be compilable. If you need help, leave me a comment, and I may do a separate zip with Cexplode and makefile only :)

And please, if anyone uses the code and finds a bug, please file me a bugreport at Mazziesaccount@gmail.com


27.07.2009 NOTE: The code presented here is faulty. I found a bug which can cause the last character of last exploded piece to be random. (And possibly other errors). I have fixed this in code I have written for my MazBot project. (Look my comment below to find the updated version) I will not update code on this website because formatting C code to be displayed correctly on this blog is somewhat troublesome && errorprone and when done manually. I am terribly sorry for inconvenience!


I decided to write also ANSI C version of php's explode() function. Why? Well, because it seems to me that most of the visitors here have been searching for C/C++ implementation for php's explode() function. So here it is my loyal readers, cxplode() written in C. a.k.a Cexplode() by Maz :)

(I'll also place it in downloadable Cexplode.tar.gz when I'll find the time.)

Cexplode.h

/* ******************************************************** */
/* *
* Implementation of php's explode written in C *
* Written by Maz (2008) *
* http://maz-programmersdiary.blogspot.com/ *
* *
* You're free to use this piece of code. *
* You can also modify it freely, but if you *
* improve this, you must write the improved code *
* in comments at: *
* http://maz-programmersdiary.blogspot.com/ *
* or at: *
* http://c-ohjelmoijanajatuksia.blogspot.com/ *
* or mail the corrected version to me at *
* Mazziesaccount@gmail.com *
* *
* Revision History: *
* *
* -v0.0.1 16.09.2008/Maz *
* */
/* ******************************************************** */

#ifndef CEXPLODE_H
#define CEXPLODE_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct CexplodeStrings
{
int amnt;
char **strings;
}CexplodeStrings;

typedef enum ECexplodeRet
{
ECexplodeRet_InternalFailure = -666,
ECexplodeRet_InvalidParams = -667
}ECexplodeRet;

int Cexplode
(
const char *string,
const char *delim,
CexplodeStrings *exp_obj
);
char *Cexplode_getNth(int index,CexplodeStrings exp_obj);
char *Cexplode_getfirst(CexplodeStrings exp_obj);
void Cexplode_free(CexplodeStrings exp_obj);


#endif


Cexplode.c

/* ******************************************************** */
/* *
* Implementation of php's explode written in C *
* Written by Maz (2008) *
* http://maz-programmersdiary.blogspot.com/ *
* *
* You're free to use this piece of code. *
* You can also modify it freely, but if you *
* improve this, you must write the improved code *
* in comments at: *
* http://maz-programmersdiary.blogspot.com/ *
* or at: *
* http://c-ohjelmoijanajatuksia.blogspot.com/ *
* or mail the corrected version to me at *
* Mazziesaccount@gmail.com *
* *
* Revision History: *
* *
* -v0.0.1 16.09.2008/Maz *
* */
/* ******************************************************** */


#include "Cexplode.h"


int Cexplode
(
const char *string,
const char *delim,
CexplodeStrings *exp_obj
)
{
int stringL = 0;
int delimL = 0;
int index;
int pieces=0;
int string_start=0;

char **tmp=NULL;

//Sanity Checks:
if(NULL==string || NULL==delim || NULL == exp_obj)
{
printf("Invalid params given to Cexplode!\n");
return ECexplodeRet_InvalidParams;
}
stringL = strlen(string);
delimL = strlen(delim);
if(delimL>=stringL)
{
printf("Invalid params given to Cexplode!\n");
return 0;
}
for(index=0;index<stringL-delimL;index++)
{
if(string[index]==delim[0])
{
//Check if delim was actually found
if( !memcmp(&(string[index]),delim,delimL) )
{
//token found
//let's check if token was at the beginning:
if(index==string_start)
{
string_start+=delimL;
index+=delimL-1;
continue;
}
/*
if token was not at start, then we
should add it in CexplodeStrings
*/
pieces++;
if(NULL==tmp)
tmp=malloc(sizeof(char *));
else
tmp=realloc(tmp,sizeof(char *)*pieces);
if(NULL==tmp)
{
printf("Cexplode: Malloc failed!\n");
return ECexplodeRet_InternalFailure;
}
//alloc also for \0
tmp[pieces-1]=malloc
(
sizeof(char *)*(index-string_start+1)
);
if(NULL==tmp[pieces-1])
{
printf("Cexplode: Malloc failed!\n");
return ECexplodeRet_InternalFailure;
}
memcpy(
tmp[pieces-1],
&(string[string_start]),
index-string_start
);

tmp[pieces-1][index-string_start]='\0';
string_start=index+delimL;
index+=(delimL-1);
}//delim found
}//first letter in delim found from string
}//for loop

if(memcmp(&(string[index]),delim,delimL))
index+=delimL;
if(index!=string_start)
{
pieces++;
if(NULL==tmp)
tmp=malloc(sizeof(char *));
else
tmp=realloc(tmp,sizeof(char *)*pieces);
if(NULL==tmp)
{
printf("Cexplode: Malloc failed!\n");
return ECexplodeRet_InternalFailure;
}
tmp[pieces-1]=malloc
(
sizeof(char *)*(index-string_start+1)
);
if(NULL==tmp[pieces-1])
{
printf("Cexplode: Malloc failed!\n");
return ECexplodeRet_InternalFailure;
}
memcpy
(
tmp[pieces-1],
&(string[string_start]),
index-string_start
);
tmp[pieces-1][index-string_start+1]='\0';
}
exp_obj->amnt=pieces;
exp_obj->strings=tmp;
return pieces;
}


char *Cexplode_getNth(int index,CexplodeStrings exp_obj)
{
if(exp_obj.amnt<index)
{
return NULL;
}
return exp_obj.strings[index-1];
}

char *Cexplode_getfirst(CexplodeStrings exp_obj)
{
return Cexplode_getNth(1,exp_obj);
}
void Cexplode_free(CexplodeStrings exp_obj)
{
int i=0;
for(;i<exp_obj.amnt;i++)
free(exp_obj.strings[i]);
free(exp_obj.strings);
}


Cexplode_example.c

/* ******************************************************** */
/* *
* Implementation of php's explode written in C *
* Written by Maz (2008) *
* http://maz-programmersdiary.blogspot.com/ *
* *
* You're free to use this piece of code. *
* You can also modify it freely, but if you *
* improve this, you must write the improved code *
* in comments at: *
* http://maz-programmersdiary.blogspot.com/ *
* or at: *
* http://c-ohjelmoijanajatuksia.blogspot.com/ *
* or mail the corrected version to me at *
* Mazziesaccount@gmail.com *
* *
* Revision History: *
* *
* -v0.0.1 16.09.2008/Maz *
* */
/* ******************************************************** */

#include "stdio.h"
#include "Cexplode.h"

int main(int argc,char *argv[])
{
char *string;
char *delim;
int retval;
int index=0;
char *token;
CexplodeStrings expString;
if(argc!=3)
{
printf("Test Command should be:\n");
printf
(
"<testExe> \"original string\" \"delimiter string\""
);
return -1;
}
string=argv[1];
delim=argv[2];

printf("TestString is \"%s\"\n",string);
printf("Test Delimiter is \"%s\"\n",delim);
if(0>(retval=Cexplode(string,delim,&expString)))
{
printf("CexplodeFailed!\n");
return -1;
}
else
{
//Way 1, use expString straight away:
printf("Way 1, use expString straight away:\n");
for(index=0;index<expString.amnt;index++)
{
printf
(
"token %d = %s\n",
index+1,
expString.strings[index]
);
}
/*
Way 2, you can use Cexplode_getNth,
or Cexplode_getfirst()
*/
printf(
"Way 2 use Cexplode_getNth, or Cexplode_getfirst():\n"
);
token=Cexplode_getfirst(expString);
printf("first token %s\n",token);
index=1;
while(NULL!=(token=Cexplode_getNth(++index,expString)))
{
printf("token %d = %s\n",index,token);
}
}
Cexplode_free(expString);
return 0;
}

8 comments:

  1. Cexplode and the usage example can now be downloaded in tar.gz package. (Link is at the left on the index bar)

    ReplyDelete
  2. Sweet -- this is *just* what I was looking for.

    If I ever finish the game I'm working on I'll be sure to put your name in the credits. :P

    ReplyDelete
  3. Thanks man :) I'm glad if this was usefull :)

    However I've not ran any stress tests for this piece of code, so you should propably run some tests yourself.

    ReplyDelete
  4. snip...

    "And finally, I have planned to use my Cexplode function set in IRC parser - and I have added some mysterious functions into it... So there's enchanced (and at the moment quite untested) version available. I just changed the file name to helpers.h and helpers.c (in generic/src folder). Also test/usage example is present in test/src folder. (This info is provided since according to my tracker, ~60% of people visiting this blog are looking for explode function for C)

    License terms are same as before - use/modify as pleases you - but let me know it by email or via a comment in this blog. But if you redistribute it, mention the original author (me) and this website (or the finnish equivalent: http://c-ohjelmoijanajatuksia.blogspot.com/ )"
    ...snip

    If you want to take a peek - http://teotilcan.net/svn/MazBot/

    ReplyDelete
  5. I found a serious bug from this C-explode code. (One random character may be added at the end of the last exploded string). Fixed version can be obtained http://teotilcan.net/svn/MazBot/ (generic/src/helpers.c and generic/src/helpers.h)

    Sorry for the inconvenience!

    ReplyDelete
  6. Mmm. Since link in above comment points to my development repository, code in there is broken quite often... So, here's a link into more stable repository:
    http://svn2.xp-dev.com/svn/Mazzie-mazbot/

    ReplyDelete
  7. Maybe many visitor came across this site and ask a question how to compile it? so i think i just want to add this tutorial for easier to use and understand the example.

    please make sure u save each file in 1 directory.
    example :
    Cexplode.h
    Cexplode.c
    Cexplode_example.c

    This is how to compile it:
    gcc -Wall Cexplode_example.c Cexplode.c -o test

    to run the program :
    ./test
    ./test "sayang-awak" "-"

    So the output :
    TestString is "sayang-awak"
    Test Delimiter is "-"
    Way 1, use expString straight away:
    token 1 = sayang
    token 2 = awak
    Way 2 use Cexplode_getNth, or Cexplode_getfirst():
    first token sayang
    token 2 = awak

    ReplyDelete
  8. Thank you for this addition! :)

    ReplyDelete