root/usr/src/lib/libeti/form/common/fieldtype.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*      Copyright (c) 1988 AT&T */
/*        All Rights Reserved   */


/*
 *      Copyright (c) 1997, by Sun Microsystems, Inc.
 *      All rights reserved.
 */

/*LINTLIBRARY*/

#include <sys/types.h>
#include <stdlib.h>
#include "utility.h"

typedef struct {
        char *leftarg;
        char *rightarg;
}
        LINK;

#define ArgL(n)         (((LINK *)(n))->leftarg)
#define ArgR(n)         (((LINK *)(n))->rightarg)

#define Ref(t)          ((t)->ref)
#define TypeL(t)        ((t)->left)
#define TypeR(t)        ((t)->right)
#define MakeA(t)        ((t)->makearg)
#define CopyA(t)        ((t)->copyarg)
#define FreeA(t)        ((t)->freearg)
#define Fcheck(t)       ((t)->fcheck)
#define Ccheck(t)       ((t)->ccheck)
#define Next(t)         ((t)->next)
#define Prev(t)         ((t)->prev)

        /*
         *  default fieldtype
         */

static FIELDTYPE default_fieldtype =
{
                        0,                      /* status       */
                        0,                      /* ref          */
                        (FIELDTYPE *) 0,        /* left         */
                        (FIELDTYPE *) 0,        /* right        */
                        (PTF_charP) 0,          /* makearg      */
                        (PTF_charP) 0,          /* copyarg      */
                        (PTF_void) 0,           /* freearg      */
                        (PTF_int) 0,            /* fcheck       */
                        (PTF_int) 0,            /* ccheck       */
                        (PTF_int) 0,            /* next         */
                        (PTF_int) 0,            /* prev         */
};

FIELDTYPE * _DEFAULT_FIELDTYPE  = &default_fieldtype;

/* new_fieldtype - field & character validation function */
FIELDTYPE *
new_fieldtype(PTF_int fcheck, PTF_int ccheck)
{
        FIELDTYPE *t = (FIELDTYPE *) 0;

        if ((fcheck || ccheck) && Alloc(t, FIELDTYPE)) {
                *t = *_DEFAULT_FIELDTYPE;

                Fcheck(t) = fcheck;
                Ccheck(t) = ccheck;
        }
        return (t);
}

FIELDTYPE *
link_fieldtype(FIELDTYPE *left, FIELDTYPE *right)
{
        FIELDTYPE *t = (FIELDTYPE *) 0;

        if ((left || right) && Alloc(t, FIELDTYPE)) {
                *t = *_DEFAULT_FIELDTYPE;

                Set(t, LINKED);

                if (Status(left, ARGS) || Status(right, ARGS))
                        Set(t, ARGS);

                if (Status(left, CHOICE) || Status(right, CHOICE))
                        Set(t, CHOICE);

                TypeL(t) = left;
                TypeR(t) = right;
                IncrType(left); /* increment reference count */
                IncrType(right);        /* increment reference count */
        }
        return (t);
}

int
free_fieldtype(FIELDTYPE *t)
{
        if (!t)
                return (E_BAD_ARGUMENT);

        if (Ref(t))
                return (E_CONNECTED);

        if (Status(t, LINKED)) {
                DecrType(TypeL(t));     /* decrement reference count */
                DecrType(TypeR(t));     /* decrement reference count */
        }
        Free(t);
        return (E_OK);
}

int
set_fieldtype_arg(FIELDTYPE *t, PTF_charP makearg,
        PTF_charP copyarg, PTF_void freearg)
{
        if (t && makearg && copyarg && freearg) {
                Set(t, ARGS);
                MakeA(t) = makearg;
                CopyA(t) = copyarg;
                FreeA(t) = freearg;
                return (E_OK);
        }
        return (E_BAD_ARGUMENT);
}

/* set_fieldtype_choice next & prev choice function */
int
set_fieldtype_choice(FIELDTYPE *t, PTF_int next, PTF_int prev)
{
        if (t && next && prev) {
                Set(t, CHOICE);
                Next(t) = next;
                Prev(t) = prev;
                return (E_OK);
        }
        return (E_BAD_ARGUMENT);
}

char *
_makearg(FIELDTYPE *t, va_list *ap, int *err)
{
/*
 * invoke make_arg function associated with field type t.
 * return pointer to argument information or null if none.
 * increment err if an error is encountered.
 */
        char *p = (char *)0;

        if (! t || ! Status(t, ARGS))
                return (p);

        if (Status(t, LINKED)) {
                LINK *n = (LINK *) 0;

                if (Alloc(n, LINK)) {
                        ArgL(n) = _makearg(TypeL(t), ap, err);
                        ArgR(n) = _makearg(TypeR(t), ap, err);
                        p = (char *)n;
                } else
                        ++(*err);               /* out of space */
        } else
                if (!(p = (*MakeA(t)) (ap)))
                        ++(*err);               /* make_arg had problem */
        return (p);
}

char *
_copyarg(FIELDTYPE *t, char *arg, int *err)
{
/*
 * invoke copy_arg function associated with field type t.
 * return pointer to argument information or null if none.
 * increment err if an error is encountered.
 */
        char *p = (char *)0;

        if (!t || !Status(t, ARGS))
                return (p);

        if (Status(t, LINKED)) {
                LINK *n = (LINK *) 0;

                if (Alloc(n, LINK)) {
                        ArgL(n) = _copyarg(TypeL(t), ArgL(arg), err);
                        ArgR(n) = _copyarg(TypeR(t), ArgR(arg), err);
                        p = (char *)n;
                } else
                        ++(*err);               /* out of space */
        } else
                if (!(p = (*CopyA(t)) (arg)))
                        ++(*err);               /* copy_arg had problem */
        return (p);
}

/* _freearg - invoke free_arg function associated with field type t.  */
void
_freearg(FIELDTYPE *t, char *arg)
{
        if (!t || !Status(t, ARGS))
                return;

        if (Status(t, LINKED)) {
                _freearg(TypeL(t), ArgL(arg));
                _freearg(TypeR(t), ArgR(arg));
                Free(arg);
        } else
                (*FreeA(t)) (arg);
}

/* _checkfield - invoke check_field function associated with field type t.  */
int
_checkfield(FIELDTYPE *t, FIELD *f, char *arg)
{
        if (!t)
                return (TRUE);

        if (Opt(f, O_NULLOK)) {
                char *v = Buf(f);

                while (*v && *v == ' ')
                        ++v;
                if (!*v)
                        return (TRUE);  /* empty field */
        }
        if (Status(t, LINKED))
                return  (_checkfield(TypeL(t), f, ArgL(arg)) ||
                    _checkfield(TypeR(t), f, ArgR(arg)));
        else
                if (Fcheck(t))
                        return ((*Fcheck(t)) (f, arg));
        return (TRUE);
}

/* _checkchar - invoke check_char function associated with field type t.  */
int
_checkchar(FIELDTYPE *t, int c, char *arg)
{
        if (!t)
                return (TRUE);

        if (Status(t, LINKED))
                return  (_checkchar(TypeL(t), c, ArgL(arg)) ||
                    _checkchar(TypeR(t), c, ArgR(arg)));
        else
                if (Ccheck(t))
                        return ((*Ccheck(t)) (c, arg));
        return (TRUE);
}

/* _nextchoice - invoke next_choice function associated with field type t.  */
int
_nextchoice(FIELDTYPE *t, FIELD *f, char *arg)
{
        if (!t || !Status(t, CHOICE))
                return (FALSE);

        if (Status(t, LINKED))
                return  (_nextchoice(TypeL(t), f, ArgL(arg)) ||
                    _nextchoice(TypeR(t), f, ArgR(arg)));
        else
                return ((*Next(t)) (f, arg));
}

/* _prevchoice - invoke prev_choice function associated with field type t. */
int
_prevchoice(FIELDTYPE *t, FIELD *f, char *arg)
{
        if (!t || !Status(t, CHOICE))
                return (FALSE);

        if (Status(t, LINKED))
                return  (_prevchoice(TypeL(t), f, ArgL(arg)) ||
                    _prevchoice(TypeR(t), f, ArgR(arg)));
        else
                return ((*Prev(t)) (f, arg));
}