Voici un .c et un .h que j'utilise assez frequemment dans mes codes. Il s'agit de quelques fonctions passe-partout, essentiellement de manipulation de chaines de caractère. Le .h regroupe une liste de #defines correspondant à des fonctions classiques mais encadrées de tests.
tools.h
L'inévitable license, ici une license BSD
/* * Copyright (c) 2005 * iMil <imil@gcu.info>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by iMil. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY iMil AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL iMil OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $Id: tools.h,v 1.6 2005/03/12 09:54:44 imil Exp $ */
On verifie que ce header n'a pas déjà été inclu
#ifndef _TOOLS_H #define _TOOLS_H
Et on inclut quelques headers nécessaires
#include <stdio.h> #include <stdarg.h> #include <stdint.h> #include <limits.h> #include <sys/queue.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <string.h> #include <err.h>
On place quelques constantes
#define MAXLEN LINE_MAX #define MIDLEN 256 #define SMLLEN 32 #define D_WARN 5 #define D_INFO 10 #define T_FALSE 0 #define T_TRUE 1
Et nous déclarons nos fonctions “helper”.
Ces deux premiers #defines sont des conteneurs des fonctions read(2) et close(2) dans un contexte threadé qui sortent du thread courant si l'operation d'I/O echoue
#define R_READ(fd, buf, len) \ if (read(fd, buf, len) < 0) { \ warn("read()"); \ pthread_exit(NULL); \ } #define R_CLOSE(fd) \ do { \ close(fd); \ pthread_exit(NULL); \ } while (/* CONSTCOND */ 0)
Voici une serie de conteneurs de fonctions d'allocation mémoire et copie chaines de caractères, avec dans tous les cas :
#define XMALLOC(elm, size) \ do { \ elm = malloc(size); \ if (elm == NULL) \ err(1, "can't allocate memory\n"); \ memset(elm, 0, size); \ } while (/* CONSTCOND */ 0) #define XSTRDUP(dest, src) \ do { \ if (src == NULL) \ dest = NULL; \ else { \ dest = strdup(src); \ if (dest == NULL) \ err(1, "can't strdup %s\n", src); \ } \ } while (/* CONSTCOND */ 0) #define XREALLOC(elm, size) \ do { \ void *telm; \ if (elm == NULL) \ XMALLOC(elm, size); \ else { \ telm = realloc(elm, size); \ if (telm == NULL) \ err(1, "can't allocate memory\n"); \ elm = telm; \ } \ } while (/* CONSTCOND */ 0) #define DSTSRC_CHK(dst, src) \ if (dst == NULL) { \ warn("NULL destination"); \ break; \ } \ if (src == NULL) { \ warn("NULL source"); \ break; \ } #define XSTRCPY(dst, src) \ do { \ DSTSRC_CHK(dst, src); \ strcpy(dst, src); \ } while (/* CONSTCOND */ 0) #define XSTRCAT(dst, src) \ do { \ DSTSRC_CHK(dst, src); \ strcat(dst, src); \ } while (/* CONSTCOND */ 0) #define XFREE(elm) \ do { \ if (elm != NULL) { \ free(elm); \ elm = NULL; \ } \ } while (/* CONSTCOND */ 0)
Un petit typedef créant un type “booléen”
typedef uint8_t T_Bool;
Et la liste des fonctions disponibles dans tools.c
/* "nettoie" une chaine de caractères de \n et \r */ extern int trimcr(char *); /* * divise une chaine de caractères en une liste de pointeurs vers des chaines * fonction d'un délimiteur et renvoie cette liste * ATTENTION: cette liste et ses membres sont alloués */ extern char **splitstr(char *, const char *); /* libère une liste créée avec splistr (ou de type similaire) */ extern void free_list(char ***); /* * revoie une chaine dans laquelle la le premier const char * est remplacé par le * second */ extern char *strreplace(char *, const char *, const char *); /* * "coupe" une chaine à l'indice passé en second paramètre et finit la chaine par * "..." */ extern void cut_str(char *, int); /* extention de printf orientée debugging, fonction du premier paramètre */ extern void d_printf(uint8_t, char *, ...); /* renvoie la laveur minimale des deux parametres */ extern int min(int, int); /* renvoie la valeur maximale des deux paramètres */ extern int max(int, int); /* * "remplit" la chaine de caractères avec le second parametre, jusqu'à l'indice passé * dans le 3eme parametre */ extern void line_padding(char *, char, int); /* renvoie la taille d'une liste */ extern int listlen(const char **); /* * renvoie une liste de chaines correspondant à la sortie de la commande passée en * 1er parametre. Le second parametre, s'il n'est pas NULL, permet de ne renvoyer que * les sorties contenant la chaine passée */ extern char **exec_list(const char *, const char *); /* verification de la présence du second parametre dans la liste passée en 1er param */ extern T_Bool is_listed(const char **, const char *); /* client TCP minimal: 1er parametre: host, second parametre: port */ extern int tcpclient(char *, int); #endif
tools.c
/* * Copyright (c) 2005 * iMil <imil@gcu.info>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by iMil. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY iMil AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL iMil OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $Id: tools.c,v 1.3 2005/03/12 09:54:44 imil Exp $ */ #include "tools.h" __inline int trimcr(char *str) { uint16_t len; if (str == NULL) return (-1); len = strlen(str); while (len--) if ((str[len] == '\r') || (str[len] == '\n')) str[len] = '\0'; return (0); } char ** splitstr(char *str, const char *sep) { int i, size; char *p, *tmp, **split; for (i = 0, size = 0; str[i] != '\0'; i++) if (str[i] == *sep) size++; /* size = number of separators + 1 member + NULL */ size += 2; XMALLOC(split, size * sizeof(char *)); i = 0; for (p = str; p != NULL;) while ((tmp = strsep(&p, sep)) != NULL) { if (*tmp != '\0') { while (*tmp == ' ' || *tmp == '\t') tmp++; XSTRDUP(split[i], tmp); i++; } } split[i] = NULL; return(split); } void free_list(char ***list) { int i; char **plist; if (*list != NULL) { plist = *list; for (i = 0; plist[i] != NULL; i++) XFREE(plist[i]); XFREE(*list); } } void cut_str(char *str, int maxlen) { int len, i, j; if (str == NULL) return; len = strlen(str); if (len > maxlen) { j = 0; /* step back */ for (i = maxlen - j; j < 3; j++) str[i + j] = '.'; str[i + j] = '\0'; } } int verbose = 10; /* debug printf, show info if global verbose >= verbosity */ void d_printf(uint8_t verbosity, char *fmt, ...) { char buffer[MAXLEN]; if (verbose >= verbosity ) { va_list args; va_start(args, fmt); vsnprintf(buffer, MAXLEN, fmt, args); fprintf(stderr, "%s", buffer); va_end(args); } } __inline int max(int a, int b) { return (a > b ? a : b); } __inline int min(int a, int b) { return (a < b ? a : b); } int tcpclient(char *host, int port) { int s; struct sockaddr_in sa; struct hostent *he; if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { warn("socket"); return (-1); } bzero(&sa, sizeof sa); sa.sin_family = AF_INET; sa.sin_port = htons(port); if ((he = gethostbyname(host)) == NULL) { herror(host); return (-1); } bcopy(he->h_addr_list[0],&sa.sin_addr, he->h_length); if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) { warn("connect"); close(s); return (-1); } return (s); } /* CAUTION, this function assume you know how long your line is ! */ void line_padding(char *line, char fill, int len) { int i; char *p; if (line == NULL || fill == 0 || len == 0) return; i = strlen(line); p = &line[i]; for (; i < len; i++) p[i] = fill; p[i] = '\0'; } char * strreplace(char *str, const char *from, const char *to) { int fromlen, tolen, i; char *p, *ret, buf[MAXLEN]; memset(buf, 0, MAXLEN); fromlen = strlen(from); /* keep space for \0's strcat */ tolen = strlen(to) + 1; for (i = 0, p = str; *p != 0;) { if (strncmp(p, from, fromlen) == 0) { strncat(buf, to, tolen); p += fromlen; i += tolen; } else { buf[i] = *p; p++; i++; } } buf[i] = '\0'; XSTRDUP(ret, buf); return(ret); } int listlen(const char **list) { int i; for (i = 0; list[i] != NULL; i++); return(i); } /* execute a command and receive result on a char ** */ char ** exec_list(const char *cmd, const char *match) { FILE *fp; int size; char **res, *rawlist, buf[MAXLEN]; if ((fp = popen(cmd, "r")) == NULL) return(NULL); rawlist = NULL; size = 0; while (fgets(buf, MAXLEN, fp) != NULL) { if (match == NULL || strstr(buf, match) != NULL) { size += (strlen(buf) + 1) * sizeof(char); XREALLOC(rawlist, size); strcat(rawlist, buf); } } pclose(fp); if (rawlist == NULL) return(NULL); res = splitstr(rawlist, "\n"); XFREE(rawlist); return(res); } T_Bool is_listed(const char **list, const char *item) { for (; *list != NULL; list++) if (strcmp(item, *list) == 0) return(T_TRUE); return(T_FALSE); }