Logo Search packages:      
Sourcecode: gretl version File versions

validate.c

/* Grab command info from libgretl, and compare with the
   command reference in gretl_commands.xml.  Check for any
   inconsistencies.

   Allin Cottrell, Feb 2004.
*/

#include "libgretl.h"

#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>

#define ROOTNODE "commandlist"
#define UTF const xmlChar *

char reffile[FILENAME_MAX];

typedef struct _cmdlist cmdlist;
typedef struct _command command;

struct _command {
    char *name;
    int nopts;
    char **opts;
};

struct _cmdlist {
    int ncmds;
    command **cmds;
};

static void missing_attrib (const char *element, const char *attrib)
{
    fprintf(stderr, "Required attribute '%s' missing for element '%s'\n",
          attrib, element);
}

static command *command_new (void)
{
    command *cmd;

    cmd = malloc(sizeof *cmd);
    if (cmd != NULL) {
      cmd->name = NULL;
      cmd->nopts = 0;
      cmd->opts = NULL;
    }

    return cmd;
}

static void 
process_option (xmlDocPtr doc, xmlNodePtr node, command *cmd, int i)
{
    xmlNodePtr cur;

    cur = node->xmlChildrenNode;
    while (cur != NULL) {  
        if (!xmlStrcmp(cur->name, (UTF) "flag")) {
          cmd->opts[i] = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
      } 
      cur = cur->next;
    }
}

static int 
process_option_list (xmlDocPtr doc, xmlNodePtr node, command *cmd)
{
    xmlNodePtr cur;
    char **opts;
    int nopts;

    cur = node->xmlChildrenNode;
    while (cur != NULL) {
        if (!xmlStrcmp(cur->name, (UTF) "option")) {
          nopts = cmd->nopts + 1;
          opts = realloc(cmd->opts, nopts * sizeof *opts);
          if (opts == NULL) return 1;
          cmd->opts = opts;
          cmd->nopts = nopts;
          process_option(doc, cur, cmd, nopts - 1);
      }
      cur = cur->next;
    }

    return 0;
}

static int 
process_usage (xmlDocPtr doc, xmlNodePtr node, command *cmd)
{
    xmlNodePtr cur;

    cur = node->xmlChildrenNode;
    while (cur != NULL) {
        if (!xmlStrcmp(cur->name, (UTF) "options")) {
          process_option_list(doc, cur, cmd);
      }
      cur = cur->next;
    }

    return 0;
}

static int check_for_label (xmlNodePtr node)
{
    char *tmp;
    int err = 0;

    tmp = xmlGetProp(node, (UTF) "label");
    if (tmp == NULL) {
      char *name = xmlGetProp(node, (UTF) "name");

      printf("'%s': command is on gui list but has no gui label\n",
             name);
      free(name);
      err = 1;
    } else {
      free(tmp);
    }

    return err;
}

static int 
process_command (xmlDocPtr doc, xmlNodePtr node, cmdlist *clist)
{
    command *cmd, **cmds = NULL;
    xmlNodePtr cur;
    char *tmp;
    int nc, err = 0;

    cmd = command_new();

    if (cmd == NULL) {
      fprintf(stderr, "Out of memory\n");
      return 1;
    }

    tmp = xmlGetProp(node, (UTF) "context");
    if (tmp == NULL || strcmp(tmp, "cli")) {
      check_for_label(node);
    }
    if (tmp != NULL && !strcmp(tmp, "gui")) {
      free(tmp);
      return 0;
    }

    tmp = xmlGetProp(node, (UTF) "name");
    if (tmp == NULL) {
      missing_attrib("command", "name");
      return 1;
    } else {
      cmd->name = tmp;
    }

    nc = clist->ncmds + 1;

    cmds = realloc(clist->cmds, nc * sizeof *cmds);
    if (cmds == NULL) {
      fprintf(stderr, "Out of memory\n");
      return 1;
    }

    clist->cmds = cmds;
    clist->cmds[nc - 1] = cmd;
    clist->ncmds = nc;

    /* walk the tree for this command */
    cur = node->xmlChildrenNode;
    while (cur != NULL && !err) {
        if (!xmlStrcmp(cur->name, (UTF) "usage")) {
          err = process_usage(doc, cur, cmd);
      }
      cur = cur->next;
    }

    return err;
}

static int parse_ref_file (cmdlist *clist)
{
    xmlDocPtr doc;
    xmlNodePtr cur;
    int err = 0;

    LIBXML_TEST_VERSION 
      xmlKeepBlanksDefault(0);

    xmlSubstituteEntitiesDefault(1);
    xmlLoadExtDtdDefaultValue = 1;

    doc = xmlParseFile(reffile);
    if (doc == NULL) {
      err = 1;
      goto bailout;
    }

    cur = xmlDocGetRootElement(doc);
    if (cur == NULL) {
      err = 1;
      goto bailout;
    }

    if (xmlStrcmp(cur->name, (UTF) ROOTNODE)) {
      fprintf(stderr, "File of the wrong type, root node not %s\n", 
            ROOTNODE);
      err = 1;
      goto bailout;
    }

    /* Now walk the tree */
    cur = cur->xmlChildrenNode;
    while (cur != NULL && !err) {
        if (!xmlStrcmp(cur->name, (UTF) "command")) {
          err = process_command(doc, cur, clist);
      }
      cur = cur->next;
    }    

 bailout:

    xmlFreeDoc(doc);
    xmlCleanupParser();

    return err;

}

static void cmdlist_init (cmdlist *clist)
{
    clist->ncmds = 0;
    clist->cmds = NULL;
}

static int ref_cmd_in_gretl (const char *cmdword)
{
    int i;

    for (i=1; i<NC; i++) {
      if (!strcmp(cmdword, gretl_command_word(i))) {
          return 1;
      }
    }

    return 0;
}

static int
option_lists_match (const char *cmdword, const char **libopts, int libn,
                char **refopts, int refn)
{
    int match;
    int i, j;

    for (i=0; i<refn; i++) {
      match = 0;
      for (j=0; j<libn; j++) {
          if (!strcmp(libopts[j], refopts[i] + 2)) {
            match = 1;
            break;
          }
      }
      if (!match) {
          printf("* '%s': ref option '%s' unmatched in lib\n", cmdword, refopts[i]);
      }
    }

    for (i=0; i<libn; i++) {
      match = 0;
      for (j=0; j<refn; j++) {
          if (!strcmp(libopts[i], refopts[j] + 2)) {
            match = 1;
            break;
          }
      }
      if (!match) {
          printf("* '%s': lib option '--%s' unmatched in ref\n", cmdword, libopts[i]);
      }
    }

    return 0;
}

static int check_options_for_cmd (command *cmd)
{
    const char **libopts = NULL;
    int i, nopt;

    for (i=1; i<NC; i++) {
      if (!strcmp(cmd->name, gretl_command_word(i))) {
          libopts = get_opts_for_command(i, &nopt);
          break;
      }
    }

    if (libopts == NULL) return 1;

    if (nopt != cmd->nopts) {
      printf("* '%s' appears to have %d options in lib, %d in manual\n",
             cmd->name, nopt, cmd->nopts);
    }

    option_lists_match(cmd->name, libopts, nopt, cmd->opts, cmd->nopts);

    free(libopts);
    
    return 0;
}

static int gretl_cmd_in_ref (const char *cmdword, const cmdlist *clist)
{
    int i;

    for (i=0; i<clist->ncmds; i++) {
      if (!strcmp(cmdword, (clist->cmds[i])->name)) {
          return 1;
      }
    }

    return 0;
}

static int check_commands (cmdlist *clist)
{
    const char *cmdword;
    int i, err = 0, missing = 0, extra = 0;

    /* NC is the sentinel value for the maximum gretl command index */
    for (i=1; i<NC; i++) {
      /* Get the string associated with each command index
         number, from libgretl */
      cmdword = gretl_command_word(i);

      /* check against XML reference list */
      if (!gretl_cmd_in_ref(cmdword, clist)) {
          printf("* libgretl command '%s' is not in the reference\n", 
               cmdword);
          missing++;
      }
    }

    /* reverse check */
    for (i=0; i<clist->ncmds; i++) {
      if (!ref_cmd_in_gretl((clist->cmds[i])->name)) {
          printf("* ref command '%s' is not in libgretl\n", 
               (clist->cmds[i])->name);
          extra++;
      }
    }

    /* options check */
    for (i=0; i<clist->ncmds; i++) {
      check_options_for_cmd(clist->cmds[i]);
    }    

    if (missing > 0 || extra > 0) {
      err = 1;
    }

    printf("Number of library commands missing from reference: %d\n", missing);
    printf("Number of extra commands in ref but not in library: %d\n", extra);

    return err;
}

void free_cmd (command *cmd)
{
    int i;

    free(cmd->name);
    for (i=0; i<cmd->nopts; i++) {
      free(cmd->opts[i]);
    }
    free(cmd->opts);
    free(cmd);
}

void free_cmdlist (cmdlist *clist)
{
    int i;

    for (i=0; i<clist->ncmds; i++) {
      free_cmd(clist->cmds[i]);
    }
    free(clist->cmds);
}

int main (int argc, char **argv)
{
    cmdlist clist;
    int err;

    if (argc != 2) {
      fprintf(stderr, "Please supply one argument: the name of a "
            "file to verify\n");
      exit(EXIT_FAILURE);
    }

    strcpy(reffile, argv[1]);

    cmdlist_init(&clist);

    err = parse_ref_file(&clist);
    if (err) {
      fprintf(stderr, "Error parsing %s\n", reffile);
      exit(EXIT_FAILURE);
    }

    printf("Found %d commands in '%s'\n", clist.ncmds, reffile);

    err = check_commands(&clist);

#if 0
    free_cmdlist(&clist);
#endif

    return err;
}

Generated by  Doxygen 1.6.0   Back to index