blob: ab0a0f1338041643fdd7eb6d984cfd6fed2b3100 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
#include "libxfs.h"
#include "type.h"
#include "faddr.h"
#include "fprint.h"
#include "field.h"
#include "flist.h"
#include "debug.h"
#include "output.h"
#include "malloc.h"
static void flist_expand_arrays(flist_t *fl);
static void flist_expand_structs(flist_t *fl, void *obj);
static flist_t *flist_replicate(flist_t *fl);
static ftok_t *flist_split(char *s);
static void ftok_free(ftok_t *ft);
static void
flist_expand_arrays(
flist_t *fl)
{
const field_t *f;
#ifdef DEBUG
const ftattr_t *fa;
#endif
int high;
int idx;
int low;
flist_t *new;
flist_t *prev;
flist_t *sib;
f = fl->fld;
#ifdef DEBUG
fa = &ftattrtab[f->ftyp];
#endif
ASSERT(fa->ftyp == f->ftyp);
ASSERT(f->flags & FLD_ARRAY);
low = fl->low;
high = fl->high;
fl->high = fl->low;
sib = fl->sibling;
for (idx = low + 1, prev = fl; idx <= high; idx++) {
new = flist_make(f->name);
new->fld = f;
new->low = new->high = idx;
new->flags |= FL_OKLOW | FL_OKHIGH;
new->child = flist_replicate(fl->child);
prev->sibling = new;
prev = new;
}
prev->sibling = sib;
}
static void
flist_expand_structs(
flist_t *fl,
void *obj)
{
const field_t *cf;
const field_t *f;
const ftattr_t *fa;
flist_t *new;
flist_t *prev;
f = fl->fld;
fa = &ftattrtab[f->ftyp];
ASSERT(fa->ftyp == f->ftyp);
ASSERT(fa->subfld != NULL);
ASSERT(fl->child == NULL);
for (cf = fa->subfld, prev = NULL; cf->name != NULL; cf++) {
if (fcount(cf, obj, fl->offset) == 0)
continue;
if (cf->flags & FLD_SKIPALL)
continue;
new = flist_make(cf->name);
new->fld = cf;
if (prev)
prev->sibling = new;
else
fl->child = new;
prev = new;
}
}
void
flist_free(
flist_t *fl)
{
if (fl->child)
flist_free(fl->child);
if (fl->sibling)
flist_free(fl->sibling);
if (fl->name)
xfree(fl->name);
xfree(fl);
}
flist_t *
flist_make(
char *name)
{
flist_t *fl;
fl = xmalloc(sizeof(*fl));
fl->name = xstrdup(name);
fl->fld = NULL;
fl->child = NULL;
fl->sibling = NULL;
fl->low = 0;
fl->high = 0;
fl->flags = 0;
fl->offset = 0;
return fl;
}
int
flist_parse(
const field_t *fields,
flist_t *fl,
void *obj,
int startoff)
{
const field_t *f;
const ftattr_t *fa;
int high;
int low;
while (fl) {
f = findfield(fl->name, fields, obj, startoff);
if (f == NULL) {
dbprintf(_("field %s not found\n"), fl->name);
return 0;
}
fl->fld = f;
fa = &ftattrtab[f->ftyp];
ASSERT(fa->ftyp == f->ftyp);
if (f->flags & FLD_ARRAY) {
low = (f->flags & FLD_ABASE1) != 0;
high = fcount(f, obj, startoff) + low - 1;
if (low > high) {
dbprintf(_("no elements in %s\n"), fl->name);
return 0;
}
if (fl->flags & FL_OKHIGH) {
if (fl->low < low || fl->low > high ||
fl->high < low || fl->high > high) {
dbprintf(_("indices %d-%d for field %s "
"out of range %d-%d\n"),
fl->low, fl->high, fl->name,
low, high);
return 0;
}
} else if (fl->flags & FL_OKLOW) {
if (fl->low < low || fl->low > high) {
dbprintf(_("index %d for field %s out of "
"range %d-%d\n"),
fl->low, fl->name, low, high);
return 0;
}
fl->high = fl->low;
fl->flags |= FL_OKHIGH;
} else {
fl->low = low;
fl->high = high;
fl->flags |= FL_OKLOW | FL_OKHIGH;
}
} else {
if (fl->flags & FL_OKLOW) {
dbprintf(_("field %s is not an array\n"),
fl->name);
return 0;
}
}
fl->offset = startoff + bitoffset(f, obj, startoff, fl->low);
if ((fl->child != NULL || fa->prfunc == NULL) &&
(f->flags & FLD_ARRAY) && fl->low != fl->high)
flist_expand_arrays(fl);
if (fa->prfunc == NULL && fl->child == NULL)
flist_expand_structs(fl, obj);
if (fl->child) {
if (fa->subfld == NULL) {
dbprintf(_("field %s has no subfields\n"),
fl->name);
return 0;
}
if (!flist_parse(fa->subfld, fl->child, obj,
fl->offset))
return 0;
}
fl = fl->sibling;
}
return 1;
}
void
flist_print(
flist_t *fl)
{
if (!(debug_state & DEBUG_FLIST))
return;
while (fl) {
dbprintf(_("fl@%p:\n"), fl);
dbprintf(_("\tname=%s, fld=%p, child=%p, sibling=%p\n"),
fl->name, fl->fld, fl->child, fl->sibling);
dbprintf(_("\tlow=%d, high=%d, flags=%d (%s%s), offset=%d\n"),
fl->low, fl->high, fl->flags,
fl->flags & FL_OKLOW ? _("oklow ") : "",
fl->flags & FL_OKHIGH ? _("okhigh") : "", fl->offset);
dbprintf(_("\tfld->name=%s, fld->ftyp=%d (%s)\n"),
fl->fld->name, fl->fld->ftyp,
ftattrtab[fl->fld->ftyp].name);
dbprintf(_("\tfld->flags=%d (%s%s%s%s%s)\n"), fl->fld->flags,
fl->fld->flags & FLD_ABASE1 ? "abase1 " : "",
fl->fld->flags & FLD_SKIPALL ? "skipall " : "",
fl->fld->flags & FLD_ARRAY ? "array " : "",
fl->fld->flags & FLD_OFFSET ? "offset " : "",
fl->fld->flags & FLD_COUNT ? "count " : "");
if (fl->child)
flist_print(fl->child);
fl = fl->sibling;
}
}
static flist_t *
flist_replicate(
flist_t *f)
{
flist_t *new;
if (f == NULL)
return NULL;
new = flist_make(f->name);
new->fld = f->fld;
new->child = flist_replicate(f->child);
new->sibling = flist_replicate(f->sibling);
new->low = f->low;
new->high = f->high;
new->flags = f->flags;
new->offset = f->offset;
return new;
}
flist_t *
flist_scan(
char *name)
{
flist_t *fl;
flist_t *lfl;
flist_t *nfl;
int num;
ftok_t *p;
ftok_t *v;
char *x;
v = flist_split(name);
if (!v)
return NULL;
p = v;
fl = lfl = NULL;
while (p->tokty != TT_END) {
if (p->tokty != TT_NAME)
goto bad;
nfl = flist_make(p->tok);
if (lfl)
lfl->child = nfl;
else
fl = nfl;
lfl = nfl;
p++;
if (p->tokty == TT_LB) {
p++;
if (p->tokty != TT_NUM)
goto bad;
num = (int)strtoul(p->tok, &x, 0);
if (*x != '\0')
goto bad;
nfl->flags |= FL_OKLOW;
nfl->low = num;
p++;
if (p->tokty == TT_DASH) {
p++;
if (p->tokty != TT_NUM)
goto bad;
num = (int)strtoul(p->tok, &x, 0);
if (*x != '\0')
goto bad;
nfl->flags |= FL_OKHIGH;
nfl->high = num;
p++;
}
if (p->tokty != TT_RB)
goto bad;
p++;
}
if (p->tokty == TT_DOT) {
p++;
if (p->tokty == TT_END)
goto bad;
}
}
ftok_free(v);
return fl;
bad:
dbprintf(_("bad syntax in field name %s\n"), name);
ftok_free(v);
if (fl)
flist_free(fl);
return NULL;
}
static ftok_t *
flist_split(
char *s)
{
char *a;
int i;
static char *idchars;
static char *initidchar;
int l;
int tailskip = 0;
static char *numchars;
static char *xnumchars; /* extended for hex conversion */
int nv;
static char punctchars[] = "[-].";
static tokty_t puncttypes[] = { TT_LB, TT_DASH, TT_RB, TT_DOT };
tokty_t t;
ftok_t *v;
if (idchars == NULL) {
idchars = xmalloc(26 + 10 + 1 + 1);
initidchar = xmalloc(26 + 1);
numchars = xmalloc(10 + 1);
xnumchars = xmalloc(12 + 1);
for (i = 'a'; i <= 'z'; i++) {
idchars[i - 'a'] = i;
initidchar[i - 'a'] = i;
}
for (i = '0'; i <= '9'; i++) {
idchars[26 + (i - '0')] = i;
numchars[i - '0'] = i;
xnumchars[i - '0'] = i;
}
idchars[26 + 10] = '_';
idchars[26 + 10 + 1] = '\0';
initidchar[26] = '\0';
numchars[10] = '\0';
xnumchars[10] = 'x';
xnumchars[11] = 'X';
xnumchars[12] = '\0';
}
nv = 0;
v = xmalloc(sizeof(*v));
v->tok = NULL;
while (*s) {
/* need to add string handling */
if (*s == '\"') {
s++; /* skip first quote */
if ((a = strrchr(s, '\"')) == NULL) {
dbprintf(_("missing closing quote %s\n"), s);
ftok_free(v);
return NULL;
}
tailskip = 1; /* skip remaing quote */
l = (int)(a - s);
t = TT_STRING;
} else if (strchr(initidchar, *s)) {
l = (int)strspn(s, idchars);
t = TT_NAME;
} else if (strchr(numchars, *s)) {
l = (int)strspn(s, xnumchars);
t = TT_NUM;
} else if ((a = strchr(punctchars, *s))) {
l = 1;
t = puncttypes[a - punctchars];
} else {
dbprintf(_("bad character in field %s\n"), s);
ftok_free(v);
return NULL;
}
a = xmalloc(l + 1);
strncpy(a, s, l);
a[l] = '\0';
v = xrealloc(v, (nv + 2) * sizeof(*v));
v[nv + 1].tok = NULL;
v[nv].tok = a;
v[nv].tokty = t;
nv++;
s += l + tailskip;
tailskip = 0;
}
v[nv].tok = NULL;
v[nv].tokty = TT_END;
return v;
}
static flist_t *
flist_field_match(
const field_t *field,
fldt_t type,
void *obj,
int startoff)
{
flist_t *fl;
int count;
const ftattr_t *fa;
flist_t *nfl;
fl = flist_make(field->name);
fl->fld = field;
if (field->ftyp == type)
return fl;
count = fcount(field, obj, startoff);
if (!count)
goto out;
fa = &ftattrtab[field->ftyp];
if (!fa->subfld)
goto out;
nfl = flist_find_ftyp(fa->subfld, type, obj, startoff);
if (nfl) {
fl->child = nfl;
return fl;
}
out:
flist_free(fl);
return NULL;
}
/*
* Given a set of fields, scan for a field of the given type.
* Return an flist leading to the first found field
* of that type.
* Return NULL if no field of the given type is found.
*/
flist_t *
flist_find_ftyp(
const field_t *fields,
fldt_t type,
void *obj,
int startoff)
{
const field_t *f;
flist_t *fl;
for (f = fields; f->name; f++) {
fl = flist_field_match(f, type, obj, startoff);
if (fl)
return fl;
}
return NULL;
}
static void
ftok_free(
ftok_t *ft)
{
ftok_t *p;
for (p = ft; p->tok; p++)
xfree(p->tok);
xfree(ft);
}