// EXEMPLE DE PARSING PARFAIT D'UNE LIGNE IRC. // Le code ci-dessous est ?tudi? pour n'utiliser aucune lib externe (sauf memory.h, stdio.h), // et ?tre impossible a faire crasher, meme en cas de r?ception d'une ligne totalement incorrecte. // yclick 15/02/2005 // NB: Ce code est pr?vu pour fonctionner sous un systeme utilisant des retour chariot type UNIX. // (sauf la fonction irc_parse qui est portable sous n'importe kel os) #include #include #define test_eol(c) ((c == '\r') || (c == '\n')) typedef struct { char signature[256]; // signature char commande[256]; // commande (num?rique ou texte) int n; // nombre d'arguments dans le milieu char milieu[16][256]; // tableau de chaines. (arguments du milieu) char complement[512]; // complement. } IRC_LINE; bool irc_parse(char *szLine, IRC_LINE *line) { char *pr = szLine; // initialise le pointeur de lecture en debut de ligne char *ptmp; // un pointeur temporaire // // Signature (argument optionnel) // if(*pr == ':') { pr++; // Saute les ':' ptmp = pr; // met un "marque page" pour m?moriser la position du d?but // Avance au prochain espace ou fin de ligne ou fin de chaine for(;(*pr) && (*pr != ' ') && (!test_eol(*pr)); pr++); // Recopie la signature au bon endroit dans notre structure memcpy(line->signature, ptmp, pr-ptmp); // Saute l'espace suivant la signature si espace il y a if(*pr == ' ') pr++; } // // Commande (argument obligatoire) // ptmp = pr; // met un "marque page" pour m?moriser la position du d?but // Avance au prochain espace ou fin de ligne ou fin de chaine for(;(*pr) && (*pr != ' ') && (!test_eol(*pr)); pr++); // Recopie la signature au bon endroit dans notre structure memcpy(line->commande, ptmp, pr-ptmp); // Saute l'espace suivant la commande si espace il y a if(*pr == ' ') pr++; // // Milieu (argument optionel) // for(; (*pr) && (!test_eol(*pr)); line->n++) { // Si le compl?ment est atteind, sortie de boucle if(*pr == ':') break; ptmp = pr; // met un "marque page" pour m?moriser la position du d?but // Avance au prochain espace ou fin de ligne ou fin de chaine for(;(*pr) && (*pr != ' ') && (!test_eol(*pr)); pr++); // Recopie la signature au bon endroit dans notre structure memcpy(line->milieu[line->n], ptmp, pr-ptmp); // Saute l'espace suivant l'argument si espace il y a if(*pr == ' ') pr++; } // // Compl?ment (argument optionel) // if(*pr == ':') { pr++; // Saute les ':' ptmp = pr; // met un "marque page" pour m?moriser la position du d?but // Avance a la fin de ligne ou fin de chaine for(;(*pr) && (!test_eol(*pr)); pr++); // Recopie la signature au bon endroit dans notre structure memcpy(line->complement, ptmp, pr-ptmp); } // Si tout c'est bien d?roul? nous devrions ?tre pile-poil en fin de ligne return(!memcmp(pr, "\r\n", 2)); } int main() { char szLine_sample[] = ":nick!uname@host KICK #salon mec :motif de kick \r\n"; // exemple 1 (toute options) //char szLine_sample[] = ":nick!uname@host MODE #salon +o mec\r\n"; // exemple 2 (sans complement) //char szLine_sample[] = ":nick!uname@host NICK :newnick\r\n"; // exemple 3 (sans milieu) //char szLine_sample[] = "PING :ta mere en short\r\n"; // exemple 4 (sans signature ni milieu) //char szLine_sample[] = "\r\n"; // exemple de ligne vide //char szLine_sample[] = ""; // exemple de ligne NULL (donc incorrecte) //char szLine_sample[] = "ERROR :ya pas de retour chariot :)"; // exemple de ligne sans CRLF (donc incorrecte) // Variables ? remplir IRC_LINE line; // Initialisation de notre structure memset(&line, 0, sizeof(IRC_LINE)); if(irc_parse(szLine_sample, &line)) { printf("La ligne [%s] ? ?t? correctement pars?e:\n\n", szLine_sample); printf("Signature : %s\n", line.signature); printf("Commande : %s\n", line.commande); for(int i=0; i