changeset 2031:4109967ef832

Merge.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 27 Nov 2018 12:21:06 +0200
parents 8a9ef75fd3cd (diff) 2b961e6b35e5 (current diff)
children 5fe25336a474
files
diffstat 3 files changed, 355 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/src/dmlib.h	Thu Nov 08 11:45:13 2018 +0200
+++ b/src/dmlib.h	Tue Nov 27 12:21:06 2018 +0200
@@ -408,14 +408,30 @@
 void *     dmMemset(void *ptr, const int c, size_t n);
 #endif
 
+
+/** String trimming option flags for dm_strdup_trim()
+ */
+enum
+{
+    DM_TRIM_START    = 1,
+    DM_TRIM_END      = 2,
+    DM_TRIM_BOTH     = 3
+};
+
+
+
 char *     dm_strdup(const char *str);
 char *     dm_strndup(const char *str, const size_t n);
+char *     dm_strdup_trim(const char *src, const int flags);
+char *     dm_strndup_trim(const char *src, const size_t n, const int flags);
 char *     dm_strdup_vprintf_len(const char *fmt, va_list args, int *len);
 char *     dm_strdup_vprintf(const char *fmt, va_list args);
 char *     dm_strdup_printf(const char *fmt, ...);
 
 char *     dm_basefilename(const char *filename);
 char *     dm_strdup_fext(const char *filename, const char *fmt);
+int        dm_strcasecmp(const char *haystack, const char *needle);
+int        dm_strncasecmp(const char *haystack, const char *needle, size_t n);
 char *     dm_strrcasecmp(char *str, const char *needle);
 
 BOOL       dmGetIntVal(const char *str, unsigned int *value, BOOL *neg);
--- a/src/dmstring.c	Thu Nov 08 11:45:13 2018 +0200
+++ b/src/dmstring.c	Tue Nov 27 12:21:06 2018 +0200
@@ -42,6 +42,53 @@
 }
 
 
+/* Compare two strings ignoring case [strcasecmp, strncasecmp]
+ */
+int dm_strcasecmp(const char *haystack, const char *needle)
+{
+    const char *s1 = haystack, *s2 = needle;
+    assert(haystack != NULL);
+    assert(needle != NULL);
+
+    if (haystack == needle)
+        return 0;
+
+    while (*s1 && *s2)
+    {
+        int k = tolower(*s1) - tolower(*s2);
+        if (k != 0)
+            return k;
+        s1++;
+        s2++;
+    }
+
+    return 0;
+}
+
+
+int dm_strncasecmp(const char *haystack, const char *needle, size_t n)
+{
+    const char *s1 = haystack, *s2 = needle;
+    assert(haystack != NULL);
+    assert(needle != NULL);
+
+    if (haystack == needle)
+        return 0;
+
+    while (n > 0 && *s1 && *s2)
+    {
+        int k = tolower(*s1) - tolower(*s2);
+        if (k != 0)
+            return k;
+        s1++;
+        s2++;
+        n--;
+    }
+
+    return 0;
+}
+
+
 /* Check if end of the given string str matches needle
  * case-insensitively, return pointer to start of the match,
  * if found, NULL otherwise.
@@ -58,7 +105,7 @@
     if (slen < nlen)
         return NULL;
 
-    if (strcasecmp(str - nlen - 1, needle) == 0)
+    if (dm_strcasecmp(str - nlen - 1, needle) == 0)
         return str - nlen - 1;
     else
         return NULL;
@@ -83,26 +130,85 @@
 
 /* Implementation of strndup() with NULL check
  */
-char *dm_strndup(const char *s, const size_t n)
+char *dm_strndup(const char *str, const size_t n)
 {
     char *res;
-    if (s == NULL)
+    if (str == NULL)
         return NULL;
 
-    size_t len = strlen(s);
+    size_t len = strlen(str);
     if (len > n)
         len = n;
 
     if ((res = dmMalloc(len + 1)) == NULL)
         return NULL;
 
-    memcpy(res, s, len);
+    memcpy(res, str, len);
     res[len] = 0;
 
     return res;
 }
 
 
+/* Like strdup, but trims whitespace from the string according to specified flags.
+ * See DM_TRIM_* in dmlib.h. If the resulting string would be empty (length 0),
+ * NULL is returned.
+ */
+static char * dm_strdup_trim_do(const char *src, size_t len, const int flags)
+{
+    char *res;
+    size_t start, end;
+
+    if (len == 0)
+        return NULL;
+
+    // Trim start: find first non-whitespace character
+    if (flags & DM_TRIM_START)
+        for (start = 0; start < len && isspace(src[start]); start++);
+    else
+        start = 0;
+
+    // Trim end: find last non-whitespace character
+    if (flags & DM_TRIM_END)
+        for (end = len - 1; end > start && isspace(src[end]); end--);
+    else
+        end = len;
+
+    // Allocate memory for result
+    if (src[end] == 0 || isspace(src[end]))
+        return NULL;
+
+    len = end - start + 1;
+    if ((res = dmMalloc(len + 1)) == NULL)
+        return NULL;
+
+    memcpy(res, src + start, len);
+    res[len] = 0;
+    return res;
+}
+
+
+char *dm_strdup_trim(const char *src, const int flags)
+{
+    if (src == NULL)
+        return NULL;
+
+    return dm_strdup_trim_do(src, strlen(src), flags);
+}
+
+
+char *dm_strndup_trim(const char *src, const size_t n, const int flags)
+{
+    size_t len;
+    if (src == NULL || n == 0)
+        return NULL;
+
+    for (len = 0; len < n && src[len]; len++);
+
+    return dm_strdup_trim_do(src, len, flags);
+}
+
+
 /* Simulate a sprintf() that allocates memory
  */
 char *dm_strdup_vprintf_len(const char *fmt, va_list args, int *len)
--- a/tools/fanalyze.c	Thu Nov 08 11:45:13 2018 +0200
+++ b/tools/fanalyze.c	Tue Nov 27 12:21:06 2018 +0200
@@ -10,8 +10,9 @@
 #include "dmargs.h"
 #include "dmfile.h"
 
-#define SET_MAX_FILES    16
+#define SET_MAX_FILES    64
 #define SET_MAX_ELEMS    256
+#define SET_MAX_VALUES   32
 
 
 /* Typedefs
@@ -47,11 +48,50 @@
 } DMSourceFile;
 
 
+enum
+{
+    DMGV_uint8 = 0,
+    DMGV_uint16_le,
+    DMGV_uint16_be,
+    DMGV_uint32_le,
+    DMGV_uint32_be,
+
+    DMGV_last
+};
+
+
+typedef struct
+{
+    char *name;
+    uint32_t nmax;
+    unsigned int bsize;
+} DMGrepDef;
+
+
+static const DMGrepDef dmGrepTypes[DMGV_last] =
+{
+    { "8bit (byte)"      , (1UL <<  8) - 1, 1 },
+    { "16bit (word) LE"  , (1UL << 16) - 1, 2 },
+    { "16bit (word) BE"  , (1UL << 16) - 1, 2 },
+    { "32bit (word) LE"  , (1UL << 32) - 1, 4 },
+    { "32bit (word) BE"  , (1UL << 32) - 1, 4 },
+};
+
+
+typedef struct
+{
+    int type;
+    uint32_t value;
+} DMGrepValue;
+
+
 /* Global variables
  */
-int           nsrcFiles = 0;              // Number of source files
-DMSourceFile  srcFiles[SET_MAX_FILES];    // Source file names
-DMStats totalStats;
+int            nsrcFiles = 0;              // Number of source files
+DMSourceFile   srcFiles[SET_MAX_FILES];    // Source file names
+DMStats        totalStats;
+int            nsetGrepValues = 0;
+DMGrepValue    setGrepValues[SET_MAX_VALUES];
 
 
 /* Arguments
@@ -60,6 +100,7 @@
 {
     {  0, '?', "help",        "Show this help", OPT_NONE },
     {  1, 'v', "verbose",     "Be more verbose", OPT_NONE },
+    {  2, 'g', "grep",        "Binary grep mode <val>[,<le|be>[8|16|32]]", OPT_ARGREQ },
 };
 
 static const int optListN = sizeof(optList) / sizeof(optList[0]);
@@ -72,24 +113,145 @@
 }
 
 
+int argParseGrepValue(const char *arg)
+{
+    const char *sep = strchr(arg, ',');
+    char *vspec, *vstr;
+    int vtype = -1, ret = DMERR_OK;
+    uint32_t vval;
+
+    // Do we have spec?
+    if (sep != NULL)
+    {
+        vspec = dm_strdup_trim(sep + 1, DM_TRIM_BOTH);
+        vstr = dm_strndup_trim(arg, sep - arg, DM_TRIM_BOTH);
+    }
+    else
+    {
+        vspec = NULL;
+        vstr = dm_strdup(arg);
+    }
+
+    // Parse spec if any
+    if (vspec != NULL)
+    {
+        BOOL vendianess = TRUE;
+        char *vtmp = vspec;
+
+        // Get endianess specifier, if any
+        if (dm_strncasecmp(vtmp, "le", 2) == 0)
+        {
+            vendianess = TRUE;
+            vtmp += 2;
+        }
+        else
+        if (dm_strncasecmp(vtmp, "be", 2) == 0)
+        {
+            vendianess = FALSE;
+            vtmp += 2;
+        }
+
+        // Get value bit size
+        if (strcmp(vtmp, "8") == 0)
+            vtype = DMGV_uint8;
+        else
+        if (strcmp(vtmp, "16") == 0)
+            vtype = vendianess ? DMGV_uint16_le : DMGV_uint16_be;
+        else
+        if (strcmp(vtmp, "32") == 0)
+            vtype = vendianess ? DMGV_uint32_le : DMGV_uint32_be;
+        else
+        {
+            ret = dmError(DMERR_INVALID_ARGS,
+                "Invalid grep type '%s'.\n",
+                vspec);
+            goto out;
+        }
+    }
+
+    // Get value
+    if (!dmGetIntVal(vstr, &vval, NULL))
+    {
+        ret = dmError(DMERR_INVALID_ARGS,
+            "Not a valid integer value '%s'.\n",
+            vstr);
+        goto out;
+    }
+
+    // Check if we need to guess size
+    if (vtype < 0)
+    {
+        for (int n = DMGV_last; n >= 0; n--)
+        {
+            const DMGrepDef *def = &dmGrepTypes[n];
+            if (vval <= def->nmax)
+                vtype = n;
+        }
+    }
+
+    if (vtype < 0)
+    {
+        ret = dmError(DMERR_INVALID_ARGS,
+            "Could not guess value type for '%s'.\n",
+            arg);
+        goto out;
+    }
+
+    // Check range
+    if (vval > dmGrepTypes[vtype].nmax)
+    {
+        ret = dmError(DMERR_INVALID_ARGS,
+            "Integer value %d <= %d <= %d out of range for type %s.\n",
+            vval, 0, dmGrepTypes[vtype].nmax, dmGrepTypes[vtype].name);
+
+        goto out;
+    }
+
+    if (nsetGrepValues < SET_MAX_VALUES)
+    {
+        DMGrepValue *node = &setGrepValues[nsetGrepValues++];
+        node->type = vtype;
+        node->value = vval;
+
+        dmMsg(1, "Grep value %s : %d / 0x%x\n",
+            dmGrepTypes[vtype].name,
+            vval, vval);
+    }
+    else
+    {
+        ret = dmError(DMERR_BOUNDS,
+            "Too many greps specified (max %d).",
+            SET_MAX_VALUES);
+    }
+
+out:
+    dmFree(vspec);
+    dmFree(vstr);
+    return ret;
+}
+
+
 BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
 {
     (void) optArg;
 
     switch (optN)
     {
-    case 0:
-        argShowHelp();
-        exit(0);
-        break;
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
 
-    case 1:
-        dmVerbosity++;
-        break;
+        case 1:
+            dmVerbosity++;
+            break;
 
-    default:
-        dmErrorMsg("Unknown argument '%s'.\n", currArg);
-        return FALSE;
+        case 2:
+            return argParseGrepValue(optArg) == DMERR_OK;
+
+        default:
+            dmErrorMsg("Unknown argument '%s'.\n", currArg);
+            return FALSE;
     }
 
     return TRUE;
@@ -188,6 +350,58 @@
         dmInitStats(&file->stats);
     }
 
+
+    // Check if we are in grep mode
+    if (nsetGrepValues > 0)
+    {
+        for (int nfile = 0; nfile < nsrcFiles; nfile++)
+        {
+            DMSourceFile *file = &srcFiles[nfile];
+            dmPrint(0, "\n%s:\n", file->filename);
+
+            for (int n = 0; n < nsetGrepValues; n++)
+            {
+                DMGrepValue *node = &setGrepValues[n];
+                const DMGrepDef *def = &dmGrepTypes[node->type];
+
+                for (size_t offs = 0; offs + def->bsize < file->size; offs++)
+                {
+                    uint32_t mval = -1;
+                    switch (node->type)
+                    {
+                        case DMGV_uint8:
+                            mval = *((uint8_t *) (file->data + offs));
+                            break;
+
+                        case DMGV_uint16_le:
+                            mval = DM_LE16_TO_NATIVE(*((uint16_t *) (file->data + offs)));
+                            break;
+
+                        case DMGV_uint16_be:
+                            mval = DM_BE16_TO_NATIVE(*((uint16_t *) (file->data + offs)));
+                            break;
+
+                        case DMGV_uint32_le:
+                            mval = DM_LE32_TO_NATIVE(*((uint32_t *) (file->data + offs)));
+                            break;
+
+                        case DMGV_uint32_be:
+                            mval = DM_BE32_TO_NATIVE(*((uint32_t *) (file->data + offs)));
+                            break;
+                    }
+
+                    if (mval == node->value)
+                    {
+                        dmPrint(0, "%08x : %s match %d / 0x%x\n",
+                            offs, def->name, mval, mval);
+
+                    }
+                }
+            }
+        }
+        goto out;
+    }
+
     // Allocate comparision buffer
     // XXX: integer overflow?
     dmPrint(2, "Allocating %d element (%d bytes) comparision buffer.\n",