Introduction
Introduction Statistics Contact Development Disclaimer Help
join.c - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
join.c (7544B)
---
1 /* join F1 F2 on stuff */
2 #include <u.h>
3 #include <stdio.h>
4 #include <libc.h>
5 #include <ctype.h>
6 #define F1 0
7 #define F2 1
8 #define F0 3
9 #define NFLD 100 /* max field per line */
10 #define comp() runecmp(ppi[F1][j1],ppi[F2][j2])
11 FILE *f[2];
12 Rune buf[2][BUFSIZ]; /*input lines */
13 Rune *ppi[2][NFLD+1]; /* pointers to fields in lines */
14 Rune *s1,*s2;
15 #define j1 joinj1
16 #define j2 joinj2
17
18 int j1 = 1; /* join of this field of file 1 */
19 int j2 = 1; /* join of this field of file 2 */
20 int olist[2*NFLD]; /* output these fields */
21 int olistf[2*NFLD]; /* from these files */
22 int no; /* number of entries in olist */
23 Rune sep1 = ' '; /* default field separator */
24 Rune sep2 = '\t';
25 char *sepstr=" ";
26 int discard; /* count of truncated lines */
27 Rune null[BUFSIZ]/* = L""*/;
28 int a1;
29 int a2;
30
31 char *getoptarg(int*, char***);
32 void output(int, int);
33 int input(int);
34 void oparse(char*);
35 void error(char*, char*);
36 void seek1(void), seek2(void);
37 Rune *strtorune(Rune *, char *);
38
39
40 void
41 main(int argc, char **argv)
42 {
43 int i;
44
45 while (argc > 1 && argv[1][0] == '-') {
46 if (argv[1][1] == '\0')
47 break;
48 switch (argv[1][1]) {
49 case '-':
50 argc--;
51 argv++;
52 goto proceed;
53 case 'a':
54 switch(*getoptarg(&argc, &argv)) {
55 case '1':
56 a1++;
57 break;
58 case '2':
59 a2++;
60 break;
61 default:
62 error("incomplete option -a","");
63 }
64 break;
65 case 'e':
66 strtorune(null, getoptarg(&argc, &argv));
67 break;
68 case 't':
69 sepstr=getoptarg(&argc, &argv);
70 chartorune(&sep1, sepstr);
71 sep2 = sep1;
72 break;
73 case 'o':
74 if(argv[1][2]!=0 ||
75 argc>2 && strchr(argv[2],',')!=0)
76 oparse(getoptarg(&argc, &argv));
77 else for (no = 0; no<2*NFLD && argc>2; no++){
78 if (argv[2][0] == '1' && argv[2][1] == '…
79 olistf[no] = F1;
80 olist[no] = atoi(&argv[2][2]);
81 } else if (argv[2][0] == '2' && argv[2][…
82 olist[no] = atoi(&argv[2][2]);
83 olistf[no] = F2;
84 } else if (argv[2][0] == '0')
85 olistf[no] = F0;
86 else
87 break;
88 argc--;
89 argv++;
90 }
91 break;
92 case 'j':
93 if(argc <= 2)
94 break;
95 if (argv[1][2] == '1')
96 j1 = atoi(argv[2]);
97 else if (argv[1][2] == '2')
98 j2 = atoi(argv[2]);
99 else
100 j1 = j2 = atoi(argv[2]);
101 argc--;
102 argv++;
103 break;
104 case '1':
105 j1 = atoi(getoptarg(&argc, &argv));
106 break;
107 case '2':
108 j2 = atoi(getoptarg(&argc, &argv));
109 break;
110 }
111 argc--;
112 argv++;
113 }
114 proceed:
115 for (i = 0; i < no; i++)
116 if (olist[i]-- > NFLD) /* 0 origin */
117 error("field number too big in -o","");
118 if (argc != 3)
119 error("usage: join [-1 x -2 y] [-o list] file1 file2",""…
120 j1--;
121 j2--; /* everyone else believes in 0 origin */
122 s1 = ppi[F1][j1];
123 s2 = ppi[F2][j2];
124 if (strcmp(argv[1], "-") == 0)
125 f[F1] = stdin;
126 else if ((f[F1] = fopen(argv[1], "r")) == 0)
127 error("can't open %s", argv[1]);
128 if(strcmp(argv[2], "-") == 0) {
129 f[F2] = stdin;
130 } else if ((f[F2] = fopen(argv[2], "r")) == 0)
131 error("can't open %s", argv[2]);
132
133 if(ftell(f[F2]) >= 0)
134 seek2();
135 else if(ftell(f[F1]) >= 0)
136 seek1();
137 else
138 error("neither file is randomly accessible","");
139 if (discard)
140 error("some input line was truncated", "");
141 exits("");
142 }
143 int runecmp(Rune *a, Rune *b){
144 while(*a==*b){
145 if(*a=='\0') return 0;
146 a++;
147 b++;
148 }
149 if(*a<*b) return -1;
150 return 1;
151 }
152 char *runetostr(char *buf, Rune *r){
153 char *s;
154 for(s=buf;*r;r++) s+=runetochar(s, r);
155 *s='\0';
156 return buf;
157 }
158 Rune *strtorune(Rune *buf, char *s){
159 Rune *r;
160 for(r=buf;*s;r++) s+=chartorune(r, s);
161 *r='\0';
162 return buf;
163 }
164 /* lazy. there ought to be a clean way to combine seek1 & seek2 */
165 #define get1() n1=input(F1)
166 #define get2() n2=input(F2)
167 void
168 seek2(void)
169 {
170 int n1, n2;
171 int top2=0;
172 int bot2 = ftell(f[F2]);
173 get1();
174 get2();
175 while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
176 if(n1>0 && n2>0 && comp()>0 || n1==0) {
177 if(a2) output(0, n2);
178 bot2 = ftell(f[F2]);
179 get2();
180 } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
181 if(a1) output(n1, 0);
182 get1();
183 } else /*(n1>0 && n2>0 && comp()==0)*/ {
184 while(n2>0 && comp()==0) {
185 output(n1, n2);
186 top2 = ftell(f[F2]);
187 get2();
188 }
189 fseek(f[F2], bot2, 0);
190 get2();
191 get1();
192 for(;;) {
193 if(n1>0 && n2>0 && comp()==0) {
194 output(n1, n2);
195 get2();
196 } else if(n1>0 && n2>0 && comp()<0 || n2…
197 fseek(f[F2], bot2, 0);
198 get2();
199 get1();
200 } else /*(n1>0 && n2>0 && comp()>0 || n1…
201 fseek(f[F2], top2, 0);
202 bot2 = top2;
203 get2();
204 break;
205 }
206 }
207 }
208 }
209 }
210 void
211 seek1(void)
212 {
213 int n1, n2;
214 int top1=0;
215 int bot1 = ftell(f[F1]);
216 get1();
217 get2();
218 while(n1>0 && n2>0 || (a1||a2) && n1+n2>0) {
219 if(n1>0 && n2>0 && comp()>0 || n1==0) {
220 if(a2) output(0, n2);
221 get2();
222 } else if(n1>0 && n2>0 && comp()<0 || n2==0) {
223 if(a1) output(n1, 0);
224 bot1 = ftell(f[F1]);
225 get1();
226 } else /*(n1>0 && n2>0 && comp()==0)*/ {
227 while(n2>0 && comp()==0) {
228 output(n1, n2);
229 top1 = ftell(f[F1]);
230 get1();
231 }
232 fseek(f[F1], bot1, 0);
233 get2();
234 get1();
235 for(;;) {
236 if(n1>0 && n2>0 && comp()==0) {
237 output(n1, n2);
238 get1();
239 } else if(n1>0 && n2>0 && comp()>0 || n1…
240 fseek(f[F1], bot1, 0);
241 get2();
242 get1();
243 } else /*(n1>0 && n2>0 && comp()<0 || n2…
244 fseek(f[F1], top1, 0);
245 bot1 = top1;
246 get1();
247 break;
248 }
249 }
250 }
251 }
252 }
253
254 int
255 input(int n) /* get input line and split into fields */
256 {
257 register int i, c;
258 Rune *bp;
259 Rune **pp;
260 char line[BUFSIZ];
261
262 bp = buf[n];
263 pp = ppi[n];
264 if (fgets(line, BUFSIZ, f[n]) == 0)
265 return(0);
266 strtorune(bp, line);
267 i = 0;
268 do {
269 i++;
270 if (sep1 == ' ') /* strip multiples */
271 while ((c = *bp) == sep1 || c == sep2)
272 bp++; /* skip blanks */
273 *pp++ = bp; /* record beginning */
274 while ((c = *bp) != sep1 && c != '\n' && c != sep2 && c …
275 bp++;
276 *bp++ = '\0'; /* mark end by overwriting blank */
277 } while (c != '\n' && c != '\0' && i < NFLD-1);
278 if (c != '\n')
279 discard++;
280
281 *pp = 0;
282 return(i);
283 }
284
285 void
286 output(int on1, int on2) /* print items from olist */
287 {
288 int i;
289 Rune *temp;
290 char buf[BUFSIZ];
291
292 if (no <= 0) { /* default case */
293 printf("%s", runetostr(buf, on1? ppi[F1][j1]: ppi[F2][j2…
294 for (i = 0; i < on1; i++)
295 if (i != j1)
296 printf("%s%s", sepstr, runetostr(buf, pp…
297 for (i = 0; i < on2; i++)
298 if (i != j2)
299 printf("%s%s", sepstr, runetostr(buf, pp…
300 printf("\n");
301 } else {
302 for (i = 0; i < no; i++) {
303 if (olistf[i]==F0 && on1>j1)
304 temp = ppi[F1][j1];
305 else if (olistf[i]==F0 && on2>j2)
306 temp = ppi[F2][j2];
307 else {
308 temp = ppi[olistf[i]][olist[i]];
309 if(olistf[i]==F1 && on1<=olist[i] ||
310 olistf[i]==F2 && on2<=olist[i] ||
311 *temp==0)
312 temp = null;
313 }
314 printf("%s", runetostr(buf, temp));
315 if (i == no - 1)
316 printf("\n");
317 else
318 printf("%s", sepstr);
319 }
320 }
321 }
322
323 void
324 error(char *s1, char *s2)
325 {
326 fprintf(stderr, "join: ");
327 fprintf(stderr, s1, s2);
328 fprintf(stderr, "\n");
329 exits(s1);
330 }
331
332 char *
333 getoptarg(int *argcp, char ***argvp)
334 {
335 int argc = *argcp;
336 char **argv = *argvp;
337 if(argv[1][2] != 0)
338 return &argv[1][2];
339 if(argc<=2 || argv[2][0]=='-')
340 error("incomplete option %s", argv[1]);
341 *argcp = argc-1;
342 *argvp = ++argv;
343 return argv[1];
344 }
345
346 void
347 oparse(char *s)
348 {
349 for (no = 0; no<2*NFLD && *s; no++, s++) {
350 switch(*s) {
351 case 0:
352 return;
353 case '0':
354 olistf[no] = F0;
355 break;
356 case '1':
357 case '2':
358 if(s[1] == '.' && isdigit((uchar)s[2])) {
359 olistf[no] = *s=='1'? F1: F2;
360 olist[no] = atoi(s += 2);
361 break;
362 } /* fall thru */
363 default:
364 error("invalid -o list", "");
365 }
366 if(s[1] == ',')
367 s++;
368 }
369 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.