modules/ob/objects.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. OB_get_inv_attr_mask
  2. OB_get_object_mask
  3. OB_object_to_string1
  4. attr_order
  5. OB_object_to_string2
  6. OB_objects_to_string
  7. OB_object_i_to_string
  8. attr2obj_index
  9. OB_attribute_i_to_string
  10. OB_init

/***************************************
  $Revision: 1.7 $

  Objects module (ob) - this _should_ eventually get merged in with the
  config module.

  Status: NOT REVUED, NOT TESTED

  ******************/ /******************
  Filename            : objects.c
  Author              : ottrey@ripe.net
  OSs Tested          : Solaris
  Related Modules     : Used in conjunction with the attributes module.
  Problems            : Consistency between arrays and enums.
  To Do               : Total re-design.
  Comments            :
  ******************/ /******************
  Copyright (c) 1999                              RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  ***************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <strings.h>

#include "bitmask.h"
#include "objects.h"
#include "attributes.h"

#define MAX_OBJECTS 60

/*+ String sizes +*/
#define STR_S   63
#define STR_M   255
#define STR_L   1023
#define STR_XL  4095
#define STR_XXL 16383

/* Global Variable */
/*+ Indicates that the objects have been initialized +*/
int    Initialized=0;
/*+ The objects +*/
struct Object_t Objects[MAX_OBJECTS];
/*+ The attributes that can be inverse attributes +*/
mask_t Inv_attr_mask;
/*+ The attributes that can be objects. +*/
mask_t Object_mask;

mask_t OB_get_inv_attr_mask(void) {
/* [<][>][^][v][top][bottom][index][help] */
  return Inv_attr_mask;
} /* OB_get_inv_attr_mask() */

mask_t OB_get_object_mask(void) {
/* [<][>][^][v][top][bottom][index][help] */
  return Object_mask;
} /* OB_get_object_mask */

char *OB_object_to_string1(Object object) {
/* [<][>][^][v][top][bottom][index][help] */
  char *result;
  int   result_len;
  char *ATSQ_str;
  char *MAND_str;
  char *MULT_str;
  char *UNIQ_str;
  char *KEYS_str;
  char *REC_str;
  char *INV_str;

  /* Add 10 for the extra bits of text & good luck ;-) */
  result_len = 10;
  ATSQ_str = MA_to_string(object.ATSQ, AT_get_attributes(), 2, 1 );
  result_len += (strlen(ATSQ_str) + 10);
  MAND_str = MA_to_string(object.MAND, AT_get_attributes(), 2, 1 );
  result_len += (strlen(MAND_str) + 10);
  MULT_str = MA_to_string(object.MULT, AT_get_attributes(), 2, 1 );
  result_len += (strlen(MULT_str) + 10);
  UNIQ_str = MA_to_string(object.UNIQ, AT_get_attributes(), 2, 1 );
  result_len += (strlen(UNIQ_str) + 10);
  KEYS_str = MA_to_string(object.KEYS, AT_get_attributes(), 2, 1 );
  result_len += (strlen(KEYS_str) + 10);
  REC_str  = MA_to_string(object.REC , AT_get_attributes(), 2, 1 );
  result_len += (strlen(REC_str)  + 10);
  INV_str  = MA_to_string(object.INV , AT_get_attributes(), 2, 1 );
  result_len += (strlen(INV_str)  + 10);


  result = (char *)calloc(1, result_len+1);
  strcpy(result, "{\n\tATSQ=");
  strcat(result, ATSQ_str); strcat(result, ",\n\tMAND=");
  strcat(result, MAND_str); strcat(result, ",\n\tMULT=");
  strcat(result, MULT_str); strcat(result, ",\n\tUNIQ=");
  strcat(result, UNIQ_str); strcat(result, ",\n\tKEYS=");
  strcat(result, KEYS_str); strcat(result, ",\n\tREC =");
  strcat(result, REC_str);  strcat(result, ",\n\tINV =");
  strcat(result, INV_str);
  strcat(result, "\n}");

  return result;

} /* OB_object_to_string1() */

static void attr_order(int *ao, int n, ...) {
/* [<][>][^][v][top][bottom][index][help] */
  va_list ap;
  int i;

  memset(ao, -1, sizeof(int)*100);

  for (i=0, va_start(ap, n); n != MA_END; n = va_arg(ap, int), i++ ) {
    ao[i] = n;
  }
  va_end(ap);

} /* attr_order() */

/* Backward compatible version. */
char *OB_object_to_string2(Object object, int verbose) {
/* [<][>][^][v][top][bottom][index][help] */
  char *result;
  char result_buf[STR_XXL];
  char result_buf_verbose[STR_XXL];
  char attr_buf[STR_L];
  char attr_buf_verbose[STR_XL];
  int i;
  int attix;

  int offset;
  
  int mand;
  int mult;
  int uniq;
  int keys;
  int inv;

  offset=1;

  strcpy(result_buf, "");
  strcpy(result_buf_verbose, "");
  /* This is in alphabetical order */
  /*
  for (i=0; AT_get_attribute(i, offset) != NULL; i++) {
    if (MA_isset(object.ATSQ, i) == 1) {
      mand = MA_isset(object.MAND, i);
      mult = MA_isset(object.MULT, i);
      uniq = MA_isset(object.UNIQ, i);
      keys = MA_isset(object.KEYS, i);
      inv  = MA_isset(object.INV , i);
      sprintf(attr_buf, "%s:   \t[%s]\t[%s]\t[%s%s%s %s]\n",
        AT_get_attribute(i, offset),
        mand ? "mandatory"   : "optional",
        mult ? "multiple"    : "single",
        uniq ? "primary/"    : "",
        keys ? "look-up" : "",
        inv  ? "inverse" : "",
        (uniq | keys | inv) ? "key" : ""
      );
      strcat(result_buf, attr_buf);
    }
  }
  */
  if (verbose == 1) {
    strcat(result_buf, "\n\n% Rights restricted by copyright. See http://www.ripe.net/db/dbcopyright.html\n\n");
    sprintf(attr_buf_verbose, "\nThe %s object:\n\n%s\n\n\n", AT_get_attribute(object.attr_index, 1), object.description);
    strcat(result_buf, attr_buf_verbose);
  }

  /* This is in the defined order. */
  for (i=0; (attix = object.attr_order[i]) != -1; i++) {
    if ( attix >= 0 ) {
      mand = MA_isset(object.MAND, attix);
      mult = MA_isset(object.MULT, attix);
      uniq = MA_isset(object.UNIQ, attix);
      keys = MA_isset(object.KEYS, attix);
      inv  = MA_isset(object.INV , attix);
      sprintf(attr_buf, "%s:   \t[%s]\t[%s]\t[%s%s%s %s]\n",
        AT_get_attribute(attix, offset),
        mand ? "mandatory"   : "optional",
        mult ? "multiple"    : "single",
        uniq ? "primary/"    : "",
        keys ? "look-up" : "",
        inv  ? "inverse" : "",
        (uniq | keys | inv) ? "key" : ""
      );
      strcat(result_buf, attr_buf);
      if (verbose == 1) {
        sprintf(attr_buf_verbose, "%s\n\t%s\n\n\t%s\n\n", AT_get_attribute(attix, offset), AT_get_attribute_desc(attix), AT_get_attribute_frmt(attix) ); 
        strcat(result_buf_verbose, attr_buf_verbose);
      }
    }
  }
  if (verbose == 1) {
    sprintf(attr_buf_verbose, "\nThe content of the attributes of the %s object are defined below:\n\n", AT_get_attribute(object.attr_index, 1) );
    strcat(result_buf, attr_buf_verbose);
    strcat(result_buf, result_buf_verbose);
  }

  result = (char *)calloc(1, strlen(result_buf)+1);
  strcpy(result, result_buf);

  return result;

} /* OB_object_to_string2() */

char *OB_objects_to_string() {
/* [<][>][^][v][top][bottom][index][help] */
  char *str;
  char str_buffer[160000];
  char *str1;
  int i;
  int attix;

  strcpy(str_buffer, "");
  for (i=0; Objects[i].attr_index != -1; i++) {
    attix = Objects[i].attr_index; 
    str1 = OB_object_to_string2(Objects[i], 1);
    strcat(str_buffer, AT_get_attribute(attix, 1));
    strcat(str_buffer, "=\n");
    strcat(str_buffer, str1);
    strcat(str_buffer, "\n");
    free(str1);
  }

  str = (char *)calloc(1, strlen(str_buffer)+1);
  strcpy(str, str_buffer);
  
  return str;

} /* OB_objects_to_string() */
  
char *OB_object_i_to_string(int obj_index, int format) {
/* [<][>][^][v][top][bottom][index][help] */
  return OB_object_to_string2(Objects[obj_index], format);
} /* OB_object_i_to_string() */

/* XXX This is really really really crap.  I want to re-design the whole thing.  - ottrey. */
/* Everytime the order changes or a new object is added, this needs to be changed aswell.  Aaargh. */
static int attr2obj_index(int attr_index) {
/* [<][>][^][v][top][bottom][index][help] */
  int result=-1;

  switch (attr_index) {
  case A_AN:
    result = O_AN;
  break;

  case A_AS:
    result = O_AS;
  break;

  case A_DC:
    result = O_DC;
  break;

  case A_DN:
    result = O_DN;
  break;

  case A_FS:
    result = O_FS;
  break;

  case A_KC:
    result = O_KC;
  break;

  case A_I6:
    result = O_I6;
  break;

  case A_IN:
    result = O_IN;
  break;

  case A_IR:
    result = O_IR;
  break;

  case A_IS:
    result = O_IS;
  break;

  case A_LI:
    result = O_LI;
  break;

  case A_MT:
    result = O_MT;
  break;

  case A_PN:
    result = O_PN;
  break;

  case A_PS:
    result = O_PS;
  break;

  case A_RO:
    result = O_RO;
  break;

  case A_RS:
    result = O_RS;
  break;

  case A_RT:
    result = O_RT;
  break;

  default:
    printf("Error in Object attribute not an object... - geez even this sounds stupid.\n");
  }

  return result;

} /* attr2obj_index() */
  
char *OB_attribute_i_to_string(int attr_index, int format) {
/* [<][>][^][v][top][bottom][index][help] */
  int obj_index=-1;
  char *str=NULL;

  obj_index = attr2obj_index(attr_index);

  if (obj_index != -1) {
    str = OB_object_to_string2(Objects[obj_index], format);
  }

  return str;

} /* OB_attribute_i_to_string() */

/* OB_init() */
/*++++++++++++++++++++++++++++++++++++++
  Initialize the objects.  This could do with some re-designing.

  More:
  +html+ <PRE>
  Authors:
        ottrey

  +html+ </PRE><DL COMPACT>
  +html+ <DT>Online References:
  +html+ <DD><UL>
  +html+ </UL></DL>

  ++++++++++++++++++++++++++++++++++++++*/
void OB_init(void) {
/* [<][>][^][v][top][bottom][index][help] */
  int i=0;

  if (Initialized == 0) {
    /*
     * aut_nums
     */
    Objects[i].attr_index = A_AN;
    Objects[i].description = "The aut-num object describes the details of the\nregistered owner of an Autonomous System and their\nrouting policy for that AS. See ripe-181 and\nRFC-BGP4 for details.\n";
    attr_order(Objects[i].attr_order, O_AN_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_AN_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_AN_MAND, MA_END);
    Objects[i].MULT = MA_new(O_AN_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_AN_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_AN_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_AN_REC , MA_END);
    Objects[i].INV  = MA_new(O_AN_INV , MA_END);
    i++;

    /*
     * as_set
     */
    Objects[i].attr_index = A_AS;
    Objects[i].description = "The aut-num object describes the details of the\nregistered owner of an Autonomous System and their\nrouting policy for that AS. See ripe-181 and\nRFC-BGP4 for details.\n";
    attr_order(Objects[i].attr_order, O_AS_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_AS_ATSQ);
    Objects[i].MAND = MA_new(O_AS_MAND);
    Objects[i].MULT = MA_new(O_AS_MULT);
    Objects[i].UNIQ = MA_new(O_AS_UNIQ);
    Objects[i].KEYS = MA_new(O_AS_KEYS);
    Objects[i].REC  = MA_new(O_AS_REC );
    Objects[i].INV  = MA_new(O_AS_INV );
    i++;

    /*
     * dictionary
     */
    Objects[i].attr_index = A_DC;
    Objects[i].description = "INSERT dictionary DESCRIPTION HERE";
    attr_order(Objects[i].attr_order, O_DC_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_DC_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_DC_MAND, MA_END);
    Objects[i].MULT = MA_new(O_DC_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_DC_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_DC_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_DC_REC , MA_END);
    Objects[i].INV  = MA_new(O_DC_INV , MA_END);
    i++;

    /*
     * domains
     */
    Objects[i].attr_index = A_DN;
    Objects[i].description = "The role object represents a \"help desk\", a network\noperations centre or a contact point for help or\ninformation on network operations.\n";
    attr_order(Objects[i].attr_order, O_DN_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_DN_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_DN_MAND, MA_END);
    Objects[i].MULT = MA_new(O_DN_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_DN_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_DN_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_DN_REC , MA_END);
    Objects[i].INV  = MA_new(O_DN_INV , MA_END);
    i++;

    /*
     * filter_set
     */
    Objects[i].attr_index = A_FS;
    Objects[i].description = "INSERT filter_set DESCRIPTION HERE";
    attr_order(Objects[i].attr_order, O_FS_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_FS_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_FS_MAND, MA_END);
    Objects[i].MULT = MA_new(O_FS_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_FS_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_FS_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_FS_REC , MA_END);
    Objects[i].INV  = MA_new(O_FS_INV , MA_END);
    i++;

    /*
     * key_cert
     */
    Objects[i].attr_index = A_KC;
    Objects[i].description = "INSERT key_cert DESCRIPTION HERE";
    attr_order(Objects[i].attr_order, O_KC_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_KC_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_KC_MAND, MA_END);
    Objects[i].MULT = MA_new(O_KC_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_KC_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_KC_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_KC_REC , MA_END);
    Objects[i].INV  = MA_new(O_KC_INV , MA_END);
    i++;

    /*
     * inet6num (experimental IPv6 allocation/assignment object)
     * XXX NB Carefully check anything to do with IP6 - my vim macros don't like a number in the name. XXX - ottrey.
   */
    Objects[i].attr_index = A_I6;
    Objects[i].description = "An experimental object for IP Version 6 addresses.";
    attr_order(Objects[i].attr_order, O_I6_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_I6_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_I6_MAND, MA_END);
    Objects[i].MULT = MA_new(O_I6_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_I6_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_I6_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_I6_REC , MA_END);
    Objects[i].INV  = MA_new(O_I6_INV , MA_END);
    i++;

    /*
     * inetnum
     */
    Objects[i].attr_index = A_IN;
    Objects[i].description = "An inetnum object contains information on allocations\nand assignments of IP address space. See ripe-142 for\ninformation on requesting IP address space.\n";
    attr_order(Objects[i].attr_order, O_IN_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_IN_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_IN_MAND, MA_END);
    Objects[i].MULT = MA_new(O_IN_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_IN_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_IN_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_IN_REC , MA_END);
    Objects[i].INV  = MA_new(O_IN_INV , MA_END);
    i++;

    /*
     * inet_rtr
     */
    Objects[i].attr_index = A_IR;
    Objects[i].description = "The inet-rtr object represents an internet router\nwithin a routing registry. See ripe-122 for details.\n";
    attr_order(Objects[i].attr_order, O_IR_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_IR_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_IR_MAND, MA_END);
    Objects[i].MULT = MA_new(O_IR_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_IR_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_IR_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_IR_REC , MA_END);
    Objects[i].INV  = MA_new(O_IR_INV , MA_END);
    i++;

    /*
     * rtr_set
     */
    Objects[i].attr_index = A_IS;
    Objects[i].description = "INSERT dictionary DESCRIPTION HERE";
    attr_order(Objects[i].attr_order, O_IS_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_IS_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_IS_MAND, MA_END);
    Objects[i].MULT = MA_new(O_IS_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_IS_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_IS_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_IS_REC , MA_END);
    Objects[i].INV  = MA_new(O_IS_INV , MA_END);
    i++;

    /*
     * limerick - RIPE special ;-)
     */
    Objects[i].attr_index = A_LI;
    Objects[i].description = "The limerick object represents a humourous poem which\nhas five lines and the rhyme scheme \"aabba\".\n";
    attr_order(Objects[i].attr_order, O_LI_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_LI_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_LI_MAND, MA_END);
    Objects[i].MULT = MA_new(O_LI_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_LI_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_LI_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_LI_REC , MA_END);
    Objects[i].INV  = MA_new(O_LI_INV , MA_END);
    i++;

    /*
     * maintainer
     */
    Objects[i].attr_index = A_MT;
    Objects[i].description = "The mntner object contains details of who is authorised\nto make changes to RIPE Database objects and details of\na process that actually verifies that the person who\nmakes the changes is authorised to do so.\nMntner objects are not created automatically, but are\nforwarded to RIPE NCC staff.\n";
    attr_order(Objects[i].attr_order, O_MT_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_MT_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_MT_MAND, MA_END);
    Objects[i].MULT = MA_new(O_MT_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_MT_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_MT_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_MT_REC , MA_END);
    Objects[i].INV  = MA_new(O_MT_INV , MA_END);
    i++;

    /*
     * person
     */
    Objects[i].attr_index = A_PN;
    Objects[i].description = "The person object contains information on how to\ncontact those people who are responsible for\nnetwork operations or RIPE Database objects.\n";
    attr_order(Objects[i].attr_order, O_PN_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_PN_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_PN_MAND, MA_END);
    Objects[i].MULT = MA_new(O_PN_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_PN_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_PN_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_PN_REC , MA_END);
    Objects[i].INV  = MA_new(O_PN_INV , MA_END);
    i++;

    /*
     * peering_set
     */
    Objects[i].attr_index = A_PS;
    Objects[i].description = "INSERT dictionary DESCRIPTION HERE";
    attr_order(Objects[i].attr_order, O_PS_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_PS_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_PS_MAND, MA_END);
    Objects[i].MULT = MA_new(O_PS_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_PS_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_PS_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_PS_REC , MA_END);
    Objects[i].INV  = MA_new(O_PS_INV , MA_END);
    i++;

    /*
     * role
     */
    Objects[i].attr_index = A_RO;
    Objects[i].description = "The role object represents a \"help desk\", a network\noperations centre or a contact point for help or\ninformation on network operations.\n";
    attr_order(Objects[i].attr_order, O_RO_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_RO_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_RO_MAND, MA_END);
    Objects[i].MULT = MA_new(O_RO_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_RO_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_RO_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_RO_REC , MA_END);
    Objects[i].INV  = MA_new(O_RO_INV , MA_END);
    i++;

    /*
     * route_set
     */
    Objects[i].attr_index = A_RS;
    Objects[i].description = "INSERT dictionary DESCRIPTION HERE";
    attr_order(Objects[i].attr_order, O_RS_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_RS_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_RS_MAND, MA_END);
    Objects[i].MULT = MA_new(O_RS_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_RS_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_RS_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_RS_REC , MA_END);
    Objects[i].INV  = MA_new(O_RS_INV , MA_END);
    i++;

    /*
     * route
     */
    Objects[i].attr_index = A_RT;
    Objects[i].description = "The route object represents a single route injected into\nthe Internet routing mesh.\n";
    attr_order(Objects[i].attr_order, O_RT_ATSQ, MA_END);
    Objects[i].ATSQ = MA_new(O_RT_ATSQ, MA_END);
    Objects[i].MAND = MA_new(O_RT_MAND, MA_END);
    Objects[i].MULT = MA_new(O_RT_MULT, MA_END);
    Objects[i].UNIQ = MA_new(O_RT_UNIQ, MA_END);
    Objects[i].KEYS = MA_new(O_RT_KEYS, MA_END);
    Objects[i].REC  = MA_new(O_RT_REC , MA_END);
    Objects[i].INV  = MA_new(O_RT_INV , MA_END);
    i++;

    Objects[i].attr_index = -1;

    /* Create the masks : Method 2 - using the object creations. */
    Object_mask   = MA_new(MA_END);
    Inv_attr_mask = MA_new(MA_END);
    for (i=0; Objects[i].attr_index != -1; i++) {
      MA_set(&Object_mask,  Objects[i].attr_index, 1);
      Inv_attr_mask = MA_or(Inv_attr_mask, Objects[i].INV);
    }

    Initialized = 1;
  } /* if () */
  else {
    printf("Warning: Call to OB_init() ignored - the objects have already been initialized.\n");
  }

} /* OB_init() */

/* [<][>][^][v][top][bottom][index][help] */