/* * Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: demo-array.c,v 1.3 2005/12/26 04:45:09 ca Exp $") #if SM_LIBCONF_ALONE #include #include #include #include #include "sm-conf.h" #else /* SM_LIBCONF_ALONE */ #include "sm/string.h" #include "sm/sm-conf.h" #include "sm/net.h" #include "sm/io.h" #include "sm/sm-conf-prt.h" #include #endif /* SM_LIBCONF_ALONE */ /* DEMO-ARRAY.C -- demo of arrays and arrays of unions. */ #ifndef offsetof #define offsetof(type, member) ((char *)&((type *)0)->member - (char *)0) #endif static int Verbose = 0; typedef union vehicle_U { enum vehicle_type { AIRPLANE = 1, BOAT = 2, CAR = 3 } type; struct { enum vehicle_type air_type; char *air_flight; int air_passengers; } airplane; struct { enum vehicle_type boat_type; int boat_knots; char *boat_name; } boat; struct { enum vehicle_type car_type; int car_mpg; char *car_plate; } car; } vehicle_T; static sm_conf_definition_T const air_definitions[] = { { SM_CONF_DEF_MAGIC, "flight", sm_conf_type_string, offsetof(vehicle_T, airplane.air_flight), 0, NULL }, { SM_CONF_DEF_MAGIC, "passengers", sm_conf_type_u32, offsetof(vehicle_T, airplane.air_passengers), sizeof(unsigned int), "1" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T const boat_definitions[] = { { SM_CONF_DEF_MAGIC, "name", sm_conf_type_string, offsetof(vehicle_T, boat.boat_name), 0, NULL }, { SM_CONF_DEF_MAGIC, "knots", sm_conf_type_u32, offsetof(vehicle_T, boat.boat_knots), sizeof(unsigned int), NULL }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T const car_definitions[] = { { SM_CONF_DEF_MAGIC, "plate", sm_conf_type_string, offsetof(vehicle_T, car.car_plate), 0, NULL }, { SM_CONF_DEF_MAGIC, "mpg", sm_conf_type_u32, offsetof(vehicle_T, car.car_mpg), sizeof(unsigned int), NULL }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T vehicle_definitions[] = { { SM_CONF_DEF_MAGIC, "", sm_conf_type_union_type, offsetof(vehicle_T, type), sizeof(enum vehicle_type), NULL, 0, NULL }, { SM_CONF_DEF_MAGIC, "", sm_conf_type_union_choice, /* offset = type tag */ AIRPLANE, sizeof(vehicle_T), "airplane", 0, air_definitions }, { SM_CONF_DEF_MAGIC, "", sm_conf_type_union_choice, /* offset = type tag */ BOAT, sizeof(vehicle_T), "boat", 0, boat_definitions }, { SM_CONF_DEF_MAGIC, "", sm_conf_type_union_choice, /* offset = type tag */ CAR, sizeof(vehicle_T), "car", 0, car_definitions }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; typedef struct { char *flavor; char *color; } icecream_T; static sm_conf_definition_T icecream_definitions[] = { { SM_CONF_DEF_MAGIC, /* name */ "color", /* type */ sm_conf_type_string, /* off */ offsetof(icecream_T, color), /* size */ 0, /* dflt */ NULL, /* flag */ SM_CONF_FLAG_STRICTLY_REQUIRED, /* cont */ NULL, /* chkf */ NULL, /* chkd */ NULL, /* desc */ "ice cream color" }, { SM_CONF_DEF_MAGIC, /* name */ "flavor", /* type */ sm_conf_type_string, /* off */ offsetof(icecream_T, flavor), /* size */ 0, /* dflt */ NULL, /* flag */ SM_CONF_FLAG_STRICTLY_REQUIRED, /* cont */ 0, /* chkf */ NULL, /* chkd */ NULL, /* desc */ "ice cream flavor" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; typedef struct { char name[20]; int price; } candy_T; static sm_conf_definition_T candy_definitions[] = { { SM_CONF_DEF_MAGIC, /* name */ "name", /* type */ sm_conf_type_string, /* off */ offsetof(candy_T, name), /* size */ 20, /* dflt */ NULL, /* flag */ SM_CONF_FLAG_STRICTLY_REQUIRED | SM_CONF_FLAG_FLAT, /* cont */ NULL, /* chkf */ NULL, /* chkd */ NULL, /* desc */ "name of candy" }, { SM_CONF_DEF_MAGIC, /* name */ "price", /* type */ sm_conf_type_u32, /* off */ offsetof(candy_T, price), /* size */ sizeof(int), /* dflt */ NULL, /* flag */ SM_CONF_FLAG_STRICTLY_REQUIRED, /* cont */ 0, /* chkf */ NULL, /* chkd */ NULL, /* desc */ "price of candy" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; typedef struct { long *fib; unsigned int fib_n; char pi[13]; unsigned int pi_n; icecream_T *icecream; unsigned int icecream_n; candy_T candy[4]; unsigned int candy_n; vehicle_T garage[2]; unsigned int garage_n; vehicle_T *fleet; unsigned int fleet_n; } structure; /* ** GARAGE_DEFINITIONS -- a two-element fixed array */ static sm_conf_definition_T garage_definitions[] = { { SM_CONF_DEF_MAGIC, "vehicle", sm_conf_type_union, offsetof(structure, garage), /* size = max # of elements */ 2, NULL, 0, vehicle_definitions, NULL, NULL, "vehicle parked in a garage" }, { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(structure, garage_n), sizeof(unsigned int), NULL, /* flags */ 0, NULL, NULL, NULL, "number of vehicles parked in the garge" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T garage_outer_definitions[] = { { SM_CONF_DEF_MAGIC, "vehicle", sm_conf_type_array, 0, sizeof(vehicle_T), NULL, SM_CONF_FLAG_FLAT, garage_definitions, NULL, NULL, "garage section" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T fleet_definitions[] = { { SM_CONF_DEF_MAGIC, "fleet vehicle", sm_conf_type_union, offsetof(structure, fleet), sizeof(vehicle_T), NULL, 0, vehicle_definitions, NULL, NULL, "fleet of vehicles" }, { SM_CONF_DEF_MAGIC, "n", sm_conf_type_array_n, offsetof(structure, fleet_n), sizeof(unsigned int), NULL, 0, vehicle_definitions, NULL, NULL, "number of vehicles in the fleet (implicit)" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T fib_definitions[] = { /* numbers: long */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_u32, offsetof(structure, fib), sizeof(long), NULL, 0, NULL }, /* counter: unsigned int */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(structure, fib_n), sizeof(unsigned int), NULL, 0, NULL }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T pi_definitions[] = { /* numbers: char */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_u32, offsetof(structure, pi), sizeof(char), NULL, 0, NULL }, /* counter: unsigned int */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(structure, pi_n), sizeof(unsigned int), NULL, 0, NULL }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T icecreams_definitions[] = { /* flavors: icecream_T */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_section, offsetof(structure, icecream), sizeof(icecream_T), NULL, 0, icecream_definitions }, /* counter: unsigned int */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(structure, icecream_n), sizeof(unsigned int) }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T candies_definitions[] = { /* candy: candy_T */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_section, offsetof(structure, candy), sizeof(candy_T), NULL, 0, candy_definitions }, /* counter: unsigned int */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(structure, candy_n), sizeof(unsigned int) }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T const definitions[] = { { SM_CONF_DEF_MAGIC, "fibonacci", sm_conf_type_array, 0, /* offset (n/a; see contents) */ 0, /* unlimited size */ NULL, 0, fib_definitions, NULL, NULL, "fibonacci numbers" }, { SM_CONF_DEF_MAGIC, "pi", sm_conf_type_array, 0, /* offset (n/a; see contents) */ 12, /* size: maximum number of elements */ NULL, SM_CONF_FLAG_FLAT, pi_definitions, NULL, NULL, "digits of pi" }, { SM_CONF_DEF_MAGIC, "icecream", sm_conf_type_array, 0, /* offset (n/a; see contents) */ 10, /* size: maximum number of elements */ NULL, SM_CONF_FLAG_MULTIPLE, icecreams_definitions, NULL, NULL, "icecream flavor(s)" }, { SM_CONF_DEF_MAGIC, "candy", sm_conf_type_array, 0, /* offset (n/a; see contents) */ 4, /* size: maximum number of elements */ NULL, SM_CONF_FLAG_MULTIPLE | SM_CONF_FLAG_FLAT, candies_definitions, NULL, NULL, "brands of candy" }, { SM_CONF_DEF_MAGIC, "garage", sm_conf_type_section, 0, /* offset */ 2, /* size (# of elements) */ NULL, /* default */ 0, garage_outer_definitions, NULL, NULL, "A garage with up to two vehicles." }, { SM_CONF_DEF_MAGIC, "vehicle", sm_conf_type_array, 0, 0, NULL, SM_CONF_FLAG_MULTIPLE, fleet_definitions, NULL, NULL, "A fleet with an arbitrary number of vehicles." }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static void print_vehicle(vehicle_T const *v) { switch (v->type) { case AIRPLANE: printf("airplane { flight=%s passengers=%d }\n", v->airplane.air_flight == NULL ? "(null)" : v->airplane.air_flight, v->airplane.air_passengers); break; case BOAT: printf("boat { knots=%d name=%s }\n", v->boat.boat_knots, v->boat.boat_name == NULL ? "(null)" : v->boat.boat_name); break; case CAR: printf("car { mpg=%d plate=%s }\n", v->car.car_mpg, v->car.car_plate == NULL ? "(null)" : v->car.car_plate); break; case 0: printf("(empty)\n"); break; default: printf("\n", (int)v->type); break; } } static void print_structure(structure *s) { size_t i; printf("fibonacci: [%lu]", (unsigned long)s->fib_n); for (i = 0; i < s->fib_n; i++) printf(" %lu", s->fib[i]); putchar('\n'); printf("pi: [%lu]", (unsigned long)s->pi_n); for (i = 0; i < s->pi_n; i++) printf(" %d", (int)s->pi[i]); putchar('\n'); printf("icecream: [%lu]\n", (unsigned long)s->icecream_n); for (i = 0; i < s->icecream_n; i++) printf("[%lu] { flavor=%s; color=%s; }\n", (unsigned long)i, s->icecream[i].flavor ? s->icecream[i].flavor : "(null)", s->icecream[i].color ? s->icecream[i].color : "(null)"); printf("candy: [%lu]\n", (unsigned long)s->candy_n); for (i = 0; i < s->candy_n; i++) printf("[%lu] { name=%s; price=%lu; }\n", (unsigned long)i, s->candy[i].name ? s->candy[i].name : "(null)", (unsigned long)s->candy[i].price); printf("garage: [%d]\n", s->garage_n); for (i = 0; i < 2; i++) { printf("[%d] ", (int)i); print_vehicle(s->garage + i); } printf("fleet: [%d]\n", s->fleet_n); for (i = 0; i < s->fleet_n; i++) { printf("[%d] ", (int)i); print_vehicle(s->fleet + i); } putchar('\n'); } static int process(char const *name, FILE *fp) { sm_conf_T *stream; int err; structure s; if (((stream = sm_conf_new(name ? name : "*stdin*"))) == NULL) { fprintf(stderr, "error -- sm_conf_new() returns NULL!\n"); return 1; } if ((err = sm_conf_read_FILE(stream, name, fp)) != 0) { char buf[SM_CONF_ERROR_BUFFER_SIZE]; char const *e = NULL; fprintf(stderr, "%s: %s\n", name ? name : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(stream, e)) != NULL) fprintf(stderr, "%s\n", e); sm_conf_destroy(stream); return 2; } memset(&s, 0, sizeof(s)); err = sm_conf_scan(stream, definitions, 0, &s); if (err != 0) { char buf[SM_CONF_ERROR_BUFFER_SIZE]; char const *e = NULL; fprintf(stderr, "(while scanning) %s: %s\n", name ? name : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(stream, e)) != NULL) fprintf(stderr, "%s\n", e); sm_conf_destroy(stream); return 3; } if (Verbose > 0) { sm_io_fprintf(smioout, "configuration\n"); sm_conf_prt_conf(definitions, &s, smioout); sm_io_flush(smioout); } print_structure(&s); sm_conf_destroy(stream); return 0; } int main(int ac, char **av) { int ai, r; while ((r = getopt(ac, av, "V")) != -1) { switch (r) { case 'V': Verbose++; break; default: /* usage(av[0]); */ return 1; } } ac -= optind; av += optind; if (ac == 0) return process("*stdin*", stdin); for (ai = 0; ai < ac; ai++) { int ret = process(av[ai], NULL); if (ret != 0) return ret; } return 0; }