chiark / gitweb /
Import fastforward 0.51
[fastforward] / setforward.c
1 #include "substdio.h"
2 #include "subfd.h"
3 #include "strerr.h"
4 #include "stralloc.h"
5 #include "open.h"
6 #include "case.h"
7 #include "readwrite.h"
8 #include "cdbmss.h"
9
10 #define FATAL "setforward: fatal: "
11
12 void usage()
13 {
14   strerr_die1x(100,"setforward: usage: setforward data.cdb data.tmp");
15 }
16 void nomem()
17 {
18   strerr_die2x(111,FATAL,"out of memory");
19 }
20 void missingsemicolon()
21 {
22   strerr_die2x(100,FATAL,"final instruction must end with semicolon");
23 }
24 void extracolon()
25 {
26   strerr_die2x(100,FATAL,"double colons are not permitted");
27 }
28 void extracomma()
29 {
30   strerr_die2x(100,FATAL,"commas are not permitted before colons");
31 }
32 void nulbyte()
33 {
34   strerr_die2x(100,FATAL,"NUL bytes are not permitted");
35 }
36 void longaddress()
37 {
38   strerr_die2x(100,FATAL,"addresses over 800 bytes are not permitted");
39 }
40
41 char *fncdb;
42 char *fntmp;
43 int fd;
44 struct cdbmss cdbmss;
45 stralloc key = {0};
46
47 stralloc target = {0}; /* always initialized; no NUL */
48 stralloc command = {0}; /* always initialized; no NUL */
49 stralloc instr = {0}; /* always initialized */
50
51 int flagtarget = 0;
52 /* 0: reading target; command is empty; instr is empty */
53 /* 1: target is complete; instr still has to be written; reading command */
54
55 void writeerr()
56 {
57   strerr_die4sys(111,FATAL,"unable to write to ",fntmp,": ");
58 }
59
60 void doit(prepend,data,datalen)
61 char *prepend;
62 char *data;
63 int datalen;
64 {
65   if (!stralloc_copys(&key,prepend)) nomem();
66   if (!stralloc_cat(&key,&target)) nomem();
67   case_lowerb(key.s,key.len);
68   if (cdbmss_add(&cdbmss,key.s,key.len,data,datalen) == -1)
69     writeerr();
70 }
71
72 int getch(ch)
73 char *ch;
74 {
75   int r;
76
77   r = substdio_get(subfdinsmall,ch,1);
78   if (r == -1)
79     strerr_die2sys(111,FATAL,"unable to read input: ");
80   return r;
81 }
82
83 void main(argc,argv)
84 int argc;
85 char **argv;
86 {
87   char ch;
88   int r;
89
90   if (!stralloc_copys(&target,"")) nomem();
91   if (!stralloc_copys(&command,"")) nomem();
92   if (!stralloc_copys(&instr,"")) nomem();
93
94   fncdb = argv[1]; if (!fncdb) usage();
95   fntmp = argv[2]; if (!fntmp) usage();
96
97   fd = open_trunc(fntmp);
98   if (fd == -1)
99     strerr_die4sys(111,FATAL,"unable to create ",fntmp,": ");
100
101   if (cdbmss_start(&cdbmss,fd) == -1) writeerr();
102
103   for (;;) {
104     if (!getch(&ch)) goto eof;
105
106     if (ch == '#') {
107       while (ch != '\n') if (!getch(&ch)) goto eof;
108       continue;
109     }
110
111     if (ch == ' ') continue;
112     if (ch == '\n') continue;
113     if (ch == '\t') continue;
114
115     if (ch == ':') {
116       if (flagtarget) extracolon();
117       flagtarget = 1;
118       continue;
119     }
120
121     if ((ch == ',') || (ch == ';')) {
122       if (!flagtarget) extracomma();
123       if (command.len) {
124         if (command.s[0] == '?') {
125           doit("?",command.s + 1,command.len - 1);
126         }
127         else if ((command.s[0] == '|') || (command.s[0] == '!')) {
128           if (!stralloc_cat(&instr,&command)) nomem();
129           if (!stralloc_0(&instr)) nomem();
130         }
131         else if ((command.s[0] == '.') || (command.s[0] == '/')) {
132           if (!stralloc_cat(&instr,&command)) nomem();
133           if (!stralloc_0(&instr)) nomem();
134         }
135         else {
136           if (command.len > 800) longaddress();
137           if (command.s[0] != '&')
138             if (!stralloc_cats(&instr,"&")) nomem();
139           if (!stralloc_cat(&instr,&command)) nomem();
140           if (!stralloc_0(&instr)) nomem();
141         }
142       }
143
144       if (!stralloc_copys(&command,"")) nomem();
145
146       if (ch == ';') {
147         if (instr.len)
148           doit(":",instr.s,instr.len);
149
150         if (!stralloc_copys(&target,"")) nomem();
151         if (!stralloc_copys(&instr,"")) nomem();
152         flagtarget = 0;
153       }
154       continue;
155     }
156
157     if (ch == '\\') if (!getch(&ch)) goto eof;
158     if (ch == 0) nulbyte();
159     if (!stralloc_append(flagtarget ? &command : &target,&ch)) nomem();
160   }
161
162   eof:
163   if (flagtarget || target.len)
164     missingsemicolon();
165
166   if (cdbmss_finish(&cdbmss) == -1) writeerr();
167   if (fsync(fd) == -1) writeerr();
168   if (close(fd) == -1) writeerr(); /* NFS stupidity */
169
170   if (rename(fntmp,fncdb) == -1)
171     strerr_die6sys(111,FATAL,"unable to move ",fntmp," to ",fncdb,": ");
172   
173   _exit(0);
174 }