[pacman-dev] [PATCH 1/3] Add strndup fallback function to libalpm util
The same fallback we are currently using in the pacman frontend. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/util.c | 22 ++++++++++++++++++++++ lib/libalpm/util.h | 5 +++++ 2 files changed, 27 insertions(+), 0 deletions(-) diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 2eee5e4..81d950e 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -937,4 +937,26 @@ long _alpm_parsedate(const char *line) return(atol(line)); } +#ifndef HAVE_STRNDUP +/* A quick and dirty implementation derived from glibc */ +static size_t strnlen(const char *s, size_t max) +{ + register const char *p; + for(p = s; *p && max--; ++p); + return(p - s); +} + +char *strndup(const char *s, size_t n) +{ + size_t len = strnlen(s, n); + char *new = (char *) malloc(len + 1); + + if (new == NULL) + return NULL; + + new[len] = '\0'; + return (char *) memcpy(new, s, len); +} +#endif + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index be5c1d9..015e9bf 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -50,6 +50,7 @@ #define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) /* This strdup macro is NULL safe- copying NULL will yield NULL */ #define STRDUP(r, s, action) do { if(s != NULL) { r = strdup(s); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0) +#define STRNDUP(r, s, l, action) do { if(s != NULL) { r = strndup(s, l); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0) #define FREE(p) do { free(p); p = NULL; } while(0) @@ -101,6 +102,10 @@ long _alpm_parsedate(const char *line); char *strsep(char **, const char *); #endif +#ifndef HAVE_STRNDUP +char *strndup(const char *s, size_t n); +#endif + /* check exported library symbols with: nm -C -D <lib> */ #define SYMEXPORT __attribute__((visibility("default"))) #define SYMHIDDEN __attribute__((visibility("internal"))) -- 1.7.3.5
Remove the need for an unconditional string duplication by using pointer arithmetic instead, and strndup() instead of an unspecified-length strdup(). This should reduce memory churn a fair amount as this is called pretty frequently during database loads. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/deps.c | 53 +++++++++++++++++++-------------------------------- 1 files changed, 20 insertions(+), 33 deletions(-) diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 3d4b1df..a7203b4 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -322,8 +322,6 @@ static int dep_vercmp(const char *version1, pmdepmod_t mod, int _alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep) { alpm_list_t *i; - const char *pkgname = pkg->name; - const char *pkgversion = pkg->version; int satisfy = 0; /* check (pkg->name, pkg->version) */ @@ -331,8 +329,8 @@ int _alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep) && pkg->name_hash != dep->name_hash) { /* skip more expensive checks */ } else { - satisfy = (strcmp(pkgname, dep->name) == 0 - && dep_vercmp(pkgversion, dep->mod, dep->version)); + satisfy = (strcmp(pkg->name, dep->name) == 0 + && dep_vercmp(pkg->version, dep->mod, dep->version)); if(satisfy) { return(satisfy); } @@ -366,55 +364,44 @@ int _alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep) pmdepend_t *_alpm_splitdep(const char *depstring) { pmdepend_t *depend; - char *ptr = NULL; - char *newstr = NULL; + const char *ptr, *version = NULL; if(depstring == NULL) { return(NULL); } - STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL)); CALLOC(depend, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL)); /* Find a version comparator if one exists. If it does, set the type and * increment the ptr accordingly so we can copy the right strings. */ - if((ptr = strstr(newstr, ">="))) { + if((ptr = strstr(depstring, ">="))) { depend->mod = PM_DEP_MOD_GE; - *ptr = '\0'; - ptr += 2; - } else if((ptr = strstr(newstr, "<="))) { + version = ptr + 2; + } else if((ptr = strstr(depstring, "<="))) { depend->mod = PM_DEP_MOD_LE; - *ptr = '\0'; - ptr += 2; - } else if((ptr = strstr(newstr, "="))) { + version = ptr + 2; + } else if((ptr = strstr(depstring, "="))) { /* Note: we must do =,<,> checks after <=, >= checks */ depend->mod = PM_DEP_MOD_EQ; - *ptr = '\0'; - ptr += 1; - } else if((ptr = strstr(newstr, "<"))) { + version = ptr + 1; + } else if((ptr = strstr(depstring, "<"))) { depend->mod = PM_DEP_MOD_LT; - *ptr = '\0'; - ptr += 1; - } else if((ptr = strstr(newstr, ">"))) { + version = ptr + 1; + } else if((ptr = strstr(depstring, ">"))) { depend->mod = PM_DEP_MOD_GT; - *ptr = '\0'; - ptr += 1; + version = ptr + 1; } else { - /* no version specified - copy the name and return it */ + /* no version specified, leave version and ptr NULL */ depend->mod = PM_DEP_MOD_ANY; - STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL)); - depend->name_hash = _alpm_hash_sdbm(depend->name); - depend->version = NULL; - free(newstr); - return(depend); } - /* if we get here, we have a version comparator, copy the right parts - * to the right places */ - STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL)); + /* copy the right parts to the right places */ + STRNDUP(depend->name, depstring, ptr - depstring, + RET_ERR(PM_ERR_MEMORY, NULL)); depend->name_hash = _alpm_hash_sdbm(depend->name); - STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL)); - free(newstr); + if(version) { + STRDUP(depend->version, version, RET_ERR(PM_ERR_MEMORY, NULL)); + } return(depend); } -- 1.7.3.5
We don't need to create a temporary copy of the string if we are smart with our pointer manipulation and string copying. This saves a bunch of string duplication during database parsing, both local and sync. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/util.c | 27 +++++++++++++-------------- 1 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 81d950e..7a73c6f 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -864,25 +864,23 @@ int _alpm_splitname(const char *target, pmpkg_t *pkg) * package name can contain hyphens, so parse from the back- go back * two hyphens and we have split the version from the name. */ - char *tmp, *p, *q; + const char *version, *end; if(target == NULL || pkg == NULL) { return(-1); } - STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1)); - p = tmp + strlen(tmp); + end = target + strlen(target); /* remove any trailing '/' */ - while (*(p - 1) == '/') { - --p; - *p = '\0'; + while (*(end - 1) == '/') { + --end; } /* do the magic parsing- find the beginning of the version string * by doing two iterations of same loop to lop off two hyphens */ - for(q = --p; *q && *q != '-'; q--); - for(p = --q; *p && *p != '-'; p--); - if(*p != '-' || p == tmp) { + for(version = end - 1; *version && *version != '-'; version--); + for(version = version - 1; *version && *version != '-'; version--); + if(*version != '-' || version == target) { return(-1); } @@ -890,16 +888,17 @@ int _alpm_splitname(const char *target, pmpkg_t *pkg) if(pkg->version) { FREE(pkg->version); } - STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1)); - /* insert a terminator at the end of the name (on hyphen)- then copy it */ - *p = '\0'; + /* version actually points to the dash, so need to increment 1 and account + * for potential end character */ + STRNDUP(pkg->version, version + 1, end - version -1, + RET_ERR(PM_ERR_MEMORY, -1)); + if(pkg->name) { FREE(pkg->name); } - STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1)); + STRNDUP(pkg->name, target, version - target, RET_ERR(PM_ERR_MEMORY, -1)); pkg->name_hash = _alpm_hash_sdbm(pkg->name); - free(tmp); return(0); } -- 1.7.3.5
participants (1)
-
Dan McGee