Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/usbhidctl Change usbhidctl to take numeric usage nam...



details:   https://anonhg.NetBSD.org/src/rev/81381fee676b
branches:  trunk
changeset: 516402:81381fee676b
user:      augustss <augustss%NetBSD.org@localhost>
date:      Mon Oct 22 22:03:49 2001 +0000

description:
Change usbhidctl to take numeric usage names.  Add examples in the man
page.  From Dave Sainty <dave%dtsp.co.nz@localhost>.

diffstat:

 usr.bin/usbhidctl/usbhid.c    |  332 +++++++++++++++++++++++++++++------------
 usr.bin/usbhidctl/usbhidctl.1 |   94 ++++++++++-
 2 files changed, 319 insertions(+), 107 deletions(-)

diffs (truncated from 583 to 300 lines):

diff -r 9316e10606ba -r 81381fee676b usr.bin/usbhidctl/usbhid.c
--- a/usr.bin/usbhidctl/usbhid.c        Mon Oct 22 21:09:47 2001 +0000
+++ b/usr.bin/usbhidctl/usbhid.c        Mon Oct 22 22:03:49 2001 +0000
@@ -1,7 +1,7 @@
-/*      $NetBSD: usbhid.c,v 1.17 2001/03/28 03:17:42 simonb Exp $ */
+/*      $NetBSD: usbhid.c,v 1.18 2001/10/22 22:03:49 augustss Exp $ */
 
 /*
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -57,10 +57,6 @@
 #define DELIM_PAGE ':'
 #define DELIM_SET '='
 
-/* Zero if not in a verbose mode.  Greater levels of verbosity are
-   indicated by values larger than one. */
-static unsigned int verbose;
-
 struct Susbvar {
        /* Variable name, not NUL terminated */
        char const *variable;
@@ -76,6 +72,7 @@
 #define MATCH_SHOWPAGENAME     (1 << 5)
 #define MATCH_SHOWNUMERIC      (1 << 6)
 #define MATCH_WRITABLE         (1 << 7)
+#define MATCH_SHOWVALUES       (1 << 8)
        unsigned int mflags;
 
        /* Workspace for hidmatch() */
@@ -107,11 +104,183 @@
 #define REPORT_MAXVAL 2
 };
 
+/*
+ * Extract 16-bit unsigned usage ID from a numeric string.  Returns -1
+ * if string failed to parse correctly.
+ */
+static int
+strtousage(const char *nptr, size_t nlen)
+{
+       char *endptr;
+       long result;
+       char numstr[16];
+
+       if (nlen >= sizeof(numstr) || !isdigit((unsigned char)*nptr))
+               return -1;
+
+       /*
+        * We use strtol() here, but unfortunately strtol() requires a
+        * NUL terminated string - which we don't have - at least not
+        * officially.
+        */
+       memcpy(numstr, nptr, nlen);
+       numstr[nlen] = '\0';
+
+       result = strtol(numstr, &endptr, 0);
+
+       if (result < 0 || result > 0xffff || endptr != &numstr[nlen])
+               return -1;
+
+       return result;
+}
+
+struct usagedata {
+       char const *page_name;
+       char const *usage_name;
+       size_t page_len;
+       size_t usage_len;
+       int isfinal;
+       u_int32_t usage_id;
+};
+
+/*
+ * Test a rule against the current usage data.  Returns -1 on no
+ * match, 0 on partial match and 1 on complete match.
+ */
+static int
+hidtestrule(struct Susbvar *var, struct usagedata *cache)
+{
+       char const *varname;
+       ssize_t matchindex, pagesplit;
+       size_t strind, varlen;
+       int numusage;
+       u_int32_t usage_id;
+
+       matchindex = var->matchindex;
+       varname = var->variable;
+       varlen = var->varlen;
+
+       usage_id = cache->usage_id;
+
+       /*
+        * Parse the current variable name, locating the end of the
+        * current 'usage', and possibly where the usage page name
+        * ends.
+        */
+       pagesplit = -1;
+       for (strind = matchindex; strind < varlen; strind++) {
+               if (varname[strind] == DELIM_USAGE)
+                       break;
+               if (varname[strind] == DELIM_PAGE)
+                       pagesplit = strind;
+       }
+
+       if (cache->isfinal && strind != varlen)
+               /*
+                * Variable name is too long (hit delimiter instead of
+                * end-of-variable).
+                */
+               return -1;
+
+       if (pagesplit >= 0) {
+               /*
+                * Page name was specified, determine whether it was
+                * symbolic or numeric.  
+                */
+               char const *strstart;
+               int numpage;
+
+               strstart = &varname[matchindex];
+
+               numpage = strtousage(strstart, pagesplit - matchindex);
+
+               if (numpage >= 0) {
+                       /* Valid numeric */
+
+                       if (numpage != HID_PAGE(usage_id))
+                               /* Numeric didn't match page ID */
+                               return -1;
+               } else {
+                       /* Not a valid numeric */
+
+                       /*
+                        * Load and cache the page name if and only if
+                        * it hasn't already been loaded (it's a
+                        * fairly expensive operation).
+                        */
+                       if (cache->page_name == NULL) {
+                               cache->page_name = hid_usage_page(HID_PAGE(usage_id));
+                               cache->page_len = strlen(cache->page_name);
+                       }
+
+                       /*
+                        * Compare specified page name to actual page
+                        * name.
+                        */
+                       if (cache->page_len !=
+                           (size_t)(pagesplit - matchindex) ||
+                           memcmp(cache->page_name,
+                                  &varname[matchindex],
+                                  cache->page_len) != 0)
+                               /* Mismatch, page name wrong */
+                               return -1;
+               }
+
+               /* Page matches, discard page name */
+               matchindex = pagesplit + 1;
+       }
+
+       numusage = strtousage(&varname[matchindex], strind - matchindex);
+
+       if (numusage >= 0) {
+               /* Valid numeric */
+
+               if (numusage != HID_USAGE(usage_id))
+                       /* Numeric didn't match usage ID */
+                       return -1;
+       } else {
+               /* Not a valid numeric */
+
+               /* Load and cache the usage name */
+               if (cache->usage_name == NULL) {
+                       cache->usage_name = hid_usage_in_page(usage_id);
+                       cache->usage_len = strlen(cache->usage_name);
+               }
+
+               /*
+                * Compare specified usage name to actual usage name
+                */
+               if (cache->usage_len != (size_t)(strind - matchindex) ||
+                   memcmp(cache->usage_name, &varname[matchindex],
+                          cache->usage_len) != 0)
+                       /* Mismatch, usage name wrong */
+                       return -1;
+       }
+
+       if (cache->isfinal)
+               /* Match */
+               return 1;
+
+       /*
+        * Partial match: Move index past this usage string +
+        * delimiter
+        */
+       var->matchindex = strind + 1;
+
+       return 0;
+}
+
+/*
+ * hidmatch() determines whether the item specified in 'item', and
+ * nested within a heirarchy of collections specified in 'collist'
+ * matches any of the rules in the list 'varlist'.  Returns the
+ * matching rule on success, or NULL on no match.
+ */
 static struct Susbvar*
 hidmatch(u_int32_t const *collist, size_t collen, struct hid_item *item,
         struct Susbvar *varlist, size_t vlsize)
 {
-       size_t vlind, colind, vlactive;
+       size_t colind, vlactive, vlind;
        int iscollection;
 
        /*
@@ -160,96 +329,52 @@
                }
        }
 
+       /*
+        * Loop through each usage in the collection list, including
+        * the 'item' itself on the final iteration.  For each usage,
+        * test which variables named in the rule list are still
+        * applicable - if any.
+        */
        for (colind = 0; vlactive > 0 && colind <= collen; colind++) {
-               char const *usage_name, *page_name;
-               size_t usage_len, page_len;
-               int final;
-               u_int32_t usage_id;
+               struct usagedata cache;
 
-               final = (colind == collen);
-
-               if (final)
-                       usage_id = item->usage;
+               cache.isfinal = (colind == collen);
+               if (cache.isfinal)
+                       cache.usage_id = item->usage;
                else
-                       usage_id = collist[colind];
+                       cache.usage_id = collist[colind];
 
-               usage_name = hid_usage_in_page(usage_id);
-               usage_len = strlen(usage_name);
+               cache.usage_name = NULL;
+               cache.page_name = NULL;
 
-               page_name = NULL;
-
+               /*
+                * Loop through each rule, testing whether the rule is
+                * still applicable or not.  For each rule,
+                * 'matchindex' retains the current match state as an
+                * index into the variable name string, or -1 if this
+                * rule has been proven not to match.
+                */
                for (vlind = 0; vlind < vlsize; vlind++) {
-                       ssize_t matchindex, pagesplit;
-                       size_t varlen, strind;
-                       char const *varname;
                        struct Susbvar *var;
+                       int matchres;
 
                        var = &varlist[vlind];
 
-                       matchindex = var->matchindex;
-                       varname = var->variable;
-                       varlen = var->varlen;
-
-                       if (matchindex < 0)
+                       if (var->matchindex < 0)
                                /* Mismatch at a previous level */
                                continue;
 
-                       pagesplit = -1;
-                       for (strind = matchindex; strind < varlen; strind++) {
-                               if (varname[strind] == DELIM_USAGE)
-                                       break;
-                               if (varname[strind] == DELIM_PAGE)
-                                       pagesplit = strind;
-                       }
+                       matchres = hidtestrule(var, &cache);
 
-                       if (final && strind != varlen) {
-                               /*
-                                * Variable name is too long (hit
-                                * delimiter instead of
-                                * end-of-variable)
-                                */
+                       if (matchres < 0) {
+                               /* Bad match */
                                var->matchindex = -1;
                                vlactive--;
                                continue;
-                       }
-
-                       if (pagesplit >= 0) {



Home | Main Index | Thread Index | Old Index