Subversion Repositories tendra.SVN

Rev

Rev 2 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific, prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */
/*
                 Crown Copyright (c) 1997

    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-

        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;

        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;

        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;

        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


#include "config.h"
#include "object.h"
#include "hash.h"
#include "index.h"
#include "name.h"
#include "type.h"
#include "print.h"
#include "utility.h"


/*
    FLAGS

    These flags are used to indicate various output states indicated by
    preprocessing directives.  A value of 1 is the default (which
    actually means that the condition is false), 2 means that the given
    statement is true, and 0 means that its negation is true.
*/

static int building_libs = 1;
static int commented_out = 1;


/*
    FIELD SEPARATOR

    The field separator for the machine processable index.  This
    separator can be changed, but no command line option is provided to
    do this as '$' seems ideal.
*/

static char field_sep = '$';


/*
    PRINT FIELD SEPARATOR

    Routine to print field separator of the machine processable index.
*/

#define print_field_sep()       IGNORE putchar(field_sep)


/*
    PRINT FIELD

    Routine to print field and separator of the machine processable index.
*/

static void
print_field(char *s)
{
    IGNORE printf("%s%c", s, field_sep);
    return;
}


/*
    PRINT ESCAPED FIELD

    Routine to print field without separator of the machine processable
    index, escaping characters that could confuse output processing tools.
*/

static void
print_escape(char *s)
{
    int c;
    while ((c = *s++)!= '\0') {
        if (c == field_sep) {
            IGNORE printf("\\F");
        } else if (c == '\n') {
            IGNORE printf("\\n");
        } else if (c == '\\') {
            IGNORE printf("\\\\");
        } else {
            IGNORE putchar(c);
        }
    }
    return;
}


/*
    PRINT VALUE FIELD

    Routine to print the final value field of the machine processable index.
*/

static void
print_value(char *s)
{
    print_field_sep();
    print_escape(s);
    IGNORE putchar('\n');
    return;
}


/*
    PRINT EMPTY VALUE FIELD

    Routine to print the final empty value field of the machine processable
    index.
*/

static void
print_no_value(void)
{
    IGNORE printf("%c\n", field_sep);
    return;
}


/*
    PRINT SORT, INFO AND TYPE FIELDS

    Routine to print sort, info and type fields of the machine processable
    index.
*/

static void
print_sit_v(char *s, char *i, type *t, char *nm)
{
    IGNORE printf("%s%c%s%c", s, field_sep, i, field_sep);
    IGNORE print_type(stdout, t, nm, 0);
    return;
}


/*
    PRINT SORT AND TYPE FIELDS

    Routine to print sort, empty info, and type fields of the machine
    processable index.
*/

static void
print_st_v(char *s, type *t, char *nm)
{
    print_sit_v(s, "", t, nm);
    return;
}


/*
    PRINT SORT AND INFO FIELDS

    Routine to print sort, info, and empty type fields of the machine
    processable index.
*/

static void
print_si_v(char *s, char *i)
{
    IGNORE printf("%s%c%s%c", s, field_sep, i, field_sep);
    return;
}


/*
    PRINT SORT FIELD

    Routine to print sort, empty info, and empty type fields of the
    machine processable index.
*/

static void
print_s_v(char *s)
{
    IGNORE printf("%s%c%c", s, field_sep, field_sep);
    return;
}


/*
    PRINT SORT, INFO, TYPE AND EMPTY VALUE FIELDS

    Routine to print sort, info, type and empty value fields of the
    machine processable index.
*/

static void
print_sit(char *s, char *i, type *t, char *nm)
{
    print_sit_v(s, i, t, nm);
    print_no_value();
    return;
}


/*
    PRINT SORT, TYPE AND EMPTY VALUE FIELDS

    Routine to print sort, empty info, type and empty value fields of the
    machine processable index.
*/

static void
print_st(char *s, type *t, char *nm)
{
    print_st_v(s, t, nm);
    print_no_value();
    return;
}


/*
    PRINT SORT, INFO AND EMPTY VALUE FIELDS

    Routine to print sort, info, empty type and empty value fields of the
    machine processable index.
*/

static void
print_si(char *s, char *i)
{
    print_si_v(s, i);
    print_no_value();
    return;
}


/*
    PRINT SORT AND EMPTY VALUE FIELDS

    Routine to print sort, empty info, empty type and empty value fields
    of the machine processable index.
*/

static void
print_s(char *s)
{
    print_s_v(s);
    print_no_value();
    return;
}


/*
    IF STACK STATE

    This stack is used to keep track of the current +IF conditions.
*/

static object **if_stack = 0;
static int if_stack_sz = 0;
static int if_stack_index = 0;


/*
    STACK AN IF COMMAND OBJECT

    Routine to stack an object representing +IFxxx or +ELSE.
*/

static void
stack_if(object *p)
{
    if (if_stack_index == if_stack_sz) {
        if_stack_sz += 16;
        if_stack = realloc_nof(if_stack, object *, if_stack_sz);
    }
    if_stack [ if_stack_index ] = p;
    if_stack_index++;
    return;
}


/*
    UNSTACK AN IF COMMAND OBJECT

    Routine to unstack an object representing +IFxxx or +ELSE.
*/

static object *
unstack_if(void)
{
    return(if_stack [ --if_stack_index ]);
}


/*
    PRINT IF NESTING

    Routine to print the currently stacked +IFxxx and +ELSE nesting.
*/

static void
print_if_nest(void)
{
    int i;
    for (i = 0; i < if_stack_index; i++) {
        char code;
        object *p = if_stack [ i ];
        char *c = p->name;

        if (i > 0)print_escape(";");
        if (i + 1 < if_stack_index &&
          if_stack [ i + 1 ]->u.u_num == CMD_ELSE) {
            IGNORE printf("e");
            i++;
        }
        switch (p->u.u_num)EXHAUSTIVE {
            case CMD_IF: code = 'i'; break;
            case CMD_IFDEF: code = 'd'; break;
            case CMD_IFNDEF: code = 'n'; break;
        }
        IGNORE printf("%c", code);
        print_escape(":");
        print_escape(c);
    }
    return;
}


/*
    PRINT A MACHINE PROCESSABLE ITEM INDEX

    This routine prints the index item indicated by the token object p.
    u gives the token status, a the current file name, and e is used in
    enumeration items.  The output is in fields suitable for machine
    processing by tools such as 'awk'.
*/

static void
print_item_m(object *p, char *u, char *a, type *e)
{
    char *nm;
    char *ap;
    char *tnm = p->name;
    object *q = p->u.u_obj;

    if (q->objtype == OBJ_FIELD) {
        nm = q->u.u_field->fname;
    } else {
        nm = q->name;
    }

    /* Field 1: C_SYMBOL */
    print_field(nm);

    /* Field 2: TOKEN */
    print_field(tnm);

    /* Field 3: STATUS */
    IGNORE printf("%c%c", u [ 0 ], field_sep);

    /* Field 4: IF_NESTING */
    print_if_nest();
    print_field_sep();

    /* Field 5: API_LOCATION */
    for (ap = a; *ap && *ap != ':'; ap++)IGNORE putchar(*ap);
    print_field_sep();

    /* Field 6: FILE_LOCATION */
    if (*ap)ap++;
    for (; *ap && *ap != ':'; ap++)IGNORE putchar(*ap);
    print_field_sep();

    /* Field 7: LINE_LOCATION */
    IGNORE printf("%d%c", q->line_no, field_sep);

    /* Field 8: SUBSET_NESTING */
    if (*ap)IGNORE printf("%s", ap + 1);
    print_field_sep();

    /* Fields 9-12: SORT, INFO, TYPE, VALUE */
    switch (q->objtype) {

        case OBJ_CONST: {
            print_st("const", q->u.u_type, null_str);
            break;
        }

        case OBJ_ENUMVAL: {
            print_field("enum_member");
            print_type(stdout, e, null_str, 0);
            print_field_sep();
            if (q->u.u_str) {
                print_value(q->u.u_str);
            } else {
                print_no_value();
            }
            break;
        }

        case OBJ_EXP: {
            type *t = q->u.u_type;
            char *s = (t->id == TYPE_LVALUE ? "lvalue" : "rvalue");
            print_st(s, t, null_str);
            break;
        }

        case OBJ_EXTERN: {
            type *t = q->u.u_type;
            if (t->id == TYPE_LVALUE)t = t->u.subtype;
            if (t->id == TYPE_PROC) {
                print_sit("func", "extern", t, nm);
            } else {
                print_st("extern", t, null_str);
            }
            break;
        }

        case OBJ_WEAK: {
            type *t = q->u.u_type;
            print_sit("func", "weak", t, nm);
            break;
        }

        case OBJ_DEFINE: {
            char *s = q->u.u_str;
            if (*s == '(') {
                print_field("define");
                print_field("param");
                for (; *s && *s != ')'; s++) {
                    IGNORE putchar(*s);
                }
                if (*s == ')')s++;
                IGNORE printf(")");
            } else {
                print_s_v("define");
            }
            while (*s == ' ')s++;
            print_value(s);
            break;
        }

        case OBJ_DEFMIN: {
            char *s = q->u.u_str;
            if (*s == '(') {
                print_field("defmin");
                print_field("param");
                for (; *s && *s != ')'; s++) {
                    IGNORE putchar(*s);
                }
                if (*s == ')')s++;
                IGNORE printf(")");
            } else {
                print_s_v("defmin");
            }
            while (*s == ' ')s++;
            print_value(s);
            break;
        }

        case OBJ_FIELD: {
            field *f = q->u.u_field;
            print_field("member");
            print_type(stdout, f->stype, null_str, 0);
            print_field_sep();
            print_type(stdout, f->ftype, null_str, 0);
            print_no_value();
            break;
        }

        case OBJ_FUNC: {
            print_st("func", q->u.u_type, nm);
            break;
        }

        case OBJ_MACRO: {
            print_st("macro", q->u.u_type, nm);
            break;
        }

        case OBJ_NAT: {
            print_s("nat");
            break;
        }

        case OBJ_STATEMENT: {
            type *t = q->u.u_type;
            if (t) {
                print_sit("statement", "param", t, null_str);
            } else {
                print_s("statement");
            }
            break;
        }

        case OBJ_TOKEN: {
            print_s_v("token");
            print_value(q->u.u_str);
            break;
        }

        case OBJ_TYPE: {
            type *t = q->u.u_type;
            int i = t->id;
            switch (i) {

                case TYPE_DEFINED: {
                    print_st("typedef", t->v.next, null_str);
                    break;
                }

                case TYPE_GENERIC: {
                    print_s("opaque");
                    break;
                }

                case TYPE_INT: {
                    print_s("integral");
                    break;
                }

                case TYPE_SIGNED: {
                    print_s("signed_integral");
                    break;
                }

                case TYPE_UNSIGNED: {
                    print_s("unsigned_integral");
                    break;
                }

                case TYPE_PROMOTE: {
                    print_field("promotion");
                    print_type(stdout, t->v.next, null_str, 0);
                    print_field_sep();
                    print_no_value();
                    break;
                }

                case TYPE_FLOAT: {
                    print_s("floating");
                    break;
                }

                case TYPE_ARITH: {
                    print_s("arithmetic");
                    break;
                }

                case TYPE_SCALAR: {
                    print_s("scalar");
                    break;
                }

                case TYPE_STRUCT:
                case TYPE_STRUCT_TAG:
                case TYPE_UNION:
                case TYPE_UNION_TAG:
                case TYPE_ENUM:
                case TYPE_ENUM_TAG: {
                    char *s;
                    type *en = null;
                    object *r = t->v.obj2;
                    char *inf = (r ? "exact" : "");
                    switch (i)EXHAUSTIVE {
                        case TYPE_STRUCT: s = "struct"; break;
                        case TYPE_STRUCT_TAG: s = "struct_tag"; break;
                        case TYPE_UNION: s = "union"; break;
                        case TYPE_UNION_TAG: s = "union_tag"; break;
                        case TYPE_ENUM: s = "enum"; en = t; break;
                        case TYPE_ENUM_TAG: s = "enum_tag"; en = t; break;
                    }
                    print_si(s, inf);
                    while (r) {
                        print_item_m(r, u, a, en);
                        r = r->next;
                    }
                    break;
                }

                default : {
                    error(ERR_INTERNAL, "Unknown type identifier, '%d'", i);
                    break;
                }
            }
            break;
        }

        default : {
            error(ERR_INTERNAL, "Unknown object type, '%d'", q->objtype);
            break;
        }
    }
    return;
}


/*
    PRINT AN INDEX ITEM

    This routine prints the index item indicated by the token object p.
    u gives the token status, a the current file name, and e is used in
    enumeration items.  The output is in a humun readable format.
*/

static void
print_item_h(object *p, char *u, char *a, type *e)
{
    char *tnm = p->name;
    object *q = p->u.u_obj;
    char *nm = q->name;
    IGNORE printf("TOKEN: %s\n", tnm);
    IGNORE printf("STATUS: %s", u);
    if (building_libs == 0)IGNORE printf(" (not library building)");
    if (building_libs == 2)IGNORE printf(" (library building only)");
    IGNORE printf("\nDEFINED: %s, line %d\n", a, q->line_no);
    IGNORE printf("INFO: ");
    if (commented_out == 2)IGNORE printf("(commented out) ");

    switch (q->objtype) {

        case OBJ_CONST: {
            IGNORE printf("%s is a constant expression of type ", nm);
            print_type(stdout, q->u.u_type, null_str, 0);
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_ENUMVAL: {
            IGNORE printf("%s is a member of the enumeration type ", nm);
            print_type(stdout, e, null_str, 0);
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_EXP: {
            IGNORE printf("%s is an expression of type ", nm);
            print_type(stdout, q->u.u_type, null_str, 0);
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_EXTERN: {
            type *t = q->u.u_type;
            if (t->id == TYPE_LVALUE)t = t->u.subtype;
            IGNORE printf("%s is an external ", nm);
            if (t->id == TYPE_PROC) {
                IGNORE printf("function with prototype ");
                print_type(stdout, t, nm, 0);
            } else {
                IGNORE printf("expression with type ");
                print_type(stdout, t, null_str, 0);
            }
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_WEAK: {
            type *t = q->u.u_type;
            IGNORE printf("%s is an external ", nm);
            IGNORE printf("function with weak prototype ");
            print_type(stdout, t, nm, 0);
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_DEFINE: {
            char *s = q->u.u_str;
            IGNORE printf("%s is a macro ", nm);
            if (*s == '(') {
                IGNORE printf("with arguments ");
                for (; *s && *s != ')'; s++) {
                    IGNORE putchar(*s);
                }
                if (*s == ')')s++;
                IGNORE printf(") ");
            }
            while (*s == ' ')s++;
            IGNORE printf("defined to be %s\n\n", s);
            break;
        }

        case OBJ_DEFMIN: {
            char *s = q->u.u_str;
            IGNORE printf("%s is a macro ", nm);
            if (*s == '(') {
                IGNORE printf("with arguments ");
                for (; *s && *s != ')'; s++) {
                    IGNORE putchar(*s);
                }
                if (*s == ')')s++;
                IGNORE printf(") ");
            }
            while (*s == ' ')s++;
            IGNORE printf("defined to be minimum %s\n\n", s);
            break;
        }

        case OBJ_FIELD: {
            field *f = q->u.u_field;
            IGNORE printf("%s is a field selector of ", f->fname);
            print_type(stdout, f->stype, null_str, 0);
            IGNORE printf(" of type ");
            print_type(stdout, f->ftype, null_str, 0);
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_FUNC: {
            IGNORE printf("%s is a function with prototype ", nm);
            print_type(stdout, q->u.u_type, nm, 0);
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_MACRO: {
            IGNORE printf("%s is a macro with prototype ", nm);
            print_type(stdout, q->u.u_type, nm, 0);
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_NAT: {
            IGNORE printf("%s is a constant integer\n\n", nm);
            break;
        }

        case OBJ_STATEMENT: {
            type *t = q->u.u_type;
            IGNORE printf("%s is a statement", nm);
            if (t) {
                IGNORE printf(" with arguments");
                print_type(stdout, t, null_str, 0);
            }
            IGNORE printf("\n\n");
            break;
        }

        case OBJ_TOKEN: {
            IGNORE printf("%s is a complex token\n\n", nm);
            break;
        }

        case OBJ_TYPE: {
            type *t = q->u.u_type;
            int i = t->id;
            print_type(stdout, t, null_str, 0);
            switch (i) {

                case TYPE_DEFINED: {
                    IGNORE printf(" is a type defined to be ");
                    print_type(stdout, t->v.next, null_str, 0);
                    IGNORE printf("\n\n");
                    break;
                }

                case TYPE_GENERIC: {
                    IGNORE printf(" is a type\n\n");
                    break;
                }

                case TYPE_INT: {
                    IGNORE printf(" is an integral type\n\n");
                    break;
                }

                case TYPE_SIGNED: {
                    IGNORE printf(" is a signed integral type\n\n");
                    break;
                }

                case TYPE_UNSIGNED: {
                    IGNORE printf(" is an unsigned integral type\n\n");
                    break;
                }

                case TYPE_PROMOTE: {
                    IGNORE printf(" is the integral promotion of ");
                    print_type(stdout, t->v.next, null_str, 0);
                    IGNORE printf("\n\n");
                    break;
                }

                case TYPE_FLOAT: {
                    IGNORE printf(" is a floating type\n\n");
                    break;
                }

                case TYPE_ARITH: {
                    IGNORE printf(" is an arithmetic type\n\n");
                    break;
                }

                case TYPE_SCALAR: {
                    IGNORE printf(" is a scalar type\n\n");
                    break;
                }

                case TYPE_STRUCT:
                case TYPE_STRUCT_TAG:
                case TYPE_UNION:
                case TYPE_UNION_TAG: {
                    char *n;
                    object *r = t->v.obj2;
                    switch (i)EXHAUSTIVE {
                        case TYPE_STRUCT: n = "structure"; break;
                        case TYPE_STRUCT_TAG: n = "structure"; break;
                        case TYPE_UNION: n = "union"; break;
                        case TYPE_UNION_TAG: n = "union"; break;
                    }
                    if (r == null) {
                        IGNORE printf(" is an inexact %s type\n\n", n);
                    } else {
                        IGNORE printf(" is an exact %s type\n\n", n);
                        while (r) {
                            print_item_h(r, u, a,(type *)null);
                            r = r->next;
                        }
                    }
                    break;
                }

                case TYPE_ENUM:
                case TYPE_ENUM_TAG: {
                    object *r = t->v.obj2;
                    IGNORE printf(" is an enumeration type\n\n");
                    while (r) {
                        print_item_h(r, u, a, t);
                        r = r->next;
                    }
                    break;
                }

                default : {
                    IGNORE printf(" is a type\n\n");
                    error(ERR_INTERNAL, "Unknown type identifier, '%d'", i);
                    break;
                }
            }
            break;
        }

        default : {
            error(ERR_INTERNAL, "Unknown object type, '%d'", q->objtype);
            break;
        }
    }
    return;
}


/*
    PRINT INDEX USING PRINT ITEM FUNCTION

    This routine prints an index of the set object input using fn.
*/

typedef void (*index_func)(object *, char *, char *, type *);

static void
print_index_with(object *input, index_func fn)
{
    object *p = input->u.u_obj;
    info *i = p->u.u_info;
    char *a = p->name;
    char *u = (i->implemented ? "implemented" : "used");
    for (p = i->elements; p != null; p = p->next) {
        switch (p->objtype) {

            case OBJ_IF: {
                /* Deal with preprocessing directives */
                char *c = p->name;
                if (fn == print_item_m) {
                    switch (p->u.u_num) {
                        case CMD_IF:
                        case CMD_IFDEF:
                        case CMD_IFNDEF:
                        case CMD_ELSE: {
                            stack_if (p);
                            break;
                        }
                        case CMD_ENDIF: {
                            if (unstack_if () ->u.u_num == CMD_ELSE) {
                                IGNORE unstack_if ();
                            }
                            break;
                        }
                    }
                } else if (streq(c, BUILDING_MACRO)) {
                    /* Check for the building_libs macro */
                    switch (p->u.u_num) {
                        case CMD_IF:
                        case CMD_IFDEF: {
                            building_libs = 2;
                            break;
                        }
                        case CMD_IFNDEF: {
                            building_libs = 0;
                            break;
                        }
                        case CMD_ELSE: {
                            building_libs = 2 - building_libs;
                            break;
                        }
                        case CMD_ENDIF: {
                            building_libs = 1;
                            break;
                        }
                    }
                } else {
                    /* Check for integers */
                    int n = 0;
                    while (*c == '-')c++;
                    while (*c >= '0' && *c <= '9') {
                        n = 10 * n + (*c - '0');
                        c++;
                    }
                    if (*c == 0) {
                        switch (p->u.u_num) {
                            case CMD_IF: {
                                commented_out = (n ? 0 : 2);
                                break;
                            }
                            case CMD_ELSE: {
                                commented_out = 2 - commented_out;
                                break;
                            }
                            case CMD_ENDIF: {
                                commented_out = 1;
                                break;
                            }
                        }
                    }
                }
                break;
            }

            case OBJ_SET: {
                /* Deal with subsets */
                print_index_with(p, fn);
                break;
            }

            case OBJ_TOKEN: {
                /* Deal with tokens */
                if (i->implemented || !restrict_use) {
                   (*fn)(p, u, a,(type *)null);
                }
                break;
            }
        }
    }
    return;
}


/*
    PRINT MACHINE PROCESSABLE INDEX

    This routine prints an index intended for machine processing of the
    set object input.
*/

void
print_machine_index(object *input)
{
    print_index_with(input, print_item_m);
    return;
}


/*
    PRINT INDEX

    This routine prints an index intended for human readers of the set
    object input.
*/

void
print_index(object *input)
{
    print_index_with(input, print_item_h);
    return;
}