Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: determine tree schema and print it out #413

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
WIP: determine tree schema and print it out
This uses the structure of lenses, simplifies it a little bit and adds a
command 'schema' in augtool that makes it possible to print out the schema
for the tree that this lens will produce.

The output format is pretty inscrutable right now
lutter committed Oct 9, 2016
commit 60ad144d84c755ba4d9b3183dfcf6ba136472a78
3 changes: 2 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
@@ -23,7 +23,8 @@ libaugeas_la_SOURCES = augeas.h augeas.c augrun.c pathx.c \
memory.h memory.c ref.h ref.c \
syntax.c syntax.h parser.y builtin.c lens.c lens.h regexp.c regexp.h \
transform.h transform.c ast.c get.c put.c list.h \
info.c info.h errcode.c errcode.h jmt.h jmt.c
info.c info.h errcode.c errcode.h jmt.h jmt.c \
schema.h schema.c

if USE_VERSION_SCRIPT
AUGEAS_VERSION_SCRIPT = $(VERSION_SCRIPT_FLAGS)$(srcdir)/augeas_sym.version
38 changes: 38 additions & 0 deletions src/augrun.c
Original file line number Diff line number Diff line change
@@ -1202,6 +1202,43 @@ static const struct command_def cmd_retrieve_def = {
.help = cmd_retrieve_help
};

#include "syntax.h"
#include "schema.h"

static void cmd_schema(struct command *cmd) {
const char *lens_name = arg_value(cmd, "lens");
struct augeas *aug = cmd->aug;
struct lens *lens = NULL;
struct schema *schema = NULL;

lens = lens_lookup(aug, lens_name);
if (lens == NULL) {
ERR_REPORT(cmd, AUG_ECMDRUN, "Lens %s does not exist", lens_name);
return;
}

schema = schema_from_lens(lens);
ERR_BAIL(aug);
simplify_schema(schema);
dump_schema(cmd->out, schema);
error:
free_schema(schema);
}

static const struct command_opt_def cmd_schema_opts[] = {
{ .type = CMD_STR, .name = "lens", .optional = false,
.help = "show schema for this lens" },
CMD_OPT_DEF_LAST
};

static const struct command_def cmd_schema_def = {
.name = "schema",
.opts = cmd_schema_opts,
.handler = cmd_schema,
.synopsis = "show the schema for a lens",
.help = "show the schema for a lens"
};

/* Given a path "/augeas/files/FILENAME/error", return FILENAME */
static char *err_filename(const char *match) {
int noise = strlen(AUGEAS_META_FILES) + strlen("/error");
@@ -1324,6 +1361,7 @@ static const struct command_grp_def cmd_grp_admin_def = {
&cmd_store_def,
&cmd_transform_def,
&cmd_load_file_def,
&cmd_schema_def,
&cmd_def_last
}
};
2 changes: 1 addition & 1 deletion src/augtool.c
Original file line number Diff line number Diff line change
@@ -180,7 +180,7 @@ static char *readline_command_generator(const char *text, int state) {
"get", "label", "ins", "load", "ls", "match",
"mv", "cp", "rename", "print", "dump-xml", "rm", "save", "set", "setm",
"clearm", "span", "store", "retrieve", "transform", "load-file",
"help", "touch", "insert", "move", "copy", "errors", NULL };
"help", "touch", "insert", "move", "copy", "errors", "schema", NULL };

static int current = 0;
const char *name;
292 changes: 292 additions & 0 deletions src/schema.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
/*
* schema.c: support for generating a tree schema from a lens
*
* Copyright (C) 2016 David Lutterkort
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: David Lutterkort <lutter@watzmann.net>
*/

#include "schema.h"

#include "internal.h"
#include "errcode.h"
#include "memory.h"

static struct schema* make_schema(enum schema_tag tag, struct info *info) {
struct schema *result = NULL;
int r;

r = ALLOC(result);
ERR_NOMEM(r < 0, info);

result->tag = tag;
result->info = ref(info);

return result;
error:
return NULL;
}

static struct schema *make_schema_concat_or_union(struct lens *lens) {
struct schema *result = NULL;
enum schema_tag tag;

int r;

ensure0(lens->tag == L_CONCAT || lens->tag == L_UNION, lens->info);

tag = lens->tag == L_CONCAT ? S_CONCAT : S_UNION;

result = make_schema(tag, lens->info);
ERR_BAIL(lens->info);

r = ALLOC_N(result->children, lens->nchildren);
ERR_NOMEM(r < 0, lens->info);
result->nchildren = lens->nchildren;
for (int i=0; i < result->nchildren; i++) {
result->children[i] = schema_from_lens(lens->children[i]);
}
return result;
error:
free_schema(result);
return NULL;
}

void simplify_schema(struct schema *schema) {
if (schema == NULL)
return;

switch(schema->tag) {
case S_REC:
case S_UNIT:
break;
case S_CONCAT:
case S_UNION:
{
int nunit = 0;
for (int i=0; i < schema->nchildren; i++) {
simplify_schema(schema->children[i]);
if (schema->children[i]->tag == S_UNIT)
nunit += 1;
}
if (nunit == schema->nchildren) {
for (int i=0; i < schema->nchildren; i++) {
free_schema(schema->children[i]);
}
FREE(schema->children);
schema->tag = S_UNIT;
} else if (nunit == schema->nchildren - 1) {
struct schema tmp;
for (int i=0; i < schema->nchildren; i++) {
if (schema->children[i]->tag != S_UNIT) {
tmp = *schema->children[i];
free(schema->children[i]);
} else {
free_schema(schema->children[i]);
}
}
free(schema->children);
unref(schema->info, info);
*schema = tmp;
}
}
break;
case S_SUBTREE:
simplify_schema(schema->child);
break;
case S_STAR:
case S_MAYBE:
case S_SQUARE:
simplify_schema(schema->child);
if (schema->child->tag == S_UNIT) {
free_schema(schema->child);
schema->child = NULL;
schema->tag = S_UNIT;
}
break;
default:
BUG_ON(true, schema->info, "Unexpected schema type %d", schema->tag);
break;
}
error:
return;
}

struct schema *schema_from_lens(struct lens *lens) {
struct schema *result = NULL;

if (lens == NULL)
return NULL;

switch (lens->tag) {
case L_DEL:
case L_STORE:
case L_VALUE:
case L_KEY:
case L_LABEL:
case L_SEQ:
case L_COUNTER:
result = make_schema(S_UNIT, lens->info);
ERR_BAIL(lens->info);
break;
case L_SUBTREE:
result = make_schema(S_SUBTREE, lens->info);
ERR_BAIL(lens->info);
result->ktype = ref(lens->child->ktype);
result->vtype = ref(lens->child->vtype);
result->child = schema_from_lens(lens->child);
break;
case L_STAR:
result = make_schema(S_STAR, lens->info);
ERR_BAIL(lens->info);
result->child = schema_from_lens(lens->child);
break;
case L_MAYBE:
result = make_schema(S_MAYBE, lens->info);
ERR_BAIL(lens->info);
result->child = schema_from_lens(lens->child);
break;
case L_SQUARE:
result = make_schema(S_SQUARE, lens->info);
ERR_BAIL(lens->info);
result->child = schema_from_lens(lens->child);
break;
case L_CONCAT:
case L_UNION:
result = make_schema_concat_or_union(lens);
ERR_BAIL(lens->info);
break;
case L_REC:
result = make_schema(S_REC, lens->info);
ERR_BAIL(lens->info);
break;
default:
BUG_ON(true, lens->info, "Unexpected lens tag %d", lens->tag);
break;
}

return result;
error:
free_schema(result);
return NULL;
}

void free_schema(struct schema *schema) {
if (schema == NULL)
return;

switch(schema->tag) {
case S_REC:
case S_UNIT:
break;
case S_CONCAT:
case S_UNION:
for (int i=0; i < schema->nchildren; i++) {
free_schema(schema->children[i]);
}
free(schema->children);
break;
case S_SUBTREE:
unref(schema->ktype, regexp);
unref(schema->vtype, regexp);
free_schema(schema->child);
break;
case S_STAR:
case S_MAYBE:
case S_SQUARE:
free_schema(schema->child);
break;
default:
BUG_ON(true, schema->info, "Unexpected schema type %d", schema->tag);
break;
}
unref(schema->info, info);
free(schema);
error:
return;
}

static void print_indent(FILE *out, int indent) {
for (int i=0; i < indent; i++)
fputc(' ', out);
}

static void dump(FILE *out, struct schema *schema, int indent) {
if (schema == NULL) {
print_indent(out, indent);
fprintf(out, "<<NULL>>\n");
return;
}

switch(schema->tag) {
case S_REC:
print_indent(out, indent);
fprintf(out, "<<REC>>\n");
case S_UNIT:
print_indent(out, indent);
fprintf(out, "()\n");
break;
case S_CONCAT:
case S_UNION:
print_indent(out, indent);
if (schema->tag == S_CONCAT) {
fprintf(out, ".\n");
} else {
fprintf(out, "|\n");
}
for (int i=0; i < schema->nchildren; i++) {
dump(out, schema->children[i], indent+2);
}
break;
case S_SUBTREE:
{
bool unit = schema->child->tag == S_UNIT;
print_indent(out, indent);
fprintf(out, unit ? "{ " : "[ ");
print_regexp(out, schema->ktype);
fprintf(out, " = ");
print_regexp(out, schema->vtype);
fprintf(out, unit ? " }\n" : " ]\n");
if (! unit)
dump(out, schema->child, indent+2);
}
break;
case S_STAR:
case S_MAYBE:
case S_SQUARE:
print_indent(out, indent);
if (schema->tag == S_STAR) {
fputc('*', out);
} else if (schema->tag == S_MAYBE) {
fputc('?', out);
} else {
fputc('#', out);
}
fputc('\n', out);
dump(out, schema->child, indent+2);
break;
default:
BUG_ON(true, schema->info, "Unexpected schema type %d", schema->tag);
break;
}
error:
return;
}

void dump_schema(FILE *out, struct schema *schema) {
dump(out, schema, 0);
}
74 changes: 74 additions & 0 deletions src/schema.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* schema.h: support for generating a tree schema from a lens
*
* Copyright (C) 2016 David Lutterkort
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: David Lutterkort <lutter@watzmann.net>
*/

#ifndef SCHEMA_H_
#define SCHEMA_H_

#include "stdio.h"

#include "config.h"
#include "lens.h"

/* What we are trying to represent in OCaml notation:
type schema = Concat schema * schema
| Union schema * schema
| Subtree rx * rx * schema
| Square schema
| Star schema
| Maybe schema
| Rec
| Unit
*/

enum schema_tag {
S_UNIT,
S_CONCAT,
S_UNION,
S_SUBTREE,
S_STAR,
S_MAYBE,
S_SQUARE,
S_REC
};

struct schema {
enum schema_tag tag;
struct info *info;
union {
struct { /* L_CONCAT, L_UNION */
unsigned int nchildren;
struct schema **children;
};
struct { /* L_SUBTREE */
struct regexp *ktype;
struct regexp *vtype;
struct schema *child; /* L_STAR, L_MAYBE, L_SQUARE */
};
};
};

struct schema *schema_from_lens(struct lens *lens);
void simplify_schema(struct schema *);
void dump_schema(FILE *out, struct schema *);
void free_schema(struct schema *);
#endif