From f142ee94c2fa3d5f8ec3686b2ced2e1f0b807def Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 5 Mar 2013 09:16:29 +0200 Subject: Revamp as a standalone project. Remove unneeded dependencies. * Makefile.am: Remove * Makefile: Restore from bc518485 * ckaliases.c: Rename to alck.c * ckaliases.h: Rename to alck.h * gram.y (emalloc, error) (syserror, parserror): New functions. (main): Use traditional getopt. * lex.l: Use slist instead of obstack. * slist.c: New file. --- Makefile | 13 +++ Makefile.am | 23 ----- alck.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ alck.h | 65 ++++++++++++ ckaliases.c | 302 ------------------------------------------------------ ckaliases.h | 71 ------------- gram.y | 115 +++++++++++++++------ lex.l | 65 ++++++++---- slist.c | 97 ++++++++++++++++++ 9 files changed, 637 insertions(+), 450 deletions(-) create mode 100644 Makefile delete mode 100644 Makefile.am create mode 100644 alck.c create mode 100644 alck.h delete mode 100644 ckaliases.c delete mode 100644 ckaliases.h create mode 100644 slist.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..00f7ea0 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +CFLAGS=-ggdb +alck: lex.yy.o y.tab.o alck.o slist.o + cc -ggdb -o $@ $^ + +y.tab.c y.tab.h: gram.y + yacc -vtd gram.y + +lex.yy.c: lex.l + lex -d lex.l + +lex.yy.o: lex.yy.c y.tab.h + +clean:; rm -rf *.o ckaliases \ No newline at end of file diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 12f531c..0000000 --- a/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# This file is part of GSC -# Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff -# -# GSC is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GSC is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GSC. If not, see . - -AM_YFLAGS=-vtd -AM_LFLAGS=-d -sbin_PROGRAMS=ckaliases -noinst_HEADERS=gram.h -ckaliases_SOURCES=gram.y lex.l ckaliases.c ckaliases.h -LDADD=../lib/libgsc.a ../gnu/libgnu.a -INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/gnu -I../gnu diff --git a/alck.c b/alck.c new file mode 100644 index 0000000..f8a3d11 --- /dev/null +++ b/alck.c @@ -0,0 +1,336 @@ +/* ckaliases - verify syntax of sendmail-style alias files + Copyright (C) 2005, 2007 Sergey Poznyakoff + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see . */ + +#include "alck.h" + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif +#define BITS_PER_WORD (sizeof(unsigned)*CHAR_BIT) +#define MAXTABLE 32767 + +#define WORDSIZE(n) (((n) + BITS_PER_WORD - 1) / BITS_PER_WORD) +#define SETBIT(x, i) ((x)[(i)/BITS_PER_WORD] |= (1<<((i) % BITS_PER_WORD))) +#define RESETBIT(x, i) ((x)[(i)/BITS_PER_WORD] &= ~(1<<((i) % BITS_PER_WORD))) +#define BITISSET(x, i) (((x)[(i)/BITS_PER_WORD] & (1<<((i) % BITS_PER_WORD))) != 0) + +/* given n by n matrix of bits R, modify its contents + to be the transitive closure of what was given. */ + +void +TC(unsigned *R, int n) +{ + register int rowsize; + register unsigned mask; + register unsigned *rowj; + register unsigned *rp; + register unsigned *rend; + register unsigned *ccol; + + unsigned *relend; + unsigned *cword; + unsigned *rowi; + + rowsize = WORDSIZE(n) * sizeof(unsigned); + relend = (unsigned *) ((char *) R + (n * rowsize)); + + cword = R; + mask = 1; + rowi = R; + while (rowi < relend) { + ccol = cword; + rowj = R; + + while (rowj < relend) { + if (*ccol & mask) { + rp = rowi; + rend = (unsigned *) ((char *) rowj + rowsize); + + while (rowj < rend) + *rowj++ |= *rp++; + } else { + rowj = (unsigned *) ((char *) rowj + rowsize); + } + + ccol = (unsigned *) ((char *) ccol + rowsize); + } + + mask <<= 1; + if (mask == 0) { + mask = 1; + cword++; + } + rowi = (unsigned *) ((char *) rowi + rowsize); + } +} + +struct alias { + struct alias *prev, *next; + char *name; + int num; + SLIST *exp; +}; + +struct ali_list { + struct alias *head, *tail; + size_t count; +}; + +struct ali_list aliases; + +static int +ali_cmp(struct alias *a, struct alias *b) +{ + return strcmp(a->name, b->name); +} + +static int +ali_cmp2(struct alias *a, struct alias *b) +{ + char *aname = a->name; + char *bname = b->name; + int rc; + int alen; + int blen; + char *p; + + if ((p = strchr(aname, '@')) && slist_member(cw_list, p + 1)) + alen = p - aname; + else + alen = strlen(aname); + + if ((p = strchr(bname, '@')) && slist_member(cw_list, p + 1)) + blen = p - bname; + else + blen = strlen(bname); + + if (alen == blen) + return memcmp(aname, bname, alen); + + return strcmp(aname, bname); +} + +void +ali_insert(struct ali_list *lp, + struct alias *anchor, + struct alias *ent, int before) +{ + struct alias *p; + + if (!anchor) { + ent->prev = NULL; + ent->next = lp->head; + if (lp->head) + lp->head->prev = ent; + else + lp->tail = ent; + lp->head = ent; + lp->count++; + return; + } + + if (before) { + ali_insert(lp, anchor->prev, ent, 0); + return; + } + + ent->prev = anchor; + if (p = anchor->next) + p->prev = ent; + else + lp->tail = ent; + ent->next = p; + anchor->next = ent; + lp->count++; +} + +void +ali_join(struct ali_list *a, struct ali_list *b) +{ + if (!b->head) + return; + b->head->prev = a->tail; + if (a->tail) + a->tail->next = b->head; + else + a->head = b->head; + a->tail = b->tail; +} + +void +ali_sort(struct ali_list *list, int (*cmp)(struct alias *, struct alias *)) +{ + struct alias *cur, *middle; + struct ali_list high_list, low_list; + int rc; + + if (!list->head) + return; + cur = list->head; + do { + cur = cur->next; + if (!cur) + return; + } while ((rc = cmp(list->head, cur)) == 0); + + /* Select the lower of the two as the middle value */ + middle = (rc > 0) ? cur : list->head; + + /* Split into two sublists */ + low_list.head = low_list.tail = NULL; + high_list.head = high_list.tail = NULL; + + for (cur = list->head; cur; ) { + struct alias *next = cur->next; + cur->next = NULL; + if (cmp(middle, cur) < 0) + ali_insert(&high_list, high_list.tail, cur, 0); + else + ali_insert(&low_list, low_list.tail, cur, 0); + cur = next; + } + + /* Sort both sublists recursively */ + ali_sort(&low_list, cmp); + ali_sort(&high_list, cmp); + + /* Join both lists in order */ + ali_join(&low_list, &high_list); + + /* Return the resulting list */ + list->head = low_list.head; + list->tail = low_list.tail; +} + +struct alias * +ali_locate(struct ali_list *lp, int (*cmp)(struct alias *, struct alias *), + struct alias *data) +{ + struct alias *ep; + + for (ep = lp->head; ep; ep = ep->next) { + if (cmp(ep, data) == 0) + return ep; + } + return NULL; +} + +void +end_aliases() +{ + int i; + struct alias *ali; + + ali_sort(&aliases, ali_cmp); + if (!aliases.head) + return; + for (i = 0, ali = aliases.head; ali->next; ali = ali->next, i++) { + if (ali_cmp(ali, ali->next) == 0) { + error("alias `%s' multiply defined", ali->name); + error_count++; + } + ali->num = i; + } +} + +void +regalias(char *name, SLIST *exp) +{ + struct alias *a = emalloc(sizeof(*a)); + a->name = name; + a->exp = exp; + a->next = NULL; + ali_insert(&aliases, NULL, a, 0); +} + +int +find_alias(char *name) +{ + struct alias a, *p; + + if (!name) + return -1; + a.name = name; + p = ali_locate(&aliases, ali_cmp2, &a); + return p ? p->num : -1; +} + + +static void +alias_setbit(unsigned *r, unsigned rowsize, unsigned row, unsigned col) +{ + SETBIT(r + rowsize * row, col); +} + +static int +alias_bitisset(unsigned *r, unsigned rowsize, unsigned row, unsigned col) +{ + return BITISSET(r + rowsize * row, col); +} + +void +mark_connected(unsigned *r, unsigned size) +{ + struct alias *ali; + + for (ali = aliases.head; ali; ali = ali->next) { + if (ali->exp) { + struct string_list *p; + for (p = ali->exp->head; p; p = p->next) { + int n = find_alias(p->str); + if (n >= 0) + alias_setbit(r, size, ali->num, n); + } + } + } +} + +void +check_circular_deps(unsigned *r, unsigned size) +{ + struct alias *ali; + + for (ali = aliases.head; ali; ali = ali->next) { + if (alias_bitisset(r, size, ali->num, ali->num)) { + error("%s: circular dependency", ali->name); + error_count++; + } + } +} + +void +check_aliases() +{ + size_t size; + unsigned *r; + + /* Allocate matrix */ + size = (aliases.count + BITS_PER_WORD - 1) / BITS_PER_WORD; + r = emalloc(aliases.count * size * sizeof(*r)); + memset(r, 0, aliases.count * size * sizeof(*r)); + + /* First pass: mark directly connected entries */ + mark_connected(r, size); + + /* Compute transitive closure of the matrix r */ + TC(r, aliases.count); + + /* Third pass: check for circular deps */ + check_circular_deps(r, size); + + if (verbose) + printf("%lu aliases\n", aliases.count); +} diff --git a/alck.h b/alck.h new file mode 100644 index 0000000..9af8db6 --- /dev/null +++ b/alck.h @@ -0,0 +1,65 @@ +/* ckaliases - verify syntax of sendmail-style alias files + Copyright (C) 2005 Sergey Poznyakoff + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *file_name; +extern int line_num; +extern int error_count; + +void *emalloc(size_t size); +void error(const char *fmt, ...); +void syserror(int ec, const char *fmt, ...); +void parserror(const char *file, int line, const char *fmt, ...); + +void init_lex(); +void lex_debug(int n); +void openaliases(char *name); +void openaliases_prefix(char *prefix, char *name); + +struct string_list { + struct string_list *next; + char *str; + size_t len; +}; + +typedef struct slist { + struct string_list *head, *tail; + int count; +} SLIST; + +char *slist_add(SLIST **plist, char *str); +char *slist_add_n(SLIST **plist, char *str, size_t n); +void slist_append(SLIST **pdst, SLIST * src); +char *slist_member(SLIST *plist, char *name); +void slist_destroy(SLIST **plist); + +void read_include(SLIST **plist, char *name); + +void regalias(char *name, SLIST *exp); +void end_aliases(void); + +extern SLIST *cw_list; +extern int verbose; diff --git a/ckaliases.c b/ckaliases.c deleted file mode 100644 index da0a5c1..0000000 --- a/ckaliases.c +++ /dev/null @@ -1,302 +0,0 @@ -/* ckaliases - verify syntax of sendmail-style alias files - Copyright (C) 2005, 2007 Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program. If not, see . */ - -#include "ckaliases.h" - -#ifndef CHAR_BIT -# define CHAR_BIT 8 -#endif -#define BITS_PER_WORD (sizeof(unsigned)*CHAR_BIT) -#define MAXTABLE 32767 - -#define WORDSIZE(n) (((n) + BITS_PER_WORD - 1) / BITS_PER_WORD) -#define SETBIT(x, i) ((x)[(i)/BITS_PER_WORD] |= (1<<((i) % BITS_PER_WORD))) -#define RESETBIT(x, i) ((x)[(i)/BITS_PER_WORD] &= ~(1<<((i) % BITS_PER_WORD))) -#define BITISSET(x, i) (((x)[(i)/BITS_PER_WORD] & (1<<((i) % BITS_PER_WORD))) != 0) - -/* given n by n matrix of bits R, modify its contents - to be the transitive closure of what was given. */ - -void -TC(unsigned *R, int n) -{ - register int rowsize; - register unsigned mask; - register unsigned *rowj; - register unsigned *rp; - register unsigned *rend; - register unsigned *ccol; - - unsigned *relend; - unsigned *cword; - unsigned *rowi; - - rowsize = WORDSIZE(n) * sizeof(unsigned); - relend = (unsigned *) ((char *) R + (n * rowsize)); - - cword = R; - mask = 1; - rowi = R; - while (rowi < relend) { - ccol = cword; - rowj = R; - - while (rowj < relend) { - if (*ccol & mask) { - rp = rowi; - rend = (unsigned *) ((char *) rowj + rowsize); - - while (rowj < rend) - *rowj++ |= *rp++; - } else { - rowj = (unsigned *) ((char *) rowj + rowsize); - } - - ccol = (unsigned *) ((char *) ccol + rowsize); - } - - mask <<= 1; - if (mask == 0) { - mask = 1; - cword++; - } - rowi = (unsigned *) ((char *) rowi + rowsize); - } -} - - -void -slist_add(SLIST **plist, char *str) -{ - struct string_list *p = xmalloc(sizeof(*p)); - p->str = str; - p->next = NULL; - - if (!*plist) { - *plist = xmalloc(sizeof(**plist)); - (*plist)->head = NULL; - } - - if ((*plist)->head == NULL) { - (*plist)->head = p; - (*plist)->count = 0; - } else { - (*plist)->tail->next = p; - (*plist)->count++; - } - (*plist)->tail = p; -} - -void -slist_append(SLIST **pdst, SLIST *src) -{ - struct string_list *tail; - - if (!*pdst) { - *pdst = xmalloc(sizeof(**pdst)); - (*pdst)->head = NULL; - (*pdst)->count = 0; - } - - if ((*pdst)->head = NULL) - (*pdst)->head = src->head; - - for (tail = src->tail; tail->next; tail = tail->next) - ; - - (*pdst)->tail = tail; - (*pdst)->count += src->count; -} - -char * -slist_member(SLIST *plist, char *name) -{ - struct string_list *p; - - if (plist) - for (p = plist->head; p; p = p->next) - if (p->str && strcmp(p->str, name) == 0) - return p->str; - return NULL; -} - -void -slist_destroy(SLIST **plist) -{ - struct string_list *p; - if (!plist || !*plist) - return; - p = (*plist)->head; - while (p) { - struct string_list *next = p->next; - free(p); - p = next; - } - free(*plist); - *plist = NULL; -} - - -typedef struct { - char *name; - SLIST *exp; -} ALIAS; - -struct obstack alias_stk; -unsigned alias_count; -ALIAS *aliases; - -void -regalias(char *name, SLIST *exp) -{ - ALIAS a; - a.name = name; - a.exp = exp; - obstack_grow(&alias_stk, &a, sizeof a); - alias_count++; -} - -void -begin_aliases() -{ - obstack_init(&alias_stk); -} - -static int -alias_cmp(const void *a, const void *b) -{ - return strcmp(((ALIAS *) a)->name, ((ALIAS *) b)->name); -} - -static int -alias_cmp2(const void *a, const void *b) -{ - char *aname = ((ALIAS *) a)->name; - char *bname = ((ALIAS *) b)->name; - int rc; - int alen; - int blen; - char *p; - - if ((p = strchr(aname, '@')) && slist_member(cw_list, p + 1)) - alen = p - aname; - else - alen = strlen(aname); - - if ((p = strchr(bname, '@')) && slist_member(cw_list, p + 1)) - blen = p - bname; - else - blen = strlen(bname); - - if (alen == blen) - return memcmp(aname, bname, alen); - - return strcmp(aname, bname); -} - -void -end_aliases() -{ - int i; - aliases = obstack_finish(&alias_stk); - qsort(aliases, alias_count, sizeof aliases[0], alias_cmp); - for (i = 1; i < alias_count; i++) - if (alias_cmp(aliases + i - 1, aliases + i) == 0) { - error(0, 0, "alias `%s' multiply defined", aliases[i].name); - error_count++; - } -} - - -int -find_alias(char *name) -{ - ALIAS a, *p; - - if (!name) - return -1; - a.name = name; - p = bsearch(&a, aliases, alias_count, sizeof aliases[0], alias_cmp2); - return p ? p - aliases : -1; -} - - -static void -alias_setbit(unsigned *r, unsigned rowsize, unsigned row, unsigned col) -{ - SETBIT(r + rowsize * row, col); -} - -static int -alias_bitisset(unsigned *r, unsigned rowsize, unsigned row, unsigned col) -{ - return BITISSET(r + rowsize * row, col); -} - - -void -mark_connected(unsigned *r, unsigned size) -{ - int i; - - for (i = 0; i < alias_count; i++) { - if (aliases[i].exp) { - struct string_list *p; - for (p = aliases[i].exp->head; p; p = p->next) { - int n = find_alias(p->str); - if (n >= 0) - alias_setbit(r, size, i, n); - } - } - } -} - -void -check_circular_deps(unsigned *r, unsigned size) -{ - int i; - - for (i = 0; i < alias_count; i++) { - if (alias_bitisset(r, size, i, i)) { - error(0, 0, "%s: circular dependency", aliases[i].name); - error_count++; - } - } -} - -void -check_aliases() -{ - size_t size; - unsigned *r; - - /* Allocate matrix */ - size = (alias_count + BITS_PER_WORD - 1) / BITS_PER_WORD; - r = xmalloc(alias_count * size * sizeof(*r)); - memset(r, 0, alias_count * size * sizeof(*r)); - - /* First pass: mark directly connected entries */ - mark_connected(r, size); - - /* Compute transitive closure of the matrix r */ - TC(r, alias_count); - - /* Third pass: check for circular deps */ - check_circular_deps(r, size); - - if (verbose) - printf("%lu aliases\n", alias_count); -} diff --git a/ckaliases.h b/ckaliases.h deleted file mode 100644 index d3e053c..0000000 --- a/ckaliases.h +++ /dev/null @@ -1,71 +0,0 @@ -/* ckaliases - verify syntax of sendmail-style alias files - Copyright (C) 2005 Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 3 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program. If not, see . */ - -#ifdef HAVE_CONFIG_H -# include -#endif -#include -#include -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "getopt.h" -#include "progname.h" -#include "error.h" -#include "xalloc.h" - -extern char *file_name; -extern int line_num; -extern int error_count; - -void init_lex (); -void lex_debug (int n); -void openaliases (char *name); -void openaliases_prefix (char *prefix, char *name); - -struct string_list -{ - struct string_list *next; - char *str; -}; - -typedef struct slist -{ - struct string_list *head, *tail; - int count; -} SLIST; - -void slist_add (SLIST ** plist, char *str); -void slist_append (SLIST ** pdst, SLIST * src); -char *slist_member (SLIST * plist, char *name); -void slist_destroy (SLIST ** plist); - -void read_include (SLIST ** plist, char *name); - -void regalias (char *name, SLIST * exp); -void begin_aliases (void); -void end_aliases (void); - -extern SLIST *cw_list; -extern int verbose; diff --git a/gram.y b/gram.y index 34d46e2..4da7cb2 100644 --- a/gram.y +++ b/gram.y @@ -15,8 +15,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "ckaliases.h" - +#include "alck.h" +#include + +char *program_name; SLIST *cw_list; /* List of domain names pertaining to Sendmail 'w' class */ static int restricted; /* prohibit use of `special' aliases (pipes, file redirections and includes */ @@ -111,9 +113,53 @@ string: IDENT int yyerror (char *s) { - error_at_line(0, 0, file_name, line_num, "%s", s); + parserror(file_name, line_num, "%s", s); error_count++; } + +void * +emalloc(size_t size) +{ + void *p = malloc(size); + if (!p) { + error("not enough memory"); + exit(1); + } + return p; +} + +void +error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); +} + +void +syserror(int ec, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": %s\n", strerror(ec)); + va_end(ap); +} + +void +parserror(const char *file, int line, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s: %s:%d: ", program_name, file, line); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); +} void @@ -122,36 +168,40 @@ usage() printf("usage: ckaliases [OPTIONS] [FILES...]\n"); printf("OPTIONS and FILES may be interspered.\n"); printf("Valid options are:\n"); - printf(" -d,--debug=SPEC Set debug level. SPEC consists of the following\n"); + printf(" -d SPEC Set debug level. SPEC consists of the following\n"); printf(" letters:\n"); printf(" y enable parser debugging\n"); printf(" l enable lexical analizer debugging\n"); printf(" Upper-case variants are also accepted. Prepending\n"); printf(" a letter with '-' reverts its sense\n"); - printf(" -f, --files-from=FILE\n"); - printf(" Read names of alias files from FILE\n"); - printf(" -h, --help Display this help list\n"); - printf(" -r, --restrict Restrict alias file syntax to aliases only (i.e.\n"); + printf(" -f FILE Read names of alias files from FILE\n"); + printf(" -h Display this help list\n"); + printf(" -r Restrict alias file syntax to aliases only (i.e.\n"); printf(" prohibit use of pipes and file redirections\n"); - printf(" -u, --unrestrict Revert the effect of the previous -r option\n"); - printf(" -v, --verbose Verbose mode\n"); - printf(" -V, --version print program version and exit\n"); + printf(" -u Revert the effect of the previous -r option\n"); + printf(" -v Verbose mode\n"); + printf(" -V print program version and exit\n"); printf(" -w FILE Read contents of Sendmail `w' class from the given\n"); printf(" file.\n"); printf("\n"); - printf("Report bugs to <%s>\n", PACKAGE_BUGREPORT); + printf("Report bugs to <%s>\n", "gray@gnu.org"); } -struct option options[] = { - { "debug", required_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { "restrict", no_argument, NULL, 'r' }, - { "unrestrict", no_argument, NULL, 'u' }, - { "verbose", no_argument, NULL, 'v' }, - { "files-from", required_argument, NULL, 'f' }, - { NULL } -}; +static char license[] = "\ +License GPLv3+: GNU GPL version 3 or later \n\ +This is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\n"; + +#define VERSION "2.0" + +void +version() +{ + printf("alck %s\n", VERSION); + printf("Copyright (C) 2005, 2007, 2013 Sergey Poznyakoff\n"); + printf("%s\n", license); + exit(0); +} int main(int argc, char **argv) @@ -164,11 +214,9 @@ main(int argc, char **argv) SLIST *file_list; /* List of files to be read */ struct string_list *s; - begin_aliases(); - init_lex (); + init_lex(); program_name = argv[0]; - while ((c = getopt_long(argc, argv, "-d:f:hp:ruvw:", - options, NULL)) != EOF) { + while ((c = getopt(argc, argv, "-d:f:hp:ruVvw:")) != EOF) { switch (c) { case 1: if (!cw_list) @@ -198,7 +246,8 @@ main(int argc, char **argv) break; default: - error(1, 0, "%s: unknown debug option %c", argv[0]); + error("%s: unknown debug option %c", + argv[0], c); } } break; @@ -235,12 +284,12 @@ main(int argc, char **argv) break; case 'V': - gsc_version ("ckaliases"); + version(); exit (0); case 'w': if (file_count) - error(1, 0, "-w must be used before first non-option argument"); + error("-w must be used before first non-option argument"); cwfile = optarg; break; @@ -260,9 +309,11 @@ main(int argc, char **argv) file_count++; } - if (!file_count) - error(1, 0, "no files specified"); - + if (!file_count) { + error("no files specified"); + exit(1); + } + if (verbose) printf("%d files\n", file_count); end_aliases(); diff --git a/lex.l b/lex.l index c71d4b9..85bd53f 100644 --- a/lex.l +++ b/lex.l @@ -15,15 +15,15 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "ckaliases.h" -#include "gram.h" +#include "alck.h" +#include "y.tab.h" static void line_begin (void); static void line_add (char *text, size_t len); static void line_add_unescape (char *text, size_t len); static void line_finish (void); -struct obstack string_stk; +static SLIST *slist; char *file_name; int line_num; @@ -86,6 +86,8 @@ int yywrap() { fclose(yyin); + free(file_name); + file_name = NULL; return 1; } @@ -106,37 +108,52 @@ unescape_char(int c) void line_add(char *text, size_t len) { - obstack_grow(&string_stk, text, len); + slist_add_n(&slist, text, len); } void line_add_unescape(char *text, size_t len) { char c; - obstack_grow(&string_stk, text, len - 2); - c = unescape_char(text[len - 1]); - obstack_1grow(&string_stk, c); + char *p; + + p = slist_add_n(&slist, text, len); + p[len - 1] = unescape_char(text[len - 1]); } void line_begin() { + slist_destroy(&slist); } void -line_finish () +line_finish() { - obstack_1grow(&string_stk, 0); - yylval.string = obstack_finish(&string_stk); + size_t len = 0; + struct string_list *sp; + char *p; + + for (sp = slist->head; sp; sp = sp->next) + len += sp->len; + yylval.string = emalloc(len + 1); + p = yylval.string; + for (sp = slist->head; sp; sp = sp->next) { + memcpy(p, sp->str, sp->len); + p += sp->len; + } + *p = 0; } void openaliases(char *name) { - yyin = fopen (name, "r"); - if (!yyin) - error(1, errno, "cannot open file `%s'", name); - file_name = name; + yyin = fopen(name, "r"); + if (!yyin) { + syserror(errno, "cannot open file `%s'", name); + exit(1); + } + file_name = strdup(name); line_num = 0; } @@ -146,8 +163,10 @@ openaliases_prefix(char *prefix, char *name) char *fullname = NULL; struct stat st; - if (stat(prefix, &st)) - error(1, errno, "cannot stat `%s'", prefix); + if (stat(prefix, &st)) { + syserror(errno, "cannot stat `%s'", prefix); + exit(1); + } if (!S_ISDIR(st.st_mode)) { char *p = strrchr(prefix, '/'); @@ -156,7 +175,10 @@ openaliases_prefix(char *prefix, char *name) else prefix = "."; } - asprintf(&fullname, "%s/%s", prefix, name); + fullname = emalloc(strlen(prefix) + strlen(name) + 2); + strcpy(fullname, prefix); + strcat(fullname, "/"); + strcat(fullname, name); openaliases(fullname); free(fullname); } @@ -164,7 +186,6 @@ openaliases_prefix(char *prefix, char *name) void init_lex() { - obstack_init(&string_stk); yy_flex_debug = 0; } @@ -182,9 +203,9 @@ read_include(SLIST **plist, char *name) FILE *fp = fopen(name, "r"); if (!fp) { - error_at_line(0, 0, file_name, line_num, - "cannot open include file `%s': %s", - name, strerror(errno)); + parserror(file_name, line_num, + "cannot open include file `%s': %s", + name, strerror(errno)); error_count++; return; } @@ -200,7 +221,7 @@ read_include(SLIST **plist, char *name) ; q[1] = 0; if (*p) - slist_add(plist, strdup(p)); + slist_add(plist, p); } fclose(fp); } diff --git a/slist.c b/slist.c new file mode 100644 index 0000000..3742aa5 --- /dev/null +++ b/slist.c @@ -0,0 +1,97 @@ +/* ckaliases - verify syntax of sendmail-style alias files + Copyright (C) 2005, 2007, 2013 Sergey Poznyakoff + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see . */ + +#include "alck.h" + +char * +slist_add_n(SLIST **plist, char *str, size_t n) +{ + struct string_list *p = emalloc(sizeof(*p)); + p->str = emalloc(n); + memcpy(p->str, str, n); + p->len = n; + p->next = NULL; + + if (!*plist) { + *plist = emalloc(sizeof(**plist)); + (*plist)->head = NULL; + } + + if ((*plist)->head == NULL) { + (*plist)->head = p; + (*plist)->count = 0; + } else { + (*plist)->tail->next = p; + (*plist)->count++; + } + (*plist)->tail = p; + return p->str; +} + +char * +slist_add(SLIST **plist, char *str) +{ + return slist_add_n(plist, str, strlen(str) + 1); +} + +void +slist_append(SLIST **pdst, SLIST *src) +{ + struct string_list *tail; + + if (!*pdst) { + *pdst = emalloc(sizeof(**pdst)); + (*pdst)->head = NULL; + (*pdst)->count = 0; + } + + if ((*pdst)->head = NULL) + (*pdst)->head = src->head; + + for (tail = src->tail; tail->next; tail = tail->next) + ; + + (*pdst)->tail = tail; + (*pdst)->count += src->count; +} + +char * +slist_member(SLIST *plist, char *name) +{ + struct string_list *p; + + if (plist) + for (p = plist->head; p; p = p->next) + if (p->str && strcmp(p->str, name) == 0) + return p->str; + return NULL; +} + +void +slist_destroy(SLIST **plist) +{ + struct string_list *p; + if (!plist || !*plist) + return; + p = (*plist)->head; + while (p) { + struct string_list *next = p->next; + free(p); + p = next; + } + free(*plist); + *plist = NULL; +} -- cgit v1.2.1