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