/* Chrysalide - Outil d'analyse de fichiers binaires * extstr.c - extension des fonctions relatives aux chaînes * * Copyright (C) 2009-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "extstr.h" #include #include #include /****************************************************************************** * * * Paramètres : str1 = chaîne de caractères à compléter. * * str2 = chaîne de caractères à ajouter. * * * * Description : Complète une chaîne de caractères avec une autre. * * * * Retour : Chaîne de caractères complétée, à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ char *stradd(char *str1, const char *str2) { char *result; /* Chaîne à renvoyer */ if (str1 == NULL) result = strdup(str2); else { result = (char *)realloc(str1, (strlen(str1) + strlen(str2) + 1) * sizeof(char)); strcat(result, str2); } return result; } /****************************************************************************** * * * Paramètres : str1 = chaîne de caractères à compléter. * * str2 = chaîne de caractères à ajouter. * * n = taille de la seconde chaîne. * * * * Description : Complète une chaîne de caractères avec une autre. * * * * Retour : Chaîne de caractères complétée, à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ char *strnadd(char *str1, const char *str2, size_t n) { char *result; /* Chaîne à renvoyer */ if (str1 == NULL) result = strndup(str2, n); else { result = (char *)realloc(str1, (strlen(str1) + n + 1) * sizeof(char)); strncat(result, str2, n); } return result; } /****************************************************************************** * * * Paramètres : str1 = chaîne de caractères à compléter. * * str2 = chaîne de caractères à ajouter. * * * * Description : Fait précéder une chaîne de caractères par une autre. * * * * Retour : Chaîne de caractères complétée, à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ char *strprep(char *str1, const char *str2) { char *result; /* Chaîne à renvoyer */ size_t len2; /* Taille de la seconde chaîne */ result = (char *)realloc(str1, (strlen(str1) + strlen(str2) + 1) * sizeof(char)); len2 = strlen(str2); memmove(&result[len2], result, strlen(result) + 1); memcpy(result, str2, len2); return result; } /****************************************************************************** * * * Paramètres : str1 = chaîne de caractères à analyser. * * str2 = chaîne de caractères à retrouver. * * * * Description : Compare deux chaînes de caractères en partant de la fin. * * * * Retour : -1, 0, ou 1 selon la comparaison. * * * * Remarques : - * * * ******************************************************************************/ int strrcmp(const char *str1, const char *str2) { int result; /* Bilan à renvoyer */ size_t len1; /* Longueur de la chaîne donnée*/ size_t len2; /* Longueur de la chaîne visée */ len1 = strlen(str1); len2 = strlen(str2); if (len1 <= len2) result = strcmp(str1, str2); else result = strcmp(&str1[len1 - len2], str2); return result; } /****************************************************************************** * * * Paramètres : haystack = botte de foin à fouiller. * * needle1 = aiguille à trouver et remplacer. * * needle2 = aiguille de remplacement. * * * * Description : Remplace des éléments d'une chaîne par d'autres. * * * * Retour : Adresse de la chaîne de caractères modifiée. * * * * Remarques : - * * * ******************************************************************************/ char *strrpl(char *haystack, const char *needle1, const char *needle2) { size_t inlen; /* Taille en entrée */ size_t len1; /* Taille de l'aiguille n°1 */ size_t len2; /* Taille de l'aiguille n°2 */ size_t index; /* Conversion en indice */ char *found; /* Position d'une trouvaille */ inlen = strlen(haystack) + 1; len1 = strlen(needle1); len2 = strlen(needle2); index = 0; for (found = strstr(haystack + index, needle1); found != NULL; found = strstr(haystack + index, needle1)) { index = found - haystack; if (len2 > len1) { inlen += (len2 - len1); haystack = (char *)realloc(haystack, inlen * sizeof(char *)); found = haystack + index; memmove(found + len2, found + len1, inlen - len2 - index); } else if (len2 < len1) { memmove(found + len2, found + len1, inlen - index - len1); inlen -= (len1 - len2); haystack = (char *)realloc(haystack, inlen * sizeof(char *)); found = haystack + index; } memcpy(found, needle2, len2); index += len2; } return haystack; } /****************************************************************************** * * * Paramètres : str = chaîne de caractères à manipuler. [OUT] * * * * Description : Bascule toute une chaîne de caractères en (min|maj)uscules. * * * * Retour : Pointeur sur la chaîne fournie. * * * * Remarques : - * * * ******************************************************************************/ char *_strxxx(char *str, int (* fn) (int)) { size_t max; /* Empleur du parcours */ size_t i; /* Boucle de parcours */ max = strlen(str); for (i = 0; i < max; i++) str[i] = fn(str[i]); return str; } /****************************************************************************** * * * Paramètres : str = chaîne de caractères à traiter. [OUT] * * delim = mot de séparation entre les mots identifiés. * * * * Description : Extrait un mot d'une chaîne selon des séparations longues. * * * * Retour : Chaîne de caractères cernée ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *strtok_w(char **str, const char *delim) { char *result; char *haystack; char *next; const char *diter; haystack = *str; if (haystack == NULL) result = NULL; else { result = haystack; next = strstr(haystack, delim); if (next != NULL) { for (diter = delim; *diter; diter++, next++) *next = '\0'; } *str = next; } return result; } /****************************************************************************** * * * Paramètres : str = chaîne de caractères à traiter. * * delim = séparateur entre les mots. * * count = nombre de mots trouvés. [OUT] * * * * Description : Extrait une liste de mots d'une chaîne. * * * * Retour : Tableau construit à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ char **strtoka(const char *str, const char *delim, size_t *count) { char **result; /* Tableau à retourner */ char *tmp; /* Sauvegarde modifiable */ char *word; /* Nouveau mot détecté */ result = NULL; *count = 0; tmp = strdup(str); for (word = strtok(tmp, delim); word != NULL; word = strtok(NULL, delim)) { result = (char **)realloc(result, ++(*count) * sizeof(char *)); result[*count - 1] = strdup(word); } free(tmp); return result; } /****************************************************************************** * * * Paramètres : input = chaîne de caractères à traiter. * * * * Description : S'assure qu'une chaîne de caractères tient sur une ligne. * * * * Retour : Adresse de la chaîne de caractères modifiée. * * * * Remarques : - * * * ******************************************************************************/ char *escape_crlf(char *input) { size_t inlen; regex_t preg; size_t curpos; regmatch_t pmatch[2]; inlen = strlen(input); /* On considère que la compilation est toujours bonne... */ regcomp(&preg, "(\t|\n|\r)", REG_EXTENDED | REG_ICASE); for (curpos = 0; regexec(&preg, &input[curpos], 2, pmatch, 0) != REG_NOMATCH; ) { inlen += 1 + 1; input = (char *)realloc(input, inlen * sizeof(char *)); memmove(&input[curpos + pmatch[1].rm_eo + 1], &input[curpos + pmatch[1].rm_eo], inlen - 1 - curpos - pmatch[1].rm_eo); switch (input[curpos + pmatch[1].rm_so]) { case '\t': memcpy(&input[curpos + pmatch[1].rm_so], "\\t", 2); break; case '\n': memcpy(&input[curpos + pmatch[1].rm_so], "\\n", 2); break; case '\r': memcpy(&input[curpos + pmatch[1].rm_so], "\\r", 2); break; } curpos += pmatch[1].rm_eo + 1; } regfree(&preg); return input; } /****************************************************************************** * * * Paramètres : input = chaîne de caractères à traiter. * * max = taille maximale de chaîne acceptable. * * * * Description : Borne la taille d'une chaîne à une valeur donnée. * * * * Retour : Adresse de la chaîne de caractères ou input si pas besoin. * * * * Remarques : - * * * ******************************************************************************/ char *ellipsis(char *input, size_t max) { char *result; /* Chaîne à retourner */ if (strlen(input) > max) { result = strndup(input, max); result = stradd(result, "..."); free(input); } else result = input; return result; } /****************************************************************************** * * * Paramètres : str = chaîne à analyser. * * prefix = chaîne à retrouver en extrémité éventuellement. * * start = premier caractère hors préfixe. [OUT] * * * * Description : Détermine si une chaîne débute par une autre. * * * * Retour : true si le préfixe a été identifié, ou false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _startswith(const char *str, const char *prefix, const char **start) { bool result; /* Bilan à faire remonter */ size_t len; /* Taille de la chaîne soumise */ size_t preflen; /* Taille du préfixe */ result = false; len = strlen(str); preflen = strlen(prefix); if (len > preflen) { result = (strncmp(str, prefix, preflen) == 0); if (result && start != NULL) *start = &str[preflen]; } return result; } /****************************************************************************** * * * Paramètres : str = chaîne à analyser. * * suffix = chaîne à retrouver en extrémité éventuellement. * * end = premier caractère du préfixe. [OUT] * * * * Description : Détermine si une chaîne se termine par une autre. * * * * Retour : true si le suffixe a été identifié, ou false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _endswith(const char *str, const char *suffix, const char **end) { bool result; /* Bilan à faire remonter */ size_t len; /* Taille de la chaîne soumise */ size_t suflen; /* Taille du suffixe */ const char *tmp; /* Stockage temporaire */ result = false; len = strlen(str); suflen = strlen(suffix); if (len > suflen) { if (end == NULL) end = &tmp; *end = &str[len - suflen]; result = (strncmp(*end, suffix, suflen) == 0); } return result; }