GNT sans publicité, site mobile, fonctionnalitées exclusives...

extraire une sous-chaîne

Le
gabriel
bonsoir,

je suis en train de jouer avec un serveur pop et je veux récupérer le
nbre de messages dans la boite.

j'ai ca dans mon buffer :
+OK maildrop ready, 1701 messages (17596741 octets) (5796222 1073741824)

Je veux le "1701".

Ma fonction, non finie, suit.
Je développe sous Linux.
Ce qui m'intéresse avant tout est de savoir quelle est la bonne méthode
pour récupérer une substring dans un tableau de caractères en C.

Cette fonction n'inclut pour l'instant aucun contrôle de mémoire, de
longueur etc.

int getNumberOfMessages(char* buffer)
{
// +OK maildrop ready, 1701 messages (17596741 octets) (5796222 1073741824)
int MsgsQn = 0;
char* temp;
char* cp = strdup(buffer);
char c;
temp = strrchr (cp, ',');
short i = 0;
char *startPoint;

startPoint = temp ;
startPoint++;
// Determine the position of the "m" letter
while (c != 'm')
{
c = *temp;
temp++;
i++;
}
i--;
char* def = malloc(strlen(buffer));
strncpy(def,startPoint,i);
i=0;
while (i<strlen(def))
{
if (*def != ' ')
{
strcat(temp,def);
}
def++;
i++;
}


return MsgsQn;
}

On ne se moque pas, je débute en C :)
Si je suis pas à la bonne adresse, envoyez-moi sur un forum dédié à la
programmation en C sur Linux. Mais je suis surtout intéressé par
l'approche, pas les librairies.

Merci pour votre aide !
Lire les 21 réponses

Questions / Réponses high-tech
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 5
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Harpo
Le #1008384
gabriel wrote:

bonsoir,

je suis en train de jouer avec un serveur pop et je veux récupérer le
nbre de messages dans la boite.

j'ai ca dans mon buffer :
+OK maildrop ready, 1701 messages (17596741 octets) (5796222
1073741824)

Je veux le "1701".
Ma fonction, non finie, suit.
Je développe sous Linux.
Ce qui m'intéresse avant tout est de savoir quelle est la bonne
méthode pour récupérer une substring dans un tableau de caractères en
C.


$ Man string
peut aider.

Cette fonction n'inclut pour l'instant aucun contrôle de mémoire, de
longueur etc....


Elle est cependant laborieuse...
Tu n'as pas besoin de strdup() et de malloc(), ça coûte cher et s'en
passer évite d'oublier les free().
Tu n'as pas besoin de strlen(), ça coûte cher, ni de strcat() ni
strncpy(), idem et en plus c'est casse-gueule.
Tu utilise strrchr(), strchr() aurait été plus heureux car strrchr()
doit scanner le string jusqu'à la fin ce qui est inutile dans ton cas.

Il y a une solution simple :
. Tu recherches la virgule par strchr()
. Tu incrémentes ton pointeur de 1, après avoir vérifié que la virgule a
bien été trouvée.
. Tu utilises strtoul pour récupérer le nombre de messages (ta fonction
pourrait avec profit retourner un long) et tu vérifies errno.
. En cas de condition anormale, tu pourrais renvoyer un nombre négatif
eventuellement printer un message si ce n'est pas la responsabilité de
l'appelant.

Je te laisse faire cet exercice, poste ensuite ton code, on verra si on
peut l'améliorer.

Comme définition de la fonction, je te conseillerais :
long getNumberOfMessages(const char * buffer);
enfin, j'aurais mis get_nb_msgs, je trouve ça plus lisible et moins
java-ish, se rappeler aussi que les noms de fonction ont une taille
maximale (26 ou 27 je crois) en C.

On ne se moque pas, je débute en C :)


Même les gurus ont commencé débutants.

Si je suis pas à la bonne adresse, envoyez-moi sur un forum dédié à la
programmation en C sur Linux.


Ta question n'a rien de spécifique à Linux, tu es dans le bon forum. Je
ne crois pas qu'il y ait de forum fr sur la programmation sous Linux
mais si tu as des questions vraiment spécifiques à Linux tu trouvera
probablement de l'aide sur fr.comp.os.unix.

Mais je suis surtout intéressé par
l'approche, pas les librairies.


Toutes les fonctions str... que tu as utilisées sont des fonctions d'une
librairie, oops bibliuthèque !

Sinon pour faire des choses un peu plus complexes tu pourrais gagner à
utiliser une bibliothèque d'expressions régulières.

Dernier conseil, ne fais pas les tests directement sur ta mailbox :-)
--
http://patrick.davalan.free.fr/

Sylvain
Le #1008383
gabriel wrote on 25/06/2006 23:41:

int getNumberOfMessages(char* buffer)
{
// +OK maildrop ready, 1701 messages (17596741 octets) (5796222
1073741824)
int MsgsQn = 0;
char* temp;
char* cp = strdup(buffer);


ceci duplique ta chaine et tu ne libères pas cp, 1iere fuite

char c;
temp = strrchr (cp, ',');
short i = 0;
char *startPoint;

startPoint = temp ;
startPoint++;
// Determine the position of the "m" letter
while (c != 'm')
{
c = *temp;
temp++;
i++;
}
i--;
char* def = malloc(strlen(buffer));


2ieme chaine allouée non libérée.

strncpy(def,startPoint,i);
i=0;
while (i<strlen(def))
{
if (*def != ' ')
{
strcat(temp,def);
}
def++;
i++;
}


return MsgsQn;


tu n'as jamais affecté MsgsQn ?! sa valeur est toujours le 0 d'init.
}


on peut surement faire plus court:
- tester que le buffer est une réponse positive du serveur de mails

if (strstr(buffer, "+OK") != buffer)
error

- skipper tous les caractères alphabétiques et ponctuation

char* ptr = buffer;
while (*ptr && *ptr < '0' || *ptr > '9')
++ptr;

- convertir alors la chaine pointée (1ier digit du nombre)

int count = atoi(ptr);

(atoi interprète les digits décimaux seuls, le texte placé après ne le
gène donc pas).

Merci pour votre aide !


de rien, je passais par là :)

Sylvain.

Pierre Maurette
Le #958652
bonsoir,


Bijôr,


j'ai ca dans mon buffer :
+OK maildrop ready, 1701 messages (17596741 octets) (5796222 1073741824)

Je veux le "1701".


Si tel est le cahier des charges, je vous propose:

int getNumberOfMessages(char* buffer)
{
return 1701;
}


Ma fonction, non finie, suit.
Je développe sous Linux.
Ce qui m'intéresse avant tout est de savoir quelle est la bonne méthode pour
récupérer une substring dans un tableau de caractères en C.

Cette fonction n'inclut pour l'instant aucun contrôle de mémoire, de longueur
etc....

int getNumberOfMessages(char* buffer)
{
// +OK maildrop ready, 1701 messages (17596741 octets) (5796222 1073741824)
int MsgsQn = 0;
[...]
return MsgsQn;
}


Vous pouvez simplifier et sécuriser:

int getNumberOfMessages(char* buffer)
{
return 0;
}

Sérieusement, quel que soit le langage, il faut définir le problème. Je
le fais donc, ce n'est qu'une proposition:

- buffer est un pointeur valide non NULL. Sinon, vérifier. Sachant
qu'on ne peut en C se prémunir d'un pointeur non NULL et non valide.
Donc, nous considérons buffer non NULL mais pouvant pointer vers une
chaîne vide "".

- Parce que ce n'est pas plus cher et c'est plus confortable, on
s'interdit de modifier la zone pointée par buffer. Le prototype sera
donc:
int getNumberOfMessages(const char* buffer);

- Je considère que c'est la virgule qui va déterminer la position du
bout de chaîne correspondant à l'entier. Quelques cas:

+OK maildrop ready, 1701 messages (17596741 octets) (5796222
1073741824)
--> renvoie 1701

+OK maildrop ready, 0 messages (17596741 octets) (5796222 1073741824)
--> renvoie 0

+OK maildrop ready, pas de messages
--> renvoie 0

+OK maildrop ready pas de messages
--> renvoie 0

On peut proposer:

const char SEPARATEUR = ',';
/**
* Renvoie l'entier suivant le premier SEPARATEUR trouvé dans buffer,
* 0 si pas de SEPARATEUR
* 0 si pas d'entier valide après SEPARATEUR
*/
int getNumberOfMessages(const char* buffer)
{
while(*buffer != '' && *buffer++ != SEPARATEUR){/* nada */}
return (int)strtol(buffer, (char**)NULL, 10);
}

Notez qu'après le while(), buffer pointera soit vers le '', soit vers
le caractère SUIVANT le premier SEPARATEUR. La même (avec test de NULL)
en moins compact:

int getNumberOfMessages(const char* buffer)
{
int retour = 0;
if(buffer != NULL)
{
int fini = 0;
while(!fini)
{
if(*buffer == '')
{
fini = 1;
}
else
{
if(*buffer == SEPARATEUR)
{
fini = 1;
}
buffer++;
}
}
retour = (int)strtol(buffer, (char**)NULL, 10);
}
return retour;
}

Le retour en int c'est peut-être "dommage". On peut facilement
retourner long, long long et les unsigned correspondant. En retournant
un type signé, vous pourriez retourner 0 pour 0 messages, et -1 pour
une erreur.

On ne se moque pas, je débute en C :)
Si je suis pas à la bonne adresse, envoyez-moi sur un forum dédié à la
programmation en C sur Linux. Mais je suis surtout intéressé par l'approche,
pas les librairies.


Les fonctions de la bibliothèque standard sont nécessaires au moins
parce qu'elle masquent la diversité des plateformes et permettent
d'écrire portable. Dans l'exemple ci-dessus, j'ai coupé la poire en
deux, en n'utilisant pas de fonction de recherche dans les chaînes,
mais en profitant de la puissance de strtol().

--
Pierre Maurette

Xavier Roche
Le #958651
je suis en train de jouer avec un serveur pop et je veux récupérer le
nbre de messages dans la boite.
+OK maildrop ready, 1701 messages (17596741 octets) (5796222 1073741824)


Tout d'abord, je pense que ce n'est pas la bonne méthode. La bonne
méthode est probablement de récupérer la valeur de la réponse "EXISTS"
(ou "RECENT" pour le nombre de messages récents) suite à une commande
"SELECT" (ou "EXAMINE" en lecture seule), car le message de réponse ne
dépendra pas alors du serveur. Je ne cacherai pas que IMAP n'est pas le
protocole le plus zen à utiliser (gestion des réponses non sollicitées,
par exemple), au passage.

Je veux le "1701".


/* Renvoie le Nième token d'une chaîne de caractères
(ou la fin de la chaîne en cas de dépassement) */
static const char *getNthToken(const char *respLine, int n) {
for( ; *respLine != 0 && n > 0 ; respLine++) {
if (isspace(*respLine)) {
n--;
}
}
return respLine;
}

/* Renvoie le Nième token d'une chaîne de caractères sous
la forme d'un entier, ou -1 en cas d'erreur */
static int *getNthTokenNum(const char *respLine, int n) {
int value;
const char *pos = getNthToken(respLine, n);
if (sscanf(pos, "%d", &value) == 1) {
return value;
}
return -1; /* default value (error) */
}

..
int number_of_messages = getNthTokenNum("+OK maildrop ready, 1701
messages (17596741 octets) (5796222 1073741824)", 3);
if (number_of_messages == -1) {
fprintf(stderr, "* bad server valuen");
abort();
}
printf("value == %dn", number_of_messages);

On ne se moque pas, je débute en C :)


Faut bien commencer un jour :p

Emmanuel Delahaye
Le #958645
+OK maildrop ready, 1701 messages (17596741 octets) (5796222 1073741824)

Je veux le "1701".


Si le format est régulier et que c'est la valeur numérique qui
t'interesse, chercher la ',' avec strchr(), avancer de 1, passer la
suite à strtoul(). 1701 sera directement traduit en numérique (unsigned
long). Une vérification est possible avec le 2è paramètre...

--
A+

Emmanuel Delahaye

Publicité
Suivre les réponses
Poster une réponse
Anonyme