tiistai 16. syyskuuta 2008

ANSI C explode.

13.09.2011: Allaoleva linkki päivitetty (taas)
16.02.2010 YeeeHaw farmarit! Vai miten se pärstäkirjan suosikkiapplikaatio sen sanoikaan... Jokatapauksessa, SVN on taas pystyssä! http://xp-dev.com/svn/MazBotV4/trunk/
(generic/src kansiosta löytynee kaikki kiinnostava materiaali)


09.02.2010 Moro! Ikäviä uutisia, mutta SVN repositorio jota käytän kehitysversion ylläpitoon on tällähaavaa ongelmien kourissa. Ilmoittelen ja korjaan asioita sitämukaa kun ehdin :(




02.02.2010: Olinpa aikaansaapa. Tekaisin pikaisen API dokumentaation Cexplodesta ja muista funktioista jotka sisältyvät bottiprojektini "helperseihin". Dokumentaatio löytyy täältä. Tämänhetken filut (helpers.h ja helpers.c) ovat täällä. Makefilen joudutte itse kyhäämään, mutta se ei liene kauhean vaikeaa :) Ja jos nyt ihan ylitsepääsemättömiä ongelmia tulee, mutta haluaisitte kuitenkin käyttää funktioita, niin pieni kommentti tänne/sähköposti osoitteeseen Mazziesaccount@gmail.com, ja saatan tehdä tuosta ihan jonkinlaisen ladattavan zipin.
Ja vielä pieni pyyntö: raportoikaa kaikki bugiloiset tänne, siitä on minulle iiiiso apu! :)

Hups. Bugin pannahinen piileskelee allaolevassa versiossa - älkää käyttäkö.
Otin tämän Cexploden käyttöön uudessa bottiprojectissani, ja siellä siihen myös ilmaantuu muutamia lisäosasia tarpeen mukaan...

Täältä löydätte suht testatun ja suht stabiilin version (Cexplode löytyy nyt kansiosta generic/src/, tiedostot helpers.c ja helpers.h.)
http://xp-dev.com/svn/Mazzie-mazbot/
(subversion repository)
Tiedostoissa on joitain muitakin funktioita, ja mikäli käännösherjoja tulee, kannattaa koettaa raapia ne pois.

Allaolevassa kommentissa on linkki kehitysversioon botista, ja siinä olevan koodin toimivuudesta ei ole mitään takeita... Toisinaan se ei edes käänny :)

Monet blogini lukijat ovat etsineet C/C++ kielistä toteutusta php:n explode funktiolle. Päätin siis kirjoitella moisen, ja tässä se nyt sitten on.

Pari sanaa kuitenkin ennen lähdekoodin näyttöä:

1. Thread safety/re-entrancy.

Suurimpana ongelmana standardikirjaston strtok:ssa nään sen, ettei se ole monisäikeiseen ohjelmaan soveltuva. (siitä kirjoittelin edellisessä blogitekstissäni). Tämäkään Cexplode ei takaa monisäikeiseen ohjelmointiin soveltuvuutta, sillä siinä käytetään standardikirjaston strlen(), memcmp(), malloc(), free() ja realloc() funktioita. Kuitenkin mikäli teette ohjelmaa normaaliin nykyaikaiseen PC käyttöön, käyttäen normaaleja standardikirjastoja, on melko turvallista olettaa kyseisten funktioiden toimivan myös monisäikeisissä ohjelmissa. (Syynä on se, ettei em. funktioiden implementointi oikeastaan vaadi minkään ei re-entrantin ominaisuuden käyttöä - ja nykyään säikeiden käyttö on enemmänkin sääntö kuin poikkeus => kirjastot pyritään tekemään monisäikeiseen ohjelmaan soveltuviksi vaikkei C:n standardit sitä vaadi.)

2. ongelmat Cexplode:n käytössä.

Lue esimerkki. Mikäli jotain jää epäselväksi, kysy :)

3. Muokkaus ja käyttö.

Koodipätkää saa vapaasti käyttää, mutta mikäli muokkaat siitä parannetun version tulee sinun postata parannettu versio kommenttina joko tähän blogiin, tai http://maz-programmersdiary.blogspot.com/ blogiini, tai laittaa se minulle sähköpostilla osoitteeseen Mazziesaccount@gmail.com

Koetan ehtiä jossain välissä laittaa pakatut tiedostot ladattavaksi, mutta tällähetkellä saatte vain allaolevan copy-pastattavan version.

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;
}

3 kommenttia:

Maz kirjoitti...

Cexplode ja esimerkki sen käytöstä on nyt ladattavissa zippinä vasemmalla olevasta indexivalikosta.

Maz kirjoitti...

oops. Blogissa esitettyyn cexplode funktioon on lipsahtanut bugi. Silloin tällöin viimeisen "räjäytetyn" stringin viimeiseksi merkiksi tulee jokin satunnainen merkki. Huomasin ongelman käyttäessäni funktiota irc bot projektissani. Korjattua versiota en lisää tähän blogiin, sillä koodin ylläpito blogissa on kertakaikkiaan hankalaa.. Korjatun version löydät bot projektini versionhallinnasta osoitteesta http://teotilcan.net/svn/MazBot kansiostä generic/src tiedostot on siellä nimillä helpers.c ja helpers.h

Anonyymi kirjoitti...

Heh heh :) Voihan sitä C:llä tosiaan tehdä näitä leikki-olioita, jne. mutta kumpihan lienee sitten syntaksiltaan siistimpi siihen tarkoitukseen, C vai C++ ...

KISS