rendez-vous sur ArraKISS
Archives ContactATOM
whoami@ybad.name
# find . -iname

    Quelques fonctions pratiques en C

    Cette page sera alimentée de fonctions et extraits de code en C en guise d’aide mémoire. Ne prenez rien pour parfait, ces extraits peuvent certainement être améliorés.

    ecalloc, erealloc : allocation avec gestion d’erreur

    /* same thing that calloc and reallocarray but check for
     * error and exit if necessary
     */
    
    void *
    ecalloc(size_t nmemb, size_t size)
    {
    	void *p;
    
    	if ((p = calloc(nmemb, size)) == NULL)
    		err(1, "calloc");
    	return p;
    }
    
    void *
    ereallocarray(void *ptr, size_t nmemb, size_t size)
    {
    	if ((ptr = reallocarray(ptr, nmemb, size)) == NULL)
    		err(1, "reallocarray");
    
    	return ptr;
    }
    
    

    get_stream_txt: Récupérer le contenu d’un fichier ouvert

    /* return text in fp
     * the fp must be closed properly after
     * the returned string is mallocated and must be freed.
     */
    char *
    get_stream_txt(FILE *fp)
    {
    	char *buf = NULL;
    	size_t s;
    	size_t len = 0;
    	size_t bsize = 2 * BUFSIZ;
    
    	buf = ecalloc(bsize, sizeof(char));
    	while((s = fread(buf + len, 1, BUFSIZ, fp))) {
    		len += s;
    		if(BUFSIZ + len + 1 > bsize) {
    			bsize += BUFSIZ;
    			buf = ereallocarray(buf, bsize, sizeof(char));
    		}
    	}
    	buf[len] = '\0';
    	
    	return(buf);
    }
    

    get_cmd_output: Récupéérer la sortie d’une commande

    /* return the output of cmd in an allocated
     * string created by get_stream_txt().
     * It is the caller responsibility to free it later
     */
    char *
    get_cmd_output(const char *cmd)
    {
    	FILE *fp = NULL;
        char *res = NULL;
    
        if ((fp = popen(cmd, "r")) == NULL)
            err(1, "%s: %s", Error opening pipe for cmd", cmd);
    
        res = get_stream_txt(fp);
        if (pclose(fp) != 0)
            err(1, "%s %s", cmd, "not found or exited with error status");
    	
    	return res;
    }
    

    Jouons avec les strings

    Quelques fonctions pour gérer les chaînes de caractères. Ici on abuse de la fonction strlcat qui s’assure que l’on termine bien une chaîne avec le fameux '\0'. Cette dernière est présente chez OpenBSD et facilement recopiable depuis leurs sources.

    /* strlcat with error handling */
    size_t
    estrlcat(char *dst, const char *src, size_t dstsize)
    {
    	size_t size;
    	if ((size = strlcat(dst, src, dstsize)) >= dstsize)
    		err(1, "strlcat");
    
    	return size;
    }
    
    /* variadic strlcat
     * a call must end with NULL
     * to append "bar", "zoo", yo" to foo, call:
     * vestrlcat(foo, sizeof(foo), "bar", "zoo", "yo", NULL);
     */
    size_t
    vestrlcat(char *dst, size_t dstsize, ...)
    {
    	size_t size = 0;
    	char *s;
    	va_list ap;
    
    	va_start(ap, dstsize);
    
    	while ((s = va_arg(ap, char *)) != NULL) {
    		size += estrlcat(dst, s, dstsize);
    	}
    	va_end(ap);
    
    	return size;
    }
    

    Et ma favorite qui permet de fabriquer n’importe quelle chaîne de caractères. On y passe un pointeur (qui peut être NULL au départ. Tous les arguments sont assemblés pour former une longue chaîne, cette dernière étant allouée dynamiquement au besoin.

    /* 
     * Make any string 
     * add in str every argument and realloc str if necessary
     * if str is NULL, it is allocated
     * argument list **must** end with NULL
     * return str
     * str should be dynamically allocated and freed later
     * example: mkstr(&foo, "hello", " there.", NULL);
     */
    char *
    mkstr(char **str, ...)
    {
    	char *s;
    	size_t len;    /* length of str at last*/
    	va_list ap;
        va_list apcopy;
    
    	va_copy(apcopy, ap);
    
    	if (*str == NULL) {
    		*str = calloc(1, sizeof(char));
    		len = 0;
    	} else {
    		len = strlen(*str);
    	}
    
    	/* count required length */
    	va_start(ap, str);
    	while ((s = va_arg(ap, char *)) != NULL) {
    		len += strlen(s);
    	}
    	va_end(ap);
    	len++; /* \0 */
    
    	*str = ereallocarray(*str, len, sizeof(char));
    
    	/* copy */
    	va_start(apcopy, str);
    
    	while ((s = va_arg(apcopy, char *)) != NULL) {
    		estrlcat(*str, s, len);
    	}
    	va_end(apcopy);
    	return(*str);
    }
    

    efopen, efclose, evfprintf : gestion des fichiers

    On ouvre et on ferme les fichiers en gérant les erreurs

    FILE *
    efopen(const char *path, const char *mode)
    {
    	FILE *f = NULL;
    	if ((f = fopen(path, mode)) == NULL)
    		err(1, "%s: %s", "Fail to open", path);
    
    	return f;
    }
    
    int
    efclose(FILE *stream)
    {
    	int ret = 0;
    	ret = fclose(stream);
    	if (ferror(stream)) {
    		err(1,"closefile");
    	}
    	return ret;
    }
    

    On écrit dans un fichier autant de choses que l’on veut en une fois. C’est comme fprint mais avec une liste d’arguments variable.

    int
    evfprintf(FILE *stream, const char *format, va_list ap)
    {
    	int ret;
    
    	ret = vfprintf(stream, format, ap);
    	if (ret < 0)
    		err(1,"evfprintf:");
    
    	return ret;
    }
    
    int
    efprintf(FILE *stream, const char *format, ...)
    {
    	va_list ap;
    	int ret;
    
    	va_start(ap, format);
    	ret = evfprintf(stream, format, ap);
    	va_end(ap);
    
    	return ret;
    }