tlist.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tlist.c (4769B)
---
     1 #include 
     2 #include 
     3 #include 
     4 #include 
     5 #include 
     6 #include 
     7 #include "dat.h"
     8 
     9 int debug;
    10 
    11 enum
    12 {
    13         Tregexp=        (1<<0),                /* ~ */
    14         Texact=                (1<<1),                /* = */
    15 };
    16 
    17 typedef struct Pattern Pattern;
    18 struct Pattern
    19 {
    20         Pattern        *next;
    21         int        type;
    22         char        *arg;
    23         int        bang;
    24 };
    25 
    26 String        *patternpath;
    27 Pattern        *patterns;
    28 String        *mbox;
    29 
    30 static void
    31 usage(void)
    32 {
    33         fprint(2, "usage: %s 'check|add' patternfile addr [addr*]\n", argv0);
    34         exits("usage");
    35 }
    36 
    37 /*
    38  *  convert string to lower case
    39  */
    40 static void
    41 mklower(char *p)
    42 {
    43         int c;
    44 
    45         for(; *p; p++){
    46                 c = *p;
    47                 if(c <= 'Z' && c >= 'A')
    48                         *p = c - 'A' + 'a';
    49         }
    50 }
    51 
    52 /*
    53  *  simplify an address, reduce to a domain
    54  */
    55 static String*
    56 simplify(char *addr)
    57 {
    58         int dots;
    59         char *p, *at;
    60         String *s;
    61 
    62         mklower(addr);
    63         at = strchr(addr, '@');
    64         if(at == nil){
    65                 /* local address, make it an exact match */
    66                 s = s_copy("=");
    67                 s_append(s, addr);
    68                 return s;
    69         }
    70 
    71         /* copy up to the '@' sign */
    72         at++;
    73         s = s_copy("~");
    74         for(p = addr; p < at; p++){
    75                 if(strchr(".*+?(|)\\[]^$", *p))
    76                         s_putc(s, '\\');
    77                 s_putc(s, *p);
    78         }
    79 
    80         /* just any address matching the two most significant domain elements */
    81         s_append(s, "(.*\\.)?");
    82         p = addr+strlen(addr);
    83         dots = 0;
    84         for(; p > at; p--){
    85                 if(*p != '.')
    86                         continue;
    87                 if(dots++ > 0){
    88                         p++;
    89                         break;
    90                 }
    91         }
    92         for(; *p; p++){
    93                 if(strchr(".*+?(|)\\[]^$", *p) != 0)
    94                         s_putc(s, '\\');
    95                 s_putc(s, *p);
    96         }
    97         s_terminate(s);
    98 
    99         return s;
   100 }
   101 
   102 /*
   103  *  link patterns in order
   104  */
   105 static int
   106 newpattern(int type, char *arg, int bang)
   107 {
   108         Pattern *p;
   109         static Pattern *last;
   110 
   111         mklower(arg);
   112 
   113         p = mallocz(sizeof *p, 1);
   114         if(p == nil)
   115                 return -1;
   116         if(type == Tregexp){
   117                 p->arg = malloc(strlen(arg)+3);
   118                 if(p->arg == nil){
   119                         free(p);
   120                         return -1;
   121                 }
   122                 p->arg[0] = 0;
   123                 strcat(p->arg, "^");
   124                 strcat(p->arg, arg);
   125                 strcat(p->arg, "$");
   126         } else {
   127                 p->arg = strdup(arg);
   128                 if(p->arg == nil){
   129                         free(p);
   130                         return -1;
   131                 }
   132         }
   133         p->type = type;
   134         p->bang = bang;
   135         if(last == nil)
   136                 patterns = p;
   137         else
   138                 last->next = p;
   139         last = p;
   140 
   141         return 0;
   142 }
   143 
   144 /*
   145  *  patterns are either
   146  *        ~ regular expression
   147  *        = exact match string
   148  *
   149  *  all comparisons are case insensitive
   150  */
   151 static int
   152 readpatterns(char *path)
   153 {
   154         Biobuf *b;
   155         char *p;
   156         char *token[2];
   157         int n;
   158         int bang;
   159 
   160         b = Bopen(path, OREAD);
   161         if(b == nil)
   162                 return -1;
   163         while((p = Brdline(b, '\n')) != nil){
   164                 p[Blinelen(b)-1] = 0;
   165                 n = tokenize(p, token, 2);
   166                 if(n == 0)
   167                         continue;
   168 
   169                 mklower(token[0]);
   170                 p = token[0];
   171                 if(*p == '!'){
   172                         p++;
   173                         bang = 1;
   174                 } else
   175                         bang = 0;
   176 
   177                 if(*p == '='){
   178                         if(newpattern(Texact, p+1, bang) < 0)
   179                                 return -1;
   180                 } else if(*p == '~'){
   181                         if(newpattern(Tregexp, p+1, bang) < 0)
   182                                 return -1;
   183                 } else if(strcmp(token[0], "#include") == 0 && n == 2)
   184                         readpatterns(token[1]);
   185         }
   186         Bterm(b);
   187         return 0;
   188 }
   189 
   190 /* fuck, shit, bugger, damn */
   191 void regerror(char *err)
   192 {
   193         USED(err);
   194 }
   195 
   196 /*
   197  *  check lower case version of address agains patterns
   198  */
   199 static Pattern*
   200 checkaddr(char *arg)
   201 {
   202         Pattern *p;
   203         Reprog *rp;
   204         String *s;
   205 
   206         s = s_copy(arg);
   207         mklower(s_to_c(s));
   208 
   209         for(p = patterns; p != nil; p = p->next)
   210                 switch(p->type){
   211                 case Texact:
   212                         if(strcmp(p->arg, s_to_c(s)) == 0){
   213                                 free(s);
   214                                 return p;
   215                         }
   216                         break;
   217                 case Tregexp:
   218                         rp = regcomp(p->arg);
   219                         if(rp == nil)
   220                                 continue;
   221                         if(regexec(rp, s_to_c(s), nil, 0)){
   222                                 free(rp);
   223                                 free(s);
   224                                 return p;
   225                         }
   226                         free(rp);
   227                         break;
   228                 }
   229         s_free(s);
   230         return 0;
   231 }
   232 static char*
   233 check(int argc, char **argv)
   234 {
   235         int i;
   236         Addr *a;
   237         Pattern *p;
   238         int matchedbang;
   239 
   240         matchedbang = 0;
   241         for(i = 0; i < argc; i++){
   242                 a = readaddrs(argv[i], nil);
   243                 for(; a != nil; a = a->next){
   244                         p = checkaddr(a->val);
   245                         if(p == nil)
   246                                 continue;
   247                         if(p->bang)
   248                                 matchedbang = 1;
   249                         else
   250                                 return nil;
   251                 }
   252         }
   253         if(matchedbang)
   254                 return "!match";
   255         else
   256                 return "no match";
   257 }
   258 
   259 /*
   260  *  add anything that isn't already matched, all matches are lower case
   261  */
   262 static char*
   263 add(char *pp, int argc, char **argv)
   264 {
   265         int fd, i;
   266         String *s;
   267         char *cp;
   268         Addr *a;
   269 
   270         a = nil;
   271         for(i = 0; i < argc; i++)
   272                 a = readaddrs(argv[i], a);
   273 
   274         fd = open(pp, OWRITE);
   275         seek(fd, 0, 2);
   276         for(; a != nil; a = a->next){
   277                 if(checkaddr(a->val))
   278                         continue;
   279                 s = simplify(a->val);
   280                 cp = s_to_c(s);
   281                 fprint(fd, "%q\t%q\n", cp, a->val);
   282                 if(*cp == '=')
   283                         newpattern(Texact, cp+1, 0);
   284                 else if(*cp == '~')
   285                         newpattern(Tregexp, cp+1, 0);
   286                 s_free(s);
   287         }
   288         close(fd);
   289         return nil;
   290 }
   291 
   292 void
   293 main(int argc, char **argv)
   294 {
   295         char *patternpath;
   296 
   297         ARGBEGIN {
   298         case 'd':
   299                 debug++;
   300                 break;
   301         } ARGEND;
   302 
   303         quotefmtinstall();
   304 
   305         if(argc < 3)
   306                 usage();
   307 
   308         patternpath = argv[1];
   309         readpatterns(patternpath);
   310         if(strcmp(argv[0], "add") == 0)
   311                 exits(add(patternpath, argc-2, argv+2));
   312         else if(strcmp(argv[0], "check") == 0)
   313                 exits(check(argc-2, argv+2));
   314         else
   315                 usage();
   316 }