From: Michael Welsh Duggan <mwd@cert.org>
To: Alan Mackenzie <acm@muc.de>
Cc: "11749@debbugs.gnu.org" <11749@debbugs.gnu.org>,
Kim Storm <storm@cua.dk>
Subject: bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
Date: Mon, 26 Nov 2012 08:25:33 -0500 [thread overview]
Message-ID: <tnty5ho4hte.fsf@waterbuck.yellow.cert.org> (raw)
In-Reply-To: <20121121213340.GB4025@acm.acm> (Alan Mackenzie's message of "Wed, 21 Nov 2012 16:33:40 -0500")
[-- Attachment #1: Type: text/plain, Size: 1957 bytes --]
Alan Mackenzie <acm@muc.de> writes:
> Hi, Michael.
>
> On Wed, Nov 14, 2012 at 11:52:41AM -0500, Michael Welsh Duggan wrote:
>
>> ... Today I started working in C again, and ran into issues like this:
>
>> Error during redisplay: (jit-lock-function 3411) signaled
>> (wrong-type-argument number-or-marker-p nil)
>> c-parse-state inconsistency at 3599: using cache: nil, from scratch:
>> ((3409 . 3599))
>> Old state:
>> (setq c-state-cache '((3409 . 3599)) c-state-cache-good-pos 3599
>> c-state-nonlit-pos-cache '(6307 3307) c-state-nonlit-pos-cache-limit
>> 3592 c-state-semi-nonlit-pos-cache '(3307)
>> c-state-semi-nonlit-pos-cache-limit 3592 c-state-brace-pair-desert
>> (nil . 3396) c-state-point-min 1 c-state-point-min-lit-type nil
>> c-state-point-min-lit-start nil c-state-min-scan-pos 1
>> c-state-old-cpp-beg nil c-state-old-cpp-end nil c-parse-state-point
>> 3600)
>
>> I have finally managed to come up with a recipe for this one. I am
>> using "110803 rgm@gnu.org-20121105111732-ilq2sbfo09xg9i9z" with your
>> patches.
>
>> emacs -Q rwfileinfo.c
>> M-x c-toggle-parse-state-debug
>> C-x 4 b *Messages* RET
>
> I assumed a C-x o here. ;-)
>
>> C-s enum RET
>> C-M-f C-p C-e ,
>
>> Error occurs after the comma (should be on line 197).
>
> I find myself on L96. I can't reproduce this error, neither on a tty or
> in X windows. I tried repeating the C-M-f, so that the C-p C-e brought
> point to just after "RWINFO_PROPERTY_COUNT" and typing a comma there.
> That still didn't signal an error.
I'm sorry. I realized that I attached the wrong file. And the line
number should have been 97, not 197. Unfortunately, I cannot reliably
trigger the problem using the above recipe using a recent Emacs trunk
check-out. Even more unfortunately, I have still encountered the
problem (but have been unable to recreate it). All in all, though, I
think your changes have been beneficial. I'll try to isolate an example
over the next few days.
[-- Attachment #2: rwsiteinfo.c --]
[-- Type: text/plain, Size: 61958 bytes --]
/*
** Copyright (C) 2011-2012 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/
/*
** Prints information about SiLK site configurations
**
** Michael Duggan
** September 2011
*/
#include <silk/silk.h>
RCSIDENT("$Id$");
#include <silk/skstream.h>
#include <silk/skstringmap.h>
#include <silk/sksite.h>
#include <silk/utils.h>
/* LOCAL DEFINES AND TYPEDEFS */
/* where to write --help output */
#define USAGE_FH stdout
/*
* Printer function typedef.
*
* rwsiteinfo "prints" the output twice. In the first pass, it
* uses a print function that does not produce output but instead
* determines the sizes of what it would print. In the second
* pass, it uses an actual print function (fprintf) to produce the
* output.
*/
typedef int (*rws_fprintf_t)(FILE *f, const char *fmt, ...);
/* Sub-iterator types */
typedef enum {
RWS_NULL,
RWS_FLOWTYPE,
RWS_CLASS,
RWS_SENSOR,
RWS_CLASS_FROM_SENSOR,
RWS_SENSOR_FROM_CLASS,
RWS_FLOWTYPE_FROM_CLASS,
RWS_DEFAULT_FLOWTYPE_FROM_CLASS
} rws_iter_type_t;
/* Site iterator */
typedef struct rws_iter_st {
/* The iterators */
flowtype_iter_t flowtype_iter;
class_iter_t class_iter;
sensor_iter_t sensor_iter;
/* The values */
flowtypeID_t flowtype_id;
classID_t class_id;
sensorID_t sensor_id;
/* Order and type of iterators */
rws_iter_type_t order[3];
/* Number of iterators */
int level;
/* Highest bound iterator */
int bound;
/* Highest started iterator */
int started;
/* Whether RWS_DEFAULT_FLOWTYPE_FROM_CLASS is one of the
* iterators */
unsigned default_type : 1;
} rws_iter_t;
/* LOCAL VARIABLE DEFINITIONS */
/* Masks for flowtypes, classes, and sensors as set by the --classes,
* --types, --flowtypes, and --sensors switches. When the bitmap is
* NULL, all values are printed; when the bitmap is not NULL, only
* values where the bit is high are printed. */
static sk_bitmap_t *flowtype_mask = NULL;
static sk_bitmap_t *class_mask = NULL;
static sk_bitmap_t *sensor_mask = NULL;
/* paging program */
static const char *pager;
/* the output stream, set by --output-path or --pager */
static sk_fileptr_t output;
/* raw filter arguments */
static char *classes_arg = NULL;
static char *types_arg = NULL;
static char *flowtypes_arg = NULL;
static char *sensors_arg = NULL;
static char *fields_arg = NULL;
/* delimiters */
static char column_separator = '|';
static char list_separator = ',';
/* how to format output */
static int no_columns = 0;
static int no_final_delimiter = 0;
static int no_titles = 0;
/* final delimiter */
static char final_delim[] = {'\0', '\0'};
/* Field types */
typedef enum {
RWST_CLASS,
RWST_TYPE,
RWST_FLOWTYPE,
RWST_FLOWTYPE_ID,
RWST_SENSOR,
RWST_SENSOR_ID,
RWST_SENSOR_DESC,
RWST_DEFAULT_CLASS,
RWST_DEFAULT_TYPE,
RWST_MARK_DEFAULTS,
RWST_CLASS_LIST,
RWST_TYPE_LIST,
RWST_FLOWTYPE_LIST,
RWST_FLOWTYPE_ID_LIST,
RWST_SENSOR_LIST,
RWST_SENSOR_ID_LIST,
RWST_DEFAULT_CLASS_LIST,
RWST_DEFAULT_TYPE_LIST,
/* Number of field types */
RWST_MAX_FIELD_COUNT
} rws_field_t;
/* Field names, types, descriptions, and titles. MUST be in the same
* order as the rws_field_t enumeration. */
static const sk_stringmap_entry_t field_map_entries[] = {
{"class", RWST_CLASS,
"class name", "Class"},
{"type", RWST_TYPE,
"type name", "Type"},
{"flowtype", RWST_FLOWTYPE,
"flowtype name", "Flowtype"},
{"id-flowtype", RWST_FLOWTYPE_ID,
"flowtype integer identifier", "Flowtype-ID"},
{"sensor", RWST_SENSOR,
"sensor name", "Sensor"},
{"id-sensor", RWST_SENSOR_ID,
"sensor integer identifier", "Sensor-ID"},
{"describe-sensor", RWST_SENSOR_DESC,
"sensor description", "Sensor-Description"},
{"default-class", RWST_DEFAULT_CLASS,
"default class name", "Default-Class"},
{"default-type", RWST_DEFAULT_TYPE,
"default type name", "Default-Type"},
{"mark-defaults", RWST_MARK_DEFAULTS,
"'+' for default classes, '*' for types", "Defaults"},
{"class:list", RWST_CLASS_LIST,
"list of class names", "Class:list"},
{"type:list", RWST_TYPE_LIST,
"list of type names", "Type:list"},
{"flowtype:list", RWST_FLOWTYPE_LIST,
"list of flowtype names", "Flowtype:list"},
{"id-flowtype:list", RWST_FLOWTYPE_ID_LIST,
"list of flowtype integer identifier", "Flowtype-ID:list"},
{"sensor:list", RWST_SENSOR_LIST,
"list of sensor names", "Sensor:list"},
{"id-sensor:list", RWST_SENSOR_ID_LIST,
"list of sensor integer identifiers", "Sensor-ID:list"},
{"default-class:list", RWST_DEFAULT_CLASS_LIST,
"list of default class names", "Default-Class:list"},
{"default-type:list", RWST_DEFAULT_TYPE_LIST,
"list of default type names", "Default-Type:list"},
SK_STRINGMAP_SENTINEL
};
/* Fields to print, in the order in which to print them */
static rws_field_t fields[RWST_MAX_FIELD_COUNT];
/* Number of fields in list */
static size_t num_fields = 0;
/* Width of the columns, where index is an rws_field_t. */
static int col_width[RWST_MAX_FIELD_COUNT];
/* OPTIONS SETUP */
typedef enum {
OPT_FIELDS, OPT_CLASSES, OPT_TYPES, OPT_FLOWTYPES,
OPT_SENSORS, OPT_NO_TITLES, OPT_NO_COLUMNS, OPT_COLUMN_SEPARATOR,
OPT_NO_FINAL_DELIMITER, OPT_DELIMITED, OPT_LIST_DELIMETER,
OPT_PAGER, OPT_DATA_ROOTDIR
} appOptionsEnum;
static struct option appOptions[] = {
{"fields", REQUIRED_ARG, 0, OPT_FIELDS},
{"classes", REQUIRED_ARG, 0, OPT_CLASSES},
{"types", REQUIRED_ARG, 0, OPT_TYPES},
{"flowtypes", REQUIRED_ARG, 0, OPT_FLOWTYPES},
{"sensors", REQUIRED_ARG, 0, OPT_SENSORS},
{"no-titles", NO_ARG, 0, OPT_NO_TITLES},
{"no-columns", NO_ARG, 0, OPT_NO_COLUMNS},
{"column-separator", REQUIRED_ARG, 0, OPT_COLUMN_SEPARATOR},
{"no-final-delimiter", NO_ARG, 0, OPT_NO_FINAL_DELIMITER},
{"delimited", OPTIONAL_ARG, 0, OPT_DELIMITED},
{"list-delimiter", REQUIRED_ARG, 0, OPT_LIST_DELIMETER},
{"pager", REQUIRED_ARG, 0, OPT_PAGER},
{"data-rootdir", REQUIRED_ARG, 0, OPT_DATA_ROOTDIR},
{0,0,0,0} /* sentinel entry */
};
static const char *appHelp[] = {
("Print the fields named in this comma-separated list. Choices:"),
("Restrict the output using classes named in this comma-\n"
"\tseparated list. Use '@' to designate the default class.\n"
"\tDef. Print data for all classes"),
("Restrict the output using the types named in this comma-\n"
"\tseparated list. Use '@' to designate the default type(s) for a class.\n"
"\tDef. Print data for all types"),
("Restrict the output using the class/type pairs named in\n"
"\tthis comma-separated list. May use 'all' for class and/or type. This\n"
"\tis an alternate way to specify class/type; switch may not be used\n"
"\twith --class or --type. Def. Print data for all class/type pairs"),
("Restrict the output using the sensors named in this comma-\n"
"\tseparated list. Sensors may be designated by name, ID (integer),\n"
"\tand/or ranges of IDs. Def. Print data for all sensors"),
("Do not print column headers. Def. Print titles"),
("Disable fixed-width columnar output. Def. Columnar"),
("Use specified character between columns. Def. '|'"),
("Suppress column delimiter at end of line. Def. No"),
("Shortcut for --no-columns --no-final-del --column-sep=CHAR"),
("Use specified character between items in FIELD:list\n"
"\tfields. Def. ','"),
("Program to invoke to page output. Def. $SILK_PAGER or $PAGER"),
("Root of directory tree containing packed data."),
(char *)NULL
};
/* LOCAL FUNCTION PROTOTYPES */
static int appOptionsHandler(clientData cData, int opt_index, char *opt_arg);
static sk_stringmap_t *createStringmap(void);
static int rws_parse_fields(void);
static int rws_parse_restrictions(void);
static int rws_print_list_field(
rws_fprintf_t printer,
FILE *fd,
rws_iter_t *iter,
rws_field_t field,
int width);
static int fprintf_size(FILE *stream, const char *format, ...);
/* FUNCTION DEFINITIONS */
/*
* appUsageLong();
*
* Print complete usage information to USAGE_FH. Pass this
* function to skOptionsSetUsageCallback(); skOptionsParse() will
* call this funciton and then exit the program when the --help
* option is given.
*/
static void appUsageLong(void)
{
#define MIN_TEXT_ON_LINE 15
#define MAX_TEXT_ON_LINE 72
#define USAGE_MSG \
("--fields=<FIELDS> [SWITCHES]\n" \
"\tPrint selected information about the classes, types, flowtypes\n" \
"\tand sensors defined in the SiLK site configuration file. By\n" \
"\tdefault, the selected information is printed for every class,\n" \
"\ttype, and sensor defined in the file; to restrict the output,\n" \
"\tspecify one or more of --classes, --types, --flowtypes, or\n" \
"\t--sensors.\n")
FILE *fh = USAGE_FH;
char *cp, *ep, *sp;
char buf[2 * PATH_MAX];
char path[PATH_MAX];
int i;
fprintf(fh, "%s %s", skAppName(), USAGE_MSG);
fprintf(fh, "\nSWITCHES:\n");
skOptionsDefaultUsage(fh);
for (i = 0; appOptions[i].name; i++ ) {
fprintf(fh, "--%s %s. ",
appOptions[i].name, SK_OPTION_HAS_ARG(appOptions[i]));
/* Print the static help text from the appHelp array */
fprintf(fh, "%s\n", appHelp[i]);
switch (appOptions[i].val) {
case OPT_FIELDS:
{
sk_stringmap_t *map = createStringmap();
if (map == NULL) {
skAppPrintErr("Error creating string map");
exit(EXIT_FAILURE);
}
skStringMapPrintUsage(map, fh, 8);
skStringMapDestroy(map);
}
break;
case OPT_DATA_ROOTDIR:
/* put the text into a buffer, and then wrap the text in
* the buffer at space characters. */
snprintf(buf, sizeof(buf),
("Currently '%s'. Def. $" SILK_DATA_ROOTDIR_ENVAR
" or '%s'"),
sksiteGetRootDir(path, sizeof(path)),
sksiteGetDefaultRootDir());
sp = buf;
while (strlen(sp) > MAX_TEXT_ON_LINE) {
cp = &sp[MIN_TEXT_ON_LINE];
while ((ep = strchr(cp+1, ' ')) != NULL) {
/* text is now too long */
if (ep - sp > MAX_TEXT_ON_LINE) {
if (cp == &sp[MIN_TEXT_ON_LINE]) {
/* this is the first space character we have
* on this line; so use it */
cp = ep;
}
break;
}
cp = ep;
}
if (cp == &sp[MIN_TEXT_ON_LINE]) {
/* no space characters anywhere on the line */
break;
}
assert(' ' == *cp);
*cp = '\0';
fprintf(fh, "\t%s\n", sp);
sp = cp + 1;
}
if (*sp) {
fprintf(fh, "\t%s\n", sp);
}
break;
default:
break;
}
}
sksiteOptionsUsage(fh);
}
/*
* appTeardown()
*
* Teardown all modules, close all files, and tidy up all
* application state.
*
* This function is idempotent.
*/
static void appTeardown(void)
{
static int teardownFlag = 0;
if (teardownFlag) {
return;
}
teardownFlag = 1;
/* close the output file or process */
if (output.of_name) {
skFileptrClose(&output, &skAppPrintErr);
}
skBitmapDestroy(&flowtype_mask);
skBitmapDestroy(&class_mask);
skBitmapDestroy(&sensor_mask);
skAppUnregister();
}
/*
* appSetup(argc, argv);
*
* Perform all the setup for this application include setting up
* required modules, parsing options, etc. This function should be
* passed the same arguments that were passed into main().
*
* Returns to the caller if all setup succeeds. If anything fails,
* this function will cause the application to exit with a FAILURE
* exit status.
*/
static void appSetup(int argc, char **argv)
{
SILK_FEATURES_DEFINE_STRUCT(features);
int arg_index;
int rv;
/* verify same number of options and help strings */
assert((sizeof(appHelp)/sizeof(char *)) ==
(sizeof(appOptions)/sizeof(struct option)));
/* register the application */
skAppRegister(argv[0]);
skAppVerifyFeatures(&features, NULL);
skOptionsSetUsageCallback(&appUsageLong);
/* initialize globals */
memset(&output, 0, sizeof(output));
output.of_fp = stdout;
/* register the options */
if (skOptionsRegister(appOptions, &appOptionsHandler, NULL)
|| sksiteOptionsRegister(SK_SITE_FLAG_CONFIG_FILE))
{
skAppPrintErr("Unable to register options");
exit(EXIT_FAILURE);
}
/* register the teardown handler */
if (atexit(appTeardown) < 0) {
skAppPrintErr("Unable to register appTeardown() with atexit()");
appTeardown();
exit(EXIT_FAILURE);
}
/* parse the options */
arg_index = skOptionsParse(argc, argv);
if (arg_index < 0) {
skAppUsage(); /* never returns */
}
/* try to load site config file; if it fails, we will not be able
* to resolve flowtype and sensor from input file names */
if (sksiteConfigure(1)) {
exit(EXIT_FAILURE);
}
/* parse fields */
if (rws_parse_fields()) {
exit(EXIT_FAILURE);
}
/* parse restrictions (--classes, --types, etc) */
if (rws_parse_restrictions()) {
exit(EXIT_FAILURE);
}
/* check for extraneous arguments */
if (arg_index != argc) {
skAppPrintErr("Too many arguments or unrecognized switch '%s'",
argv[arg_index]);
skAppUsage(); /* never returns */
}
/* Initialize column widths */
if (no_titles || no_columns) {
memset(col_width, 0, sizeof(col_width));
} else {
size_t i;
for (i = 0; i < RWST_MAX_FIELD_COUNT; i++) {
col_width[i] = strlen((char *)field_map_entries[i].userdata);
/* While looping through, verify that the
* field_map_entries is in the same order as the
* enumeration. */
assert(i == field_map_entries[i].id);
}
}
/* Set the final delimiter, if used */
if (!no_final_delimiter) {
final_delim[0] = column_separator;
}
rv = skFileptrOpenPager(&output, pager);
if (rv && rv != SK_FILEPTR_PAGER_IGNORED) {
skAppPrintErr("Unable to invoke pager");
}
return; /* OK */
}
/*
* status = appOptionsHandler(cData, opt_index, opt_arg);
*
* This function is passed to skOptionsRegister(); it will be called
* by skOptionsParse() for each user-specified switch that the
* application has registered; it should handle the switch as
* required---typically by setting global variables---and return 1
* if the switch processing failed or 0 if it succeeded. Returning
* a non-zero from from the handler causes skOptionsParse() to return
* a negative value.
*
* The clientData in 'cData' is typically ignored; 'opt_index' is
* the index number that was specified as the last value for each
* struct option in appOptions[]; 'opt_arg' is the user's argument
* to the switch for options that have a REQUIRED_ARG or an
* OPTIONAL_ARG.
*/
static int appOptionsHandler(
clientData UNUSED(cData),
int opt_index,
char *opt_arg)
{
switch ((appOptionsEnum)opt_index) {
case OPT_DATA_ROOTDIR:
if (!skDirExists(opt_arg)) {
skAppPrintErr("Root data directory '%s' does not exist", opt_arg);
return -1;
}
if (sksiteSetRootDir(opt_arg)) {
skAppPrintErr("Unable to set root data directory to %s", opt_arg);
return -1;
}
break;
case OPT_CLASSES:
if (classes_arg != NULL) {
skAppPrintErr("Invalid %s: Switch specified multiple times",
appOptions[opt_index].name);
return -1;
}
classes_arg = opt_arg;
break;
case OPT_TYPES:
if (types_arg != NULL) {
skAppPrintErr("Invalid %s: Switch specified multiple times",
appOptions[opt_index].name);
return -1;
}
types_arg = opt_arg;
break;
case OPT_FLOWTYPES:
if (flowtypes_arg != NULL) {
skAppPrintErr("Invalid %s: Switch specified multiple times",
appOptions[opt_index].name);
return -1;
}
flowtypes_arg = opt_arg;
break;
case OPT_SENSORS:
if (sensors_arg != NULL) {
skAppPrintErr("Invalid %s: Switch specified multiple times",
appOptions[opt_index].name);
return -1;
}
sensors_arg = opt_arg;
break;
case OPT_FIELDS:
if (fields_arg != NULL) {
skAppPrintErr("Invalid %s: Switch specified multiple times",
appOptions[opt_index].name);
return -1;
}
fields_arg = opt_arg;
break;
case OPT_NO_TITLES:
no_titles = 1;
break;
case OPT_NO_COLUMNS:
no_columns = 1;
break;
case OPT_COLUMN_SEPARATOR:
column_separator = opt_arg[0];
break;
case OPT_NO_FINAL_DELIMITER:
no_final_delimiter = 1;
break;
case OPT_DELIMITED:
no_columns = 1;
no_final_delimiter = 1;
if (opt_arg) {
column_separator = opt_arg[0];
}
break;
case OPT_LIST_DELIMETER:
list_separator = opt_arg[0];
break;
case OPT_PAGER:
pager = opt_arg;
break;
}
return 0; /* OK */
}
/*
* stringmap = createStringmap();
*
* Create the string map that is used to parse the --fields
* paramater.
*/
static sk_stringmap_t *createStringmap(void)
{
sk_stringmap_t *field_map;
/* Create the map */
if (SKSTRINGMAP_OK != skStringMapCreate(&field_map)) {
return NULL;
}
/* add entries */
if (skStringMapAddEntries(field_map, -1, field_map_entries)
!= SKSTRINGMAP_OK)
{
skStringMapDestroy(field_map);
return NULL;
}
return field_map;
}
/*
* status = rws_parse_fields();
*
* Parse the --fields argument. Return 0 on success, -1 on
* failure.
*/
static int rws_parse_fields(void)
{
sk_stringmap_t *field_map = NULL;
sk_stringmap_iter_t *iter = NULL;
sk_stringmap_entry_t *entry;
char *errmsg;
int rv = -1;
if (fields_arg == NULL) {
skAppPrintErr("The --%s switch is required",
appOptions[OPT_FIELDS].name);
return rv;
}
field_map = createStringmap();
if (NULL == field_map) {
skAppPrintOutOfMemory(NULL);
goto END;
}
/* parse the field-list */
if (skStringMapParse(field_map, fields_arg, SKSTRINGMAP_DUPES_ERROR,
&iter, &errmsg))
{
skAppPrintErr("Invalid %s: %s",
appOptions[OPT_FIELDS].name, errmsg);
goto END;
}
/* add the selected fields to the 'fields[]' array */
while (skStringMapIterNext(iter, &entry, NULL) == SK_ITERATOR_OK) {
assert(num_fields < RWST_MAX_FIELD_COUNT);
fields[num_fields] = (rws_field_t)entry->id;
++num_fields;
}
rv = 0;
END:
if (iter != NULL) {
skStringMapIterDestroy(iter);
}
if (field_map != NULL) {
skStringMapDestroy(field_map);
}
return rv;
}
/*
* status = rws_parse_sensors(sn_bitmap);
*
* Parse the --sensors argument from the global 'sensors_arg'.
* Set a bit in 'sn_bitmap' for each sensor we see. Return 0 on
* success, or -1 if any invalid sensors are found.
*/
static int rws_parse_sensors(
sk_bitmap_t *sn_bitmap)
{
char *user_arg = NULL;
char *user_arg_freeable = NULL;
char *sensor_token = NULL;
uint32_t min_sensor_id;
uint32_t max_sensor_id;
uint32_t val_min, val_max;
sensorID_t sid = SK_INVALID_SENSOR;
int p_err;
int rv = 0;
/* nothing to do when no --sensors switch is given */
if (NULL == sensors_arg) {
return 0;
}
assert(sn_bitmap);
assert(skBitmapGetSize(sn_bitamp) > sksiteSensorGetMaxID());
min_sensor_id = sksiteSensorGetMinID();
max_sensor_id = sksiteSensorGetMaxID();
/* create a copy of the input string and maintain a reference to
* it so we can free it */
user_arg = strdup(sensors_arg);
user_arg_freeable = user_arg;
if (user_arg == NULL) {
skAppPrintOutOfMemory(NULL);
rv = -1;
goto END;
}
/* parse the sensors as a comma separated list of tokens */
while ((sensor_token = strsep(&user_arg, ",")) != NULL) {
/* check for empty token (e.g., double comma) */
if ('\0' == *sensor_token) {
continue;
}
/* look up sensor_token as a sensor name */
sid = sksiteSensorLookup(sensor_token);
if (SK_INVALID_SENSOR != sid) {
/* found it. add it to our lists and continue */
skBitmapSetBit(sn_bitmap, sid);
continue;
}
/* parsing failed. does the token look like a number? */
if (!isdigit((int)(*sensor_token))) {
/* not a number: error */
skAppPrintErr("Invalid %s '%s': Unknown sensor name",
appOptions[OPT_SENSORS].name, sensor_token);
rv = -1;
continue;
}
/* it is a digit: parse the token as a single number or a
* range */
p_err = skStringParseRange32(&val_min, &val_max, sensor_token,
min_sensor_id, max_sensor_id,
SKUTILS_RANGE_NO_OPEN);
if (p_err != 0) {
/* an error */
skAppPrintErr("Invalid %s '%s': %s",
appOptions[OPT_SENSORS].name, sensor_token,
skStringParseStrerror(p_err));
rv = -1;
continue;
}
/* verify that start of range is valid */
sid = (sensorID_t)val_min;
if (!sksiteSensorExists(sid)) {
skAppPrintErr(("Invalid %s: Value %" PRIu32
" is not a valid sensor id"),
appOptions[OPT_SENSORS].name, val_min);
rv = -1;
continue;
}
/* verify that end of range is valid */
if (val_min != val_max && !sksiteSensorExists((sensorID_t)val_max)) {
skAppPrintErr(("Invalid %s: Value %" PRIu32
" is not a valid sensor id"),
appOptions[OPT_SENSORS].name, val_max);
rv = -1;
continue;
}
/* add all sensor IDs in range */
skBitmapRangeSet(sn_bitmap, sid, val_max);
}
/* did we find any sensors? */
if ((0 == rv) && (0 == skBitmapGetHighCount(sn_bitmap))) {
skAppPrintErr("Invalid %s: No valid sensors",
appOptions[OPT_SENSORS].name);
rv = -1;
}
END:
if (user_arg_freeable) {
free(user_arg_freeable);
}
return rv;
}
/*
* status = rws_parse_flowtypes(cl_bitmap, ft_bitmap);
*
* Parse the --flowtypes argument from the global 'flowtypes_arg'.
* Set a bit on 'cl_bitmap' for each valid class and and a bit on
* 'ft_bitmap' for each valid flowtype. Return 0 on success, or -1
* on if any class/type value is not a valid pair.
*/
static int rws_parse_flowtypes(
sk_bitmap_t *cl_bitmap,
sk_bitmap_t *ft_bitmap)
{
char *user_arg = NULL;
char *user_arg_freeable = NULL;
char *class_name;
char *type_name;
flowtype_iter_t ft_iter;
flowtypeID_t ft;
classID_t class_id;
int rv = 0;
/* nothing to do when no --flowtypes switch is given */
if (NULL == flowtypes_arg) {
return 0;
}
/* create a modifiable version of the user's input. store a
* pointer to it we can free it */
user_arg = strdup(flowtypes_arg);
user_arg_freeable = user_arg;
if (NULL == user_arg) {
skAppPrintOutOfMemory(NULL);
rv = -1;
goto END;
}
/* parse user's string as a comma separated list */
while ((class_name = strsep(&user_arg, ",")) != NULL) {
if (class_name[0] == '\0') {
/* empty token (e.g., double comma) */
continue;
}
/* break token into class and type separated by '/' */
type_name = strchr(class_name, '/');
if (type_name == NULL) {
skAppPrintErr("Invalid %s: Missing '/' in token '%s'",
appOptions[OPT_FLOWTYPES].name, class_name);
rv = -1;
continue;
}
*type_name = '\0';
++type_name;
/* find class and type. if lookup fails, test for special
* "all" keyword */
ft = sksiteFlowtypeLookupByClassType(class_name, type_name);
if (SK_INVALID_FLOWTYPE != ft) {
/* Yay! Class and type are specific */
skBitmapSetBit(ft_bitmap, ft);
skBitmapSetBit(cl_bitmap, sksiteFlowtypeGetClassID(ft));
} else if (0 == strcmp(class_name, "all")) {
if (0 == strcmp(type_name, "all")) {
/* Use all classes and all types. */
sksiteFlowtypeIterator(&ft_iter);
while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
skBitmapSetBit(ft_bitmap, ft);
skBitmapSetBit(cl_bitmap, sksiteFlowtypeGetClassID(ft));
}
} else {
/* Loop over all classes and add flowtype if type_name
* is valid for that class. Don't complain unless the
* type is not valid for any class. */
class_iter_t ci;
int found_type = 0;
sksiteClassIterator(&ci);
while (sksiteClassIteratorNext(&ci, &class_id)) {
ft = sksiteFlowtypeLookupByClassIDType(class_id,type_name);
if (SK_INVALID_FLOWTYPE != ft) {
++found_type;
skBitmapSetBit(ft_bitmap, ft);
skBitmapSetBit(cl_bitmap, class_id);
}
}
if (!found_type) {
skAppPrintErr(("Invalid %s:"
" Type '%s' not valid for any class"),
appOptions[OPT_FLOWTYPES].name, type_name);
rv = -1;
}
}
} else if (0 == strcmp(type_name, "all")) {
/* Use all types in the specified class */
class_id = sksiteClassLookup(class_name);
if (SK_INVALID_CLASS == class_id) {
skAppPrintErr("Invalid %s: Invalid class '%s'",
appOptions[OPT_FLOWTYPES].name, class_name);
rv = -1;
} else {
skBitmapSetBit(cl_bitmap, class_id);
sksiteClassFlowtypeIterator(class_id, &ft_iter);
while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
skBitmapSetBit(ft_bitmap, ft);
}
}
} else {
/* Invalid class/type */
skAppPrintErr("Invalid %s: Unknown class/type pair '%s/%s'",
appOptions[OPT_FLOWTYPES].name,
class_name, type_name);
rv = -1;
}
}
if ((rv == 0) && (skBitmapGetHighCount(ft_bitmap) == 0)) {
skAppPrintErr("Invalid %s: No valid class/type pairs",
appOptions[OPT_FLOWTYPES].name);
rv = -1;
}
END:
if (user_arg_freeable) {
free(user_arg_freeable);
}
return rv;
}
/*
* status = rws_parse_classes_and_types();
*
* Parse the --classes and/or --types arguments from the globals
* 'classes_arg' and 'types_arg'. Set a bit on 'cl_bitmap' for
* each valid class and and a bit on 'ft_bitmap' for each valid
* flowtype. Return 0 on success, or -1 on if any class/type value
* is not a valid pair.
*/
static int rws_parse_classes_and_types(
sk_bitmap_t *cl_bitmap,
sk_bitmap_t *ft_bitmap)
{
sk_bitmap_iter_t bmap_iter;
uint32_t bmap_val;
class_iter_t ci;
flowtype_iter_t ft_iter;
char *user_arg = NULL;
char *user_arg_freeable = NULL;
char *class_token = NULL;
char *type_token = NULL;
classID_t class_id;
flowtypeID_t ft;
int found_type;
int rv = 0;
if (NULL == classes_arg) {
/* temporarily enable all classes */
sksiteClassIterator(&ci);
while (sksiteClassIteratorNext(&ci, &class_id)) {
skBitmapSetBit(cl_bitmap, class_id);
}
} else {
/* create a copy of the input string and maintain a reference to
* it so we can free it */
user_arg = strdup(classes_arg);
user_arg_freeable = user_arg;
if (user_arg == NULL) {
skAppPrintOutOfMemory(NULL);
rv = -1;
goto END;
}
/* parse the classes as a comma separated list of tokens */
while ((class_token = strsep(&user_arg, ",")) != NULL) {
/* check for empty token (e.g., double comma) */
if ('\0' == *class_token) {
continue;
}
/* Handle default class token */
if (strcmp(class_token, "@") == 0) {
skBitmapSetBit(cl_bitmap, sksiteClassGetDefault());
continue;
}
/* look up class_token as a class name */
class_id = sksiteClassLookup(class_token);
if (SK_INVALID_CLASS != class_id) {
/* found it. add it to our lists and continue */
skBitmapSetBit(cl_bitmap, class_id);
continue;
}
skAppPrintErr("Invalid %s '%s': Unknown class name",
appOptions[OPT_CLASSES].name, class_token);
rv = -1;
continue;
}
free(user_arg_freeable);
user_arg_freeable = NULL;
/* did we find any classes? */
if ((0 == rv) && (0 == skBitmapGetHighCount(cl_bitmap))) {
skAppPrintErr("Invalid %s: No valid classes",
appOptions[OPT_CLASSES].name);
rv = -1;
}
if (NULL == types_arg) {
if (rv != 0) {
goto END;
}
/* there is no --types; enable all flowtypes that exist in
* the specified class(es) */
skBitmapIteratorBind(cl_bitmap, &bmap_iter);
while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK)
{
class_id = (classID_t)bmap_val;
sksiteClassFlowtypeIterator(class_id, &ft_iter);
while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
skBitmapSetBit(ft_bitmap, ft);
}
}
goto END;
}
}
/* create a modifiable version of the user's input. store a
* pointer to it we can free */
user_arg = strdup(types_arg);
user_arg_freeable = user_arg;
if (NULL == user_arg) {
skAppPrintOutOfMemory(NULL);
rv = -1;
goto END;
}
/* parse user's string as a comma separated list */
while ((type_token = strsep(&user_arg, ",")) != NULL) {
found_type = 0;
if (type_token[0] == '\0') {
/* empty token (e.g., double comma) */
continue;
}
/* check for the type in all the classes we found above */
skBitmapIteratorBind(cl_bitmap, &bmap_iter);
while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
class_id = (classID_t)bmap_val;
/* find class and type */
ft = sksiteFlowtypeLookupByClassIDType(class_id, type_token);
if (SK_INVALID_FLOWTYPE != ft) {
/* Yay! Class and type are specific */
skBitmapSetBit(ft_bitmap, ft);
++found_type;
} else if (0 == strcmp(type_token, "all")) {
/* Use all types in the specified class */
sksiteClassFlowtypeIterator(class_id, &ft_iter);
while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
++found_type;
skBitmapSetBit(ft_bitmap, ft);
}
} else if (0 == strcmp(type_token, "@")) {
sksiteClassDefaultFlowtypeIterator(class_id, &ft_iter);
while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
++found_type;
skBitmapSetBit(ft_bitmap, ft);
}
}
}
if (!found_type) {
skAppPrintErr("Invalid %s: Type '%s' not valid for %s",
appOptions[OPT_TYPES].name, type_token,
(classes_arg ? "specified classes" : "any class"));
rv = -1;
}
}
if ((rv == 0) && (skBitmapGetHighCount(ft_bitmap) == 0)) {
skAppPrintErr("Invalid --%s: No valid types",
appOptions[OPT_TYPES].name);
rv = -1;
}
if ((rv == 0) && (NULL == classes_arg)) {
/* no --classes were specified. reset the cl_bitmap based on
* the flowtypes we found */
skBitmapClearAllBits(cl_bitmap);
skBitmapIteratorBind(ft_bitmap, &bmap_iter);
while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
ft = (flowtypeID_t)bmap_val;
skBitmapSetBit(cl_bitmap, sksiteFlowtypeGetClassID(ft));
}
}
END:
if (user_arg_freeable) {
free(user_arg_freeable);
}
return rv;
}
/*
* status = rws_parse_restrictions();
*
* Parse the --classes, --types, --flowtypes, and --sensors options
* and create/fill bitmaps that restrict the output.
*
* Returns 0 on success, -1 on error.
*/
static int rws_parse_restrictions(void)
{
sk_bitmap_iter_t bmap_iter;
uint32_t bmap_val;
sk_bitmap_t *cl_mask = NULL;
sk_bitmap_t *ft_mask = NULL;
sk_bitmap_t *sn_mask = NULL;
class_iter_t class_iter;
flowtype_iter_t ft_iter;
sensor_iter_t sensor_iter;
classID_t class_id;
sensorID_t sensor_id;
flowtypeID_t flowtype_id;
int sensors_only = 0;
int rv = 0;
if (!classes_arg && !types_arg && !flowtypes_arg) {
if (!sensors_arg) {
/* nothing to do */
return 0;
}
/* else, only need to process --sensors */
sensors_only = 1;
}
/* create the global bitmaps for all classes, all flowtypes, and
* all sensors */
if (skBitmapCreate(&class_mask, 1 + sksiteClassGetMaxID())) {
skAppPrintOutOfMemory("class bitmap");
return -1;
}
if (skBitmapCreate(&flowtype_mask, 1 + sksiteFlowtypeGetMaxID())) {
skAppPrintOutOfMemory("flowtype bitmap");
return -1;
}
if (skBitmapCreate(&sensor_mask, 1 + sksiteSensorGetMaxID())) {
skAppPrintOutOfMemory("sensor bitmap");
return -1;
}
if (!sensors_only && sensors_arg) {
/* need to create temporary bitmaps */
if (skBitmapCreate(&cl_mask, 1 + sksiteClassGetMaxID())) {
skAppPrintOutOfMemory("class bitmap");
rv = -1;
goto END;
}
if (skBitmapCreate(&ft_mask, 1 + sksiteFlowtypeGetMaxID())) {
skAppPrintOutOfMemory("flowtype bitmap");
rv = -1;
goto END;
}
if (skBitmapCreate(&sn_mask, 1 + sksiteSensorGetMaxID())) {
skAppPrintOutOfMemory("sensor bitmap");
rv = -1;
goto END;
}
} else {
/* else we can point the temporaries at the real thing */
cl_mask = class_mask;
ft_mask = flowtype_mask;
sn_mask = sensor_mask;
}
if (sensors_arg) {
rv = rws_parse_sensors(sensor_mask);
if (sensors_only && rv != 0) {
goto END;
}
/* set class_mask and flowtype_mask based on the sensors we saw */
skBitmapIteratorBind(sensor_mask, &bmap_iter);
while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
sensor_id = (sensorID_t)bmap_val;
sksiteSensorClassIterator(sensor_id, &class_iter);
while (sksiteClassIteratorNext(&class_iter, &class_id)) {
skBitmapSetBit(cl_mask, class_id);
sksiteClassFlowtypeIterator(class_id, &ft_iter);
while (sksiteFlowtypeIteratorNext(&ft_iter, &flowtype_id)) {
skBitmapSetBit(ft_mask, flowtype_id);
}
}
}
if (sensors_only) {
return 0;
}
}
/* handle case when --flowtypes is given */
if (flowtypes_arg) {
if (classes_arg || types_arg) {
skAppPrintErr(("Cannot use --%s when either --%s or --%s is"
" specified"),
appOptions[OPT_FLOWTYPES].name,
appOptions[OPT_CLASSES].name,
appOptions[OPT_TYPES].name);
goto END;
}
rv |= rws_parse_flowtypes(class_mask, flowtype_mask);
if (rv != 0) {
goto END;
}
} else {
assert(classes_arg || types_arg);
rv |= rws_parse_classes_and_types(class_mask, flowtype_mask);
if (rv != 0) {
goto END;
}
}
/* set sensor_mask based on the classes we saw */
skBitmapIteratorBind(class_mask, &bmap_iter);
while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
class_id = (classID_t)bmap_val;
sksiteClassSensorIterator(class_id, &sensor_iter);
while (sksiteSensorIteratorNext(&sensor_iter, &sensor_id)) {
skBitmapSetBit(sn_mask, sensor_id);
}
}
/* perform the intersection of the masks with the temporaries */
if (sn_mask && sn_mask != sensor_mask) {
skBitmapIntersection(sensor_mask, sn_mask);
skBitmapDestroy(&sn_mask);
}
if (cl_mask && cl_mask != class_mask) {
skBitmapIntersection(class_mask, cl_mask);
skBitmapDestroy(&cl_mask);
}
if (ft_mask && ft_mask != flowtype_mask) {
skBitmapIntersection(flowtype_mask, ft_mask);
skBitmapDestroy(&ft_mask);
}
END:
if (sn_mask && sn_mask != sensor_mask) {
skBitmapDestroy(&sn_mask);
}
if (cl_mask && cl_mask != class_mask) {
skBitmapDestroy(&cl_mask);
}
if (ft_mask && ft_mask != flowtype_mask) {
skBitmapDestroy(&ft_mask);
}
return rv;
}
/*
* rws_iter_bind(&iter, level);
*
* Bind the sub-iterator of a site iterator at the given level.
*/
static void rws_iter_bind(
rws_iter_t *iter,
int level)
{
assert(iter);
assert(iter->level >= level);
/* Negative level is for a non-iterable iterator. This is used
* for options that require no iteration, like
* --fields=class-default. */
if (level >= 0) {
switch (iter->order[level]) {
case RWS_FLOWTYPE:
sksiteFlowtypeIterator(&iter->flowtype_iter);
break;
case RWS_CLASS:
sksiteClassIterator(&iter->class_iter);
break;
case RWS_SENSOR:
sksiteSensorIterator(&iter->sensor_iter);
break;
case RWS_FLOWTYPE_FROM_CLASS:
sksiteClassFlowtypeIterator(iter->class_id, &iter->flowtype_iter);
break;
case RWS_CLASS_FROM_SENSOR:
sksiteSensorClassIterator(iter->sensor_id, &iter->class_iter);
break;
case RWS_SENSOR_FROM_CLASS:
sksiteClassSensorIterator(iter->class_id, &iter->sensor_iter);
break;
case RWS_DEFAULT_FLOWTYPE_FROM_CLASS:
sksiteClassDefaultFlowtypeIterator(
iter->class_id, &iter->flowtype_iter);
iter->default_type = 1;
break;
case RWS_NULL:
skAbortBadCase(iter->order[level]);
break;
}
}
/* We are now bound at this level */
iter->bound = level;
/* But mark as not having stared iteration yet */
iter->started = level - 1;
}
/*
* status = rws_iter_next(iter, level);
*
* Site iterator iteration, at a particular sub-iterator level.
* Returns 1 on success, 0 if the iteration is complete at the
* given level.
*/
static int rws_iter_next(
rws_iter_t *iter,
int level)
{
int rv;
assert(iter);
assert(iter->level >= level);
/* Prevent re-iteration after already having completed
* iteration */
if (iter->bound < level) {
assert(level == 0);
return 0;
}
do {
/* Iterate at the next level if we've already started
* iteration on this level */
if (iter->started >= level && level < iter->level) {
if (iter->bound == level) {
rws_iter_bind(iter, level + 1);
}
rv = rws_iter_next(iter, level + 1);
if (rv != 0) {
/* Leaf iter succeeded */
return 1;
}
}
/* Iterate at the current level */
switch (iter->order[level]) {
case RWS_FLOWTYPE:
case RWS_FLOWTYPE_FROM_CLASS:
case RWS_DEFAULT_FLOWTYPE_FROM_CLASS:
/* Flowtype iteration */
while ((rv = sksiteFlowtypeIteratorNext(&iter->flowtype_iter,
&iter->flowtype_id))
&& flowtype_mask != NULL
&& !skBitmapGetBit(flowtype_mask, iter->flowtype_id))
; /* empty */
/* Set class from flowtype */
if (rv) {
iter->class_id = sksiteFlowtypeGetClassID(iter->flowtype_id);
}
break;
case RWS_CLASS:
case RWS_CLASS_FROM_SENSOR:
/* Class iteration */
while ((rv = sksiteClassIteratorNext(&iter->class_iter,
&iter->class_id))
&& class_mask != NULL
&& !skBitmapGetBit(class_mask, iter->class_id))
; /* empty */
break;
case RWS_SENSOR:
case RWS_SENSOR_FROM_CLASS:
/* Sensor iteration */
while ((rv = sksiteSensorIteratorNext(&iter->sensor_iter,
&iter->sensor_id))
&& sensor_mask != NULL
&& !skBitmapGetBit(sensor_mask, iter->sensor_id))
; /* empty */
break;
default:
skAbortBadCase(iter->order[level]);
}
/* Mark that we've started iterating at the current level */
if (iter->started < level) {
iter->started = level;
}
if (rv && level == iter->level) {
/* return success at leaf */
return 1;
}
/* Iterate until a leaf iteration succeeds, or we fail to
* iterate at this level. */
} while (rv);
/* Iteration is over. We are no longer bound at this level. */
iter->bound = level - 1;
return 0;
}
/*
* len = rws_print_field(printer, fd, iter, field, width);
*
* Print a 'width'-wide column containing the value for 'field'
* using the fprintf-style function 'printer' to the FILE pointer
* 'fd', where 'iter' is the current context.
*
* Return the number of characters printed.
*/
static int rws_print_field(
rws_fprintf_t printer,
FILE *fd,
rws_iter_t *iter,
rws_field_t field,
int width)
{
/* buffer large enough to hold a single sensor name or flowtype
* name */
char buf[SK_MAX_STRLEN_SENSOR + SK_MAX_STRLEN_FLOWTYPE];
const char *s;
int rv = 0;
switch (field) {
case RWST_CLASS:
if (iter->class_id != SK_INVALID_CLASS) {
sksiteClassGetName(buf, sizeof(buf), iter->class_id);
rv = printer(fd, "%*s", width, buf);
}
break;
case RWST_DEFAULT_TYPE:
if (!iter->default_type) {
/* When there's no default_type iterator, we can't do a
* default_type */
break;
}
/* Fall through */
case RWST_TYPE:
if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
sksiteFlowtypeGetType(buf, sizeof(buf), iter->flowtype_id);
rv = printer(fd, "%*s", width, buf);
}
break;
case RWST_FLOWTYPE:
if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
sksiteFlowtypeGetName(buf, sizeof(buf), iter->flowtype_id);
rv = printer(fd, "%*s", width, buf);
}
break;
case RWST_FLOWTYPE_ID:
if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
rv = printer(fd, "%*" PRIu8, width, iter->flowtype_id);
}
break;
case RWST_SENSOR:
if (iter->sensor_id != SK_INVALID_SENSOR) {
sksiteSensorGetName(buf, sizeof(buf), iter->sensor_id);
rv = printer(fd, "%*s", width, buf);
}
break;
case RWST_SENSOR_ID:
if (iter->sensor_id != SK_INVALID_SENSOR) {
rv = printer(fd, "%*" PRIu16, width, iter->sensor_id);
}
break;
case RWST_SENSOR_DESC:
if (iter->sensor_id != SK_INVALID_SENSOR) {
s = sksiteSensorGetDescription(iter->sensor_id);
if (s != NULL) {
rv = printer(fd, "%*s", width, s);
}
}
break;
case RWST_DEFAULT_CLASS:
case RWST_DEFAULT_CLASS_LIST:
{
classID_t cid = sksiteClassGetDefault();
if (cid != SK_INVALID_CLASS) {
sksiteClassGetName(buf, sizeof(buf), cid);
rv = printer(fd, "%*s", width, buf);
}
}
break;
case RWST_MARK_DEFAULTS:
{
char mark[3] = {' ', ' ', '\0'};
int i = 0;
if (iter->class_id != SK_INVALID_CLASS) {
if (no_columns) {
memset(mark, 0, sizeof(mark));
}
if (iter->class_id == sksiteClassGetDefault())
{
mark[0] = '+';
++i;
}
if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
flowtype_iter_t fi;
flowtypeID_t ft;
/* See if this type is a default for this class */
sksiteClassDefaultFlowtypeIterator(iter->class_id, &fi);
while (sksiteFlowtypeIteratorNext(&fi, &ft)) {
if (iter->flowtype_id == ft) {
mark[no_columns ? i : 1] = '*';
++i;
break;
}
}
}
}
rv = printer(fd, "%*s", width, mark);
}
break;
case RWST_CLASS_LIST:
rv = rws_print_list_field(printer, fd, iter, RWST_CLASS, width);
break;
case RWST_TYPE_LIST:
rv = rws_print_list_field(printer, fd, iter, RWST_TYPE, width);
break;
case RWST_FLOWTYPE_LIST:
rv = rws_print_list_field(printer, fd, iter, RWST_FLOWTYPE, width);
break;
case RWST_FLOWTYPE_ID_LIST:
rv = rws_print_list_field(printer, fd, iter, RWST_FLOWTYPE_ID, width);
break;
case RWST_SENSOR_LIST:
rv = rws_print_list_field(printer, fd, iter, RWST_SENSOR, width);
break;
case RWST_SENSOR_ID_LIST:
rv = rws_print_list_field(printer, fd, iter, RWST_SENSOR_ID, width);
break;
case RWST_DEFAULT_TYPE_LIST:
rv = rws_print_list_field(printer, fd, iter, RWST_DEFAULT_TYPE, width);
break;
case RWST_MAX_FIELD_COUNT:
skAbortBadCase(field);
}
/* Fill in any missing spaces. */
if (rv < width) {
printer(fd, "%*s", width - rv, "");
}
return rv;
}
/*
* len = rws_print_list_field(printer, fd, iter, field, width);
*
* Print a 'width'-wide column containing the value for 'field'
* (where 'field' represents a "FIELD:list" field) using the
* fprintf-style function 'printer' to the FILE pointer 'fd', where
* 'iter' is the current context.
*
* Return the number of characters printed.
*/
static int rws_print_list_field(
rws_fprintf_t printer,
FILE *fd,
rws_iter_t *iter,
rws_field_t field,
int width)
{
int total = 0;
int len;
rws_iter_t subiter;
int first;
/* Create a site iterator containing a single sub-iterator of the
* correct type. */
memset(&subiter, 0, sizeof(subiter));
switch (field) {
case RWST_CLASS:
if (iter->sensor_id == SK_INVALID_SENSOR) {
subiter.order[0] = RWS_CLASS;
} else {
subiter.order[0] = RWS_CLASS_FROM_SENSOR;
}
subiter.sensor_id = iter->sensor_id;
break;
case RWST_TYPE:
case RWST_FLOWTYPE:
case RWST_FLOWTYPE_ID:
if (iter->class_id == SK_INVALID_CLASS) {
subiter.order[0] = RWS_FLOWTYPE;
} else {
subiter.order[0] = RWS_FLOWTYPE_FROM_CLASS;
}
subiter.class_id = iter->class_id;
subiter.flowtype_id = iter->flowtype_id;
break;
case RWST_SENSOR:
case RWST_SENSOR_ID:
if (iter->class_id == SK_INVALID_CLASS) {
subiter.order[0] = RWS_SENSOR;
} else {
subiter.order[0] = RWS_SENSOR_FROM_CLASS;
}
subiter.class_id = iter->class_id;
break;
case RWST_DEFAULT_TYPE:
if (iter->class_id == SK_INVALID_CLASS) {
return 0;
}
subiter.order[0] = RWS_DEFAULT_FLOWTYPE_FROM_CLASS;
subiter.class_id = iter->class_id;
break;
default:
skAbortBadCase(field);
}
rws_iter_bind(&subiter, 0);
/* Call ourself with the fake-fprintf to determine the number of
* printed characters in this field, and then print the padding */
if (width != 0) {
len = rws_print_list_field(fprintf_size, NULL, iter, field, 0);
if (len < width) {
total += printer(fd, "%*s", width - len, "");
}
}
/* Iterate over the fields, printing each */
first = 1;
while (rws_iter_next(&subiter, 0)) {
if (!first) {
len = printer(fd, "%c", list_separator);
total += len;
}
len = rws_print_field(printer, fd, &subiter, field, 0);
total += len;
first = 0;
}
return total;
}
/*
* rws_print_row(iter);
*
* Print a single row from an iterator.
*/
static void rws_print_row(
rws_iter_t *iter)
{
size_t i;
for (i = 0; i < num_fields; ++i) {
if (i > 0) {
fprintf(output.of_fp, "%c", column_separator);
}
rws_print_field(fprintf, output.of_fp, iter,
fields[i], col_width[fields[i]]);
}
fprintf(output.of_fp, "%s\n", final_delim);
}
/*
* len = fprintf_size(fs, format, ...);
*
* Used to calculate print sizes. This fprintf() variation does
* not produce outout, it simply returns how many charcters it
* WOULD have printed.
*/
static int fprintf_size(
FILE UNUSED(*stream),
const char *format,
...)
{
char buf;
int len;
va_list ap;
va_start(ap, format);
len = vsnprintf(&buf, 0, format, ap);
va_end(ap);
return len;
}
/*
* rws_calcsize_row(iter);
*
* Updates column sizes based on a single row that would be printed
* from the given iterator.
*/
static void rws_calcsize_row(
rws_iter_t *iter)
{
size_t i;
int len;
for (i = 0; i < num_fields; i++) {
len = rws_print_field(fprintf_size, NULL, iter, fields[i], 0);
if (len > col_width[fields[i]]) {
col_width[fields[i]] = len;
}
}
}
/*
* rws_print_titles();
*
* Print the column headings unless --no-titles was specified.
*/
static void rws_print_titles(void)
{
size_t i;
if (no_titles) {
return;
}
for (i = 0; i < num_fields; ++i) {
if (i > 0) {
fprintf(output.of_fp, "%c", column_separator);
}
fprintf(output.of_fp, "%*s", col_width[fields[i]],
(char *)field_map_entries[fields[i]].userdata);
}
fprintf(output.of_fp, "%s\n", final_delim);
}
/*
* status = rws_setup_iter_from_fields(iter);
*
* Set up the iterator for iterating based on the field list.
*
* Return 0 for normal iteration. Return -1 for no output (other
* than titles). Return 1 for outputting a single non-iterated
* entry.
*/
static int rws_setup_iter_from_fields(
rws_iter_t *iter)
{
size_t i;
/* Next iterator level to initialize */
int level = 0;
/* Boolean: class iterator set? */
int class_set = 0;
/* Boolean: flowtype iterator set? */
int flowtype_set = 0;
/* Boolean: sensor iterator set? */
int sensor_set = 0;
/* Default-type iterator set at this level (0 == none, since
* default-type cannot exist at level 0. */
int default_type = 0;
/* Boolean: could be a non-iterable singleton */
int singleton = 0;
memset(iter, 0, sizeof(*iter));
iter->level = -1;
for (i = 0; i < num_fields; i++) {
switch (fields[i]) {
case RWST_CLASS:
case RWST_DEFAULT_TYPE_LIST:
/* Need classes to generate default types */
if (class_set || flowtype_set) {
break;
}
iter->order[level] = sensor_set ? RWS_CLASS_FROM_SENSOR : RWS_CLASS;
iter->level = level;
++level;
class_set = 1;
break;
case RWST_TYPE:
case RWST_FLOWTYPE:
case RWST_FLOWTYPE_ID:
if (flowtype_set) {
break;
}
if (default_type) {
/* Replace default type, as flowtype and default type
is nonsensical */
iter->order[default_type] =
class_set ? RWS_FLOWTYPE_FROM_CLASS : RWS_FLOWTYPE;
default_type = 0;
} else {
iter->order[level] =
class_set ? RWS_FLOWTYPE_FROM_CLASS : RWS_FLOWTYPE;
iter->level = level;
++level;
}
flowtype_set = 1;
break;
case RWST_SENSOR:
case RWST_SENSOR_ID:
case RWST_SENSOR_DESC:
if (sensor_set) {
break;
}
iter->order[level] = class_set ? RWS_SENSOR_FROM_CLASS : RWS_SENSOR;
iter->level = level;
++level;
sensor_set = 1;
break;
case RWST_DEFAULT_TYPE:
assert(!default_type);
if (flowtype_set) {
break;
}
if (!class_set) {
/* Default-type needs a class iterator, so add one */
iter->order[level] =
sensor_set ? RWS_CLASS_FROM_SENSOR : RWS_CLASS;
++level;
class_set = 1;
}
iter->order[level] = RWS_DEFAULT_FLOWTYPE_FROM_CLASS;
iter->level = level;
++level;
default_type = level;
break;
case RWST_DEFAULT_CLASS:
case RWST_CLASS_LIST:
case RWST_TYPE_LIST:
case RWST_FLOWTYPE_LIST:
case RWST_FLOWTYPE_ID_LIST:
case RWST_SENSOR_LIST:
case RWST_SENSOR_ID_LIST:
case RWST_DEFAULT_CLASS_LIST:
/* These fields can generate null-iterators with a single
* row of output. */
singleton = 1;
break;
case RWST_MARK_DEFAULTS:
break;
case RWST_MAX_FIELD_COUNT:
default:
skAbortBadCase(fields[i]);
}
}
/* Bind the iterator (at level -1 if this is a null-iterator) */
iter->flowtype_id = SK_INVALID_FLOWTYPE;
iter->class_id = SK_INVALID_CLASS;
iter->sensor_id = SK_INVALID_SENSOR;
rws_iter_bind(iter, level ? 0 : -1);
if (level != 0) {
/* Return 0 if this is not a null iterator */
return 0;
}
/* Return 1 if this is a singleton null-iterator. -1 otherwise */
return singleton ? 1 : -1;
}
int main(int argc, char **argv)
{
rws_iter_t iter;
rws_iter_t calciter;
int rv;
appSetup(argc, argv); /* never returns on error */
/* Set up site iterator */
rv = rws_setup_iter_from_fields(&iter);
if (rv == -1) {
/* Nothing to do */
rws_print_titles();
return EXIT_SUCCESS;
}
/* Calculate column sizes */
if (!no_columns) {
calciter = iter;
if (rv == 1) {
/* Null iterator case */
rws_calcsize_row(&calciter);
} else {
while (rws_iter_next(&calciter, 0)) {
rws_calcsize_row(&calciter);
}
}
}
/* Print titles */
rws_print_titles();
/* Print rows */
if (rv == 1) {
/* Null iterator case */
rws_print_row(&iter);
} else {
while (rws_iter_next(&iter, 0)) {
rws_print_row(&iter);
}
}
return EXIT_SUCCESS;
}
/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/
[-- Attachment #3: Type: text/plain, Size: 41 bytes --]
--
Michael Welsh Duggan
(mwd@cert.org)
next prev parent reply other threads:[~2012-11-26 13:25 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-19 20:45 bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Kim F. Storm
2012-06-21 7:17 ` Glenn Morris
2012-06-21 9:34 ` Kim Storm
2012-08-28 16:17 ` bug#11749: 24.2; wrong-type-argument Kim F. Storm
[not found] ` <handler.11749.B.13401389485673.ack@debbugs.gnu.org>
2012-08-28 22:49 ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Kim Storm
2012-08-31 11:01 ` Eli Zaretskii
2012-08-31 12:37 ` Kim Storm
2012-09-02 21:16 ` Alan Mackenzie
2012-09-03 9:47 ` Kim Storm
2012-09-03 13:56 ` Stefan Monnier
2012-09-03 14:20 ` Kim Storm
2012-09-03 18:52 ` Stefan Monnier
2012-09-05 20:48 ` Alan Mackenzie
2012-09-07 3:45 ` Michael Welsh Duggan
2012-09-07 14:53 ` Stefan Monnier
2012-09-07 16:16 ` Kim Storm
2012-09-08 21:14 ` Alan Mackenzie
2012-09-10 12:18 ` Michael Welsh Duggan
2012-09-10 12:48 ` Michael Welsh Duggan
2012-09-21 17:47 ` Michael Welsh Duggan
2012-10-07 10:59 ` Alan Mackenzie
2012-10-09 14:05 ` Michael Welsh Duggan
2012-10-10 20:00 ` Alan Mackenzie
2012-10-14 17:06 ` Alan Mackenzie
2012-10-23 16:13 ` Michael Welsh Duggan
2012-10-25 13:41 ` Michael Welsh Duggan
2012-10-28 11:36 ` Alan Mackenzie
2012-11-04 3:43 ` Chong Yidong
2012-11-04 20:42 ` Alan Mackenzie
2012-11-21 20:58 ` Alan Mackenzie
2012-11-22 14:52 ` Stefan Monnier
2012-11-04 20:39 ` Alan Mackenzie
2012-11-04 21:04 ` Kim Storm
2012-11-14 16:52 ` Michael Welsh Duggan
2012-11-21 21:33 ` Alan Mackenzie
2012-11-26 13:25 ` Michael Welsh Duggan [this message]
2012-12-10 3:35 ` Michael Welsh Duggan
2013-01-07 12:09 ` Alan Mackenzie
2013-01-17 16:27 ` Michael Welsh Duggan
2013-01-17 16:28 ` Michael Welsh Duggan
2013-01-23 14:16 ` Alan Mackenzie
2013-01-23 15:39 ` Michael Welsh Duggan
2013-01-29 11:37 ` Alan Mackenzie
[not found] ` <20130129113737.GA4544@acm.acm>
2013-02-01 22:18 ` Michael Welsh Duggan
2013-02-01 23:50 ` Kim Storm
2013-02-02 19:35 ` Alan Mackenzie
2012-09-10 13:10 ` Michael Welsh Duggan
2012-09-10 13:22 ` Michael Welsh Duggan
2012-09-10 18:25 ` Michael Welsh Duggan
2012-09-05 13:11 ` bug#11749: I also have this issue Denis Zalevskiy
2013-01-08 19:10 ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Glenn Morris
2013-01-09 22:13 ` Alan Mackenzie
2013-02-02 18:37 ` bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Alan Mackenzie
2013-01-08 13:49 ` bug#13385: 24.1; TAB in C file causes type error Julian Stecklina
[not found] ` <handler.13385.D11749.1359830688892.notifdone@debbugs.gnu.org>
2013-02-03 13:00 ` bug#13385: closed (Re: 24.1; C-mode indentation gives wrong-type-argument error.) Julian Stecklina
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=tnty5ho4hte.fsf@waterbuck.yellow.cert.org \
--to=mwd@cert.org \
--cc=11749@debbugs.gnu.org \
--cc=acm@muc.de \
--cc=storm@cua.dk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).