/*
* 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.
*/
/*
** Use a tree for sorting.
** Note: this requires unique keys, hence it doesn't work for something
** like sorting domains.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-treeinsert.c,v 1.5 2005/04/14 17:08:56 ca Exp $")
#include "sm/types.h"
#include "sm/str.h"
#include "sm/bsd-tree.h"
#include "sm/mta.h"
#include "sm/test.h"
#include "sm/io.h"
#include "sm/sysexits.h"
static int Verbose = 0;
#define SMT_NOCHECKS 0x01
#define SMT_APPEND 0x02
#define SMT_LIST 0x04
#define SM_AQ_RCPTS 256
#define RCPT_MAX_LEN 256
static char *list[] = {
"Sendmail.ORG",
"sendmailx.org",
"sendmail.com",
"Sendmail.ORG",
"sendmail.com",
"Sendmail.COM",
"Sendmail.COM",
"sendmail.com",
"sendmail.com",
"sendmail.com",
"sendmail.com",
"sendmail.com",
"sendmail.com",
"sendmail.org",
"csuchico.edu",
"niu.edu",
"uni-kiel.de",
"vt.edu",
"andrew.cmu.edu",
"onet.pl",
"Sendmail.ORG",
"debian.org",
"nmt.edu",
"uwaterloo.ca",
"yale.edu",
"uni-erlangen.de",
"yahoo.com",
"earthlink.net",
"hotmail.com",
"hp.com",
"polytechnique.fr",
"gmail.com",
NULL
};
typedef struct aqt_root_S aqt_root_T, *aqt_root_P;
typedef struct aqr_tree_S aqr_tree_T, *aqr_tree_P;
typedef struct aq_rcpt_S aq_rcpt_T, *aq_rcpt_P;
struct aqt_root_S
{
RB_HEAD(aqr_tree_S, aq_rcpt_S) aqt_root;
};
struct aq_rcpt_S
{
sm_str_P aqr_domain;
RB_ENTRY(aq_rcpt_S) aqr_entry;
};
/*
** AQR_CMP -- compare two tnodes
**
** Parameters:
** na -- aq_rcpt a
** nb -- aq_rcpt b
**
** Returns:
** usual comparison code (<0, 0, >0)
*/
static int
aqr_cmp(aq_rcpt_P na, aq_rcpt_P nb)
{
SM_REQUIRE(na != NULL);
SM_REQUIRE(nb != NULL);
return sm_str_casecmp(na->aqr_domain, nb->aqr_domain);
}
RB_PROTOTYPE(aqr_tree_S, aq_rcpt_S, aqr_entry, aqr_cmp)
RB_GENERATE(aqr_tree_S, aq_rcpt_S, aqr_entry, aqr_cmp)
/*
** TREE_INSERT -- insert new elem into tree
**
** Parameters:
** elem -- previous element (may be NULL)
** new -- element to insert
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
tree_insert(aqt_root_P aqt_root, aq_rcpt_P aq_rcpt)
{
aq_rcpt_P aq_rcpt_h;
aq_rcpt_h = RB_INSERT(aqr_tree_S, &(aqt_root->aqt_root), aq_rcpt);
#if 0
if (aq_rcpt_h != NULL)
return sm_error_perm(SM_EM_Q_EDBC, EEXIST);
#endif /* 0 */
return SM_SUCCESS;
}
static sm_ret_T
aqr_test1(aqt_root_P aqt_root, uint n)
{
uint i;
aq_rcpt_P aq_rcpt_nxt, aq_rcpt_prev;
i = 0;
aq_rcpt_prev = NULL;
RB_FOREACH(aq_rcpt_nxt, aqr_tree_S, &(aqt_root->aqt_root))
{
if (Verbose > 0)
sm_io_fprintf(smioerr,
"LIST: %2u: aq_rcpt=%p, domain=%S\n",
i, aq_rcpt_nxt, aq_rcpt_nxt->aqr_domain);
++i;
if (aq_rcpt_prev != NULL)
SM_TEST(aqr_cmp(aq_rcpt_prev, aq_rcpt_nxt) <= 0);
aq_rcpt_prev = aq_rcpt_nxt;
}
if (Verbose > 0)
{
if (i != n)
sm_io_fprintf(smioerr, "i=%u, n=%u\n", i, n);
else
sm_io_fprintf(smioerr, "\n");
}
SM_TEST(i == n);
sm_io_flush(smioerr);
return SM_SUCCESS;
}
static sm_ret_T
aqr_test0(uint lim, uint flags)
{
sm_ret_T ret;
uint i;
int r;
sm_str_P str;
char buf[RCPT_MAX_LEN];
aq_rcpt_P aq_rcpt, aq_rcpt_prev;
aqt_root_T aqt_root;
aq_rcpt_prev = NULL;
aq_rcpt = NULL;
ret = SM_SUCCESS;
srand(time(0));
RB_INIT(&(aqt_root.aqt_root));
for (i = 0; i < lim; i++)
{
aq_rcpt = sm_zalloc(sizeof(*aq_rcpt));
SM_TEST_ERR(aq_rcpt != NULL);
if (SM_IS_FLAG(flags, SMT_LIST) && i < SM_ARRAY_SIZE(list))
{
if (list[i] == NULL)
break;
strlcpy(buf, list[i], sizeof(buf));
}
else
{
r = rand();
if (Verbose > 1)
sm_io_fprintf(smioout, "i=%u, r=%8d\n", i, r);
sm_snprintf(buf, sizeof(buf), "%d-domain.tld-%u", r, i);
}
str = sm_str_scpy0(NULL, buf, sizeof(buf));
aq_rcpt->aqr_domain = str;
str = NULL;
ret = tree_insert(&aqt_root, aq_rcpt);
if (sm_is_err(ret))
goto error;
aq_rcpt_prev = aq_rcpt;
if (!SM_IS_FLAG(flags, SMT_NOCHECKS))
ret = aqr_test1(&aqt_root, i + 1);
}
if (!SM_IS_FLAG(flags, SMT_NOCHECKS))
ret = aqr_test1(&aqt_root, i);
return ret;
error:
return ret;
}
static void
usage(const char *prg)
{
sm_io_fprintf(smioerr, "usage: %s [options]\n", prg);
sm_io_fprintf(smioerr, "Test AQ recipient sorting (domains are random numbers)\n");
sm_io_fprintf(smioerr, "options:\n");
sm_io_fprintf(smioerr, "-a append only, don't sort\n");
sm_io_fprintf(smioerr, "-n n specify number of recipients to sort\n");
sm_io_fprintf(smioerr, "-t don't perform tests, just sort\n");
sm_io_fprintf(smioerr, "-V increase verbosity\n");
exit(0);
}
int
main(int argc, char **argv)
{
int c;
uint n, flags;
sm_ret_T r;
char *prg;
prg = argv[0];
n = SM_AQ_RCPTS;
flags = 0;
while ((c = getopt(argc, argv, "aln:tV")) != -1)
{
switch (c)
{
case 'a':
flags |= SMT_NOCHECKS|SMT_APPEND;
break;
case 'l':
flags |= SMT_LIST;
break;
case 'n':
n = (uint) strtoul(optarg, NULL, 0);
break;
case 't':
flags |= SMT_NOCHECKS;
break;
case 'V':
++Verbose;
break;
default:
usage(prg);
return(EX_USAGE);
}
}
sm_test_begin(argc, argv, "test adbr 0");
r = aqr_test0(n, flags);
return sm_test_end();
}
syntax highlighted by Code2HTML, v. 0.9.1