Skip to content

Instantly share code, notes, and snippets.

@Siguza
Created October 6, 2017 09:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Siguza/86f772ddec5114bfc951ae0f4eb5b30f to your computer and use it in GitHub Desktop.
Save Siguza/86f772ddec5114bfc951ae0f4eb5b30f to your computer and use it in GitHub Desktop.
// Siguza
// Treat as public domain.
#include <ctype.h> // isspace
#include <stdlib.h> // malloc, free,
#include <string.h> // strlen, strncmp, strstr
// Turn delimiter tokens into null terminators and
// create array of pointers to each new string.
static void destructive_split(char *str, const char *delim, char ***out, size_t *outlen)
{
size_t len = strlen(delim),
num = 1;
for(char *ptr = strstr(str, delim); ptr != NULL; ptr = strstr(ptr + len, delim))
{
if(ptr[len] == '\0')
{
break;
}
++num;
}
char **bits = malloc(num * sizeof(char*));
if(bits)
{
num = 0;
bits[num++] = str;
for(char *ptr = strstr(str, delim); ptr != NULL; ptr = strstr(ptr + len, delim))
{
ptr[0] = '\0';
if(ptr[len] == '\0')
{
break;
}
bits[num++] = ptr + len;
}
*outlen = num;
}
*out = bits;
}
#define DELIM "\n\n"
#define PKG "Package:"
char* dpkg_merge(char *old, char *new)
{
char **oldbits = NULL,
**newbits = NULL;
size_t oldlen = 0,
newlen = 0;
destructive_split(old, DELIM, &oldbits, &oldlen);
destructive_split(new, DELIM, &newbits, &newlen);
char *result = NULL;
if(oldbits && newbits)
{
char **oldpkg = malloc(oldlen * sizeof(char*));
if(oldpkg)
{
for(size_t i = 0; i < oldlen; ++i)
{
char *pkg = strstr(oldbits[i], PKG);
if(pkg)
{
for(pkg += strlen(PKG); isspace(*pkg); ++pkg);
}
oldpkg[i] = pkg;
}
for(size_t i = 0; i < newlen; ++i)
{
char *pkg = strstr(newbits[i], PKG);
if(!pkg)
{
// No package? Drop this.
newbits[i] = NULL;
}
else
{
for(pkg += strlen(PKG); isspace(*pkg); ++pkg);
size_t pkglen;
for(pkglen = 0; !isspace(pkg[pkglen]); ++pkglen);
for(size_t j = 0; j < oldlen; ++j)
{
if
(
oldpkg[j] != NULL && strncmp(pkg, oldpkg[j], pkglen) == 0 &&
(oldpkg[j][pkglen] == '\0' || isspace(oldpkg[j][pkglen]))
)
{
oldpkg[j] = pkg;
oldbits[j] = newbits[i];
newbits[i] = NULL;
break;
}
}
}
}
size_t total = 0;
for(size_t i = 0; i < oldlen; ++i)
{
total += 2 + strlen(oldbits[i]);
}
for(size_t i = 0; i < newlen; ++i)
{
if(newbits[i])
{
total += 2 + strlen(newbits[i]);
}
}
result = malloc(total);
if(result)
{
result[0] = '\0';
for(size_t i = 0; i < oldlen; ++i)
{
strcat(result, oldbits[i]);
strcat(result, DELIM);
}
for(size_t i = 0; i < newlen; ++i)
{
if(newbits[i])
{
strcat(result, newbits[i]);
strcat(result, DELIM);
}
}
}
free(oldpkg);
}
}
if(oldbits) free(oldbits);
if(newbits) free(newbits);
return result;
}
#undef DELIM
#undef PKG
#ifdef HAVE_MAIN
#include <stdio.h>
int main(void)
{
// Error handling omitted here in main
FILE *f = fopen("status-old", "r");
fseek(f, 0, SEEK_END);
long len = ftell(f);
fseek(f, 0, SEEK_SET);
char *old = malloc(len);
fread(old, 1, len, f);
fclose(f);
f = fopen("status-new", "r");
fseek(f, 0, SEEK_END);
len = ftell(f);
fseek(f, 0, SEEK_SET);
char *new = malloc(len);
fread(new, 1, len, f);
fclose(f);
char *result = dpkg_merge(old, new);
if(result)
{
printf("%s", result);
free(result);
}
free(old);
free(new);
return 0;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment