[Nut-upsdev] upsdrv_print_ups_list and afferant reflections
Peter Selinger
selinger at mathstat.dal.ca
Wed Aug 9 15:52:10 UTC 2006
Hi Jonathan,
I had a brief look at the parser. Here are some cases where I think
the parser will malfunction:
Name: APC Back-UPS 800 # the parser will set value="APC"
VendorID:0x0001 # the parser will not see the ":"
ProductID: 0002 # missing "0x"
==== # the parser will not recognize this line
Name: XYZ UPS 1000
VendorID: 0x0003
ProductID: 0x0004
===
Name: XYZ UPS 1001
VendorID: 0x0005 # since productID != 0 (line 152), the
# parser will call print_ups(0005,0004), a bug
ProductID: 0x0006 # since vendorID != 0 (line 165), the
# parser will call print_ups(0005,0006)
Is it really appropriate to use the PCONF_CTX macros for parsing a
key-value file format? Perhaps it would be better to have a function
strip() (destructively remove white space, i.e., ' \t\n', from front
and end of a string), and a function key_value, perhaps as follows:
/* if line represents a key-value pair, return 1 and let key and value
point to key and value. "line" is updated destructively, and key
and value may point inside line. If not a key-value-pair, return 0
and leave line unchanged. */
int key_value(char *line, char **key, char **value) {
char *p;
p = strchr(line, ':');
if (!p) {
return 0;
}
*p = 0;
*key = strip(line);
*value = strip(value);
return 1;
}
Then the parse() function could be something simple and reliable, like:
void parse(FILE *pipe) {
char line[100];
char *p, *key, *value;
int l = 0;
int productid = 0, vendorid = 0, ...;
int have_record = 0;
while (getline(line, 100, pipe) >= 0) {
l++;
p = strip(line);
if (*p == 0 || *p == '#') { /* comment, blank line */
continue;
} else if (key_value(p, &key, &value)) {
if (strcasecmp(key, "ProductID") == 0) {
productid = parse_hex(value);
} else if (strcasecmp(key, "VendorID") == 0) {
vendorid = parse_hex(value);
} else if (...) {
...
} else {
upsdebugx("Warning: unknown key %s in line %d\n", key, l);
}
have_record = 1;
continue;
} else if (*p == '=') { /* any line starting with '=' */
if (have_record) {
print_record(vendorid, productid, ...);
}
}
}
if (have_record) {
print_record(vendorid, productid, ...);
}
}
This would treat multi-word values, and all the other special cases,
correctly, and would also extend easily to new key-value pairs.
-- Peter
Jonathan Dion wrote:
>
> > > MyDriver version x.y.z...
> > >
> > > List of Supported UPSs
> > > ===
> > > Name : UPS1
> > > Vendor : TheVendor
> > > Extra : USB
> > > VendorID : 0xXXXX
> > > ProductID : 0xXXXX
> > > Status : Supported
> > > ===
> > > Name UPS2
> > > Vendor : TheVendor
> > > Status : Unstable
> > > ===
> > > .
> > > .
> > > .
> >
> > Make sure you make the format flexible enough that: (1) all whitespace
> > before/after ":" and at the beginning/end of the line is ignored
> > (there should be no difference between "Name: X" and " Name : X "),
> > (2) case is ignored in keywords (vendorID, Vendorid etc), (3) blank
> > lines are ignored, (4) include some format for comments, and (5) if
> > lines of the form "===" have a special meaning, make the rule for this
> > flexible (e.g., any line starting with "=" after whitespace).
> >
> > In short, even though this format is machine-generated, it should still
> > be human-editable, just in case.
>
> No problem for all that. It is done.
> # is the comments escape character
More information about the Nut-upsdev
mailing list