This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
make exec keep its argument list more reliably
[perl5.git] / ext / SDBM_File / dbe.c
1 #include <stdio.h>
2 #include <string.h>
3 #ifndef VMS
4 #include <sys/file.h>
5 #include <ndbm.h>
6 #else
7 #include "file.h"
8 #include "ndbm.h"
9 #endif
10 #include <ctype.h>
11
12 /***************************************************************************\
13 **                                                                         **
14 **   Function name: getopt()                                               **
15 **   Author:        Henry Spencer, UofT                                    **
16 **   Coding date:   84/04/28                                               **
17 **                                                                         **
18 **   Description:                                                          **
19 **                                                                         **
20 **   Parses argv[] for arguments.                                          **
21 **   Works with Whitesmith's C compiler.                                   **
22 **                                                                         **
23 **   Inputs   - The number of arguments                                    **
24 **            - The base address of the array of arguments                 **
25 **            - A string listing the valid options (':' indicates an       **
26 **              argument to the preceding option is required, a ';'        **
27 **              indicates an argument to the preceding option is optional) **
28 **                                                                         **
29 **   Outputs  - Returns the next option character,                         **
30 **              '?' for non '-' arguments                                  **
31 **              or ':' when there is no more arguments.                    **
32 **                                                                         **
33 **   Side Effects + The argument to an option is pointed to by 'optarg'    **
34 **                                                                         **
35 *****************************************************************************
36 **                                                                         **
37 **   REVISION HISTORY:                                                     **
38 **                                                                         **
39 **     DATE           NAME                        DESCRIPTION              **
40 **   YY/MM/DD  ------------------   ------------------------------------   **
41 **   88/10/20  Janick Bergeron      Returns '?' on unamed arguments        **
42 **                                  returns '!' on unknown options         **
43 **                                  and 'EOF' only when exhausted.         **
44 **   88/11/18  Janick Bergeron      Return ':' when no more arguments      **
45 **   89/08/11  Janick Bergeron      Optional optarg when ';' in optstring  **
46 **                                                                         **
47 \***************************************************************************/
48
49 char *optarg;                          /* Global argument pointer. */
50
51 char
52 getopt(int argc, char **argv, char *optstring)
53 {
54         int c;
55         char *place;
56         static int optind = 0;
57         static char *scan = NULL;
58
59         optarg = NULL;
60
61         if (scan == NULL || *scan == '\0') {
62
63                 if (optind == 0)
64                         optind++;
65                 if (optind >= argc)
66                         return ':';
67
68                 optarg = place = argv[optind++];
69                 if (place[0] != '-' || place[1] == '\0')
70                         return '?';
71                 if (place[1] == '-' && place[2] == '\0')
72                         return '?';
73                 scan = place + 1;
74         }
75
76         c = *scan++;
77         place = strchr(optstring, c);
78         if (place == NULL || c == ':' || c == ';') {
79
80                 (void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
81                 scan = NULL;
82                 return '!';
83         }
84         if (*++place == ':') {
85
86                 if (*scan != '\0') {
87
88                         optarg = scan;
89                         scan = NULL;
90
91                 }
92                 else {
93
94                         if (optind >= argc) {
95
96                                 (void) fprintf(stderr, "%s: %c requires an argument\n",
97                                                argv[0], c);
98                                 return '!';
99                         }
100                         optarg = argv[optind];
101                         optind++;
102                 }
103         }
104         else if (*place == ';') {
105
106                 if (*scan != '\0') {
107
108                         optarg = scan;
109                         scan = NULL;
110
111                 }
112                 else {
113
114                         if (optind >= argc || *argv[optind] == '-')
115                                 optarg = NULL;
116                         else {
117                                 optarg = argv[optind];
118                                 optind++;
119                         }
120                 }
121         }
122         return c;
123 }
124
125
126 void
127 print_datum(datum db)
128 {
129         int i;
130
131         putchar('"');
132         for (i = 0; i < db.dsize; i++) {
133                 if (isprint((unsigned char)db.dptr[i]))
134                         putchar(db.dptr[i]);
135                 else {
136                         putchar('\\');
137                         putchar('0' + ((db.dptr[i] >> 6) & 0x07));
138                         putchar('0' + ((db.dptr[i] >> 3) & 0x07));
139                         putchar('0' + (db.dptr[i] & 0x07));
140                 }
141         }
142         putchar('"');
143 }
144
145
146 datum
147 read_datum(char *s)
148 {
149         datum db;
150         char *p;
151         int i;
152
153         db.dsize = 0;
154         db.dptr = (char *) malloc(strlen(s) * sizeof(char));
155         if (!db.dptr)
156             oops("cannot get memory");
157
158         for (p = db.dptr; *s != '\0'; p++, db.dsize++, s++) {
159                 if (*s == '\\') {
160                         if (*++s == 'n')
161                                 *p = '\n';
162                         else if (*s == 'r')
163                                 *p = '\r';
164                         else if (*s == 'f')
165                                 *p = '\f';
166                         else if (*s == 't')
167                                 *p = '\t';
168                         else if (isdigit((unsigned char)*s)
169                                  && isdigit((unsigned char)*(s + 1))
170                                  && isdigit((unsigned char)*(s + 2)))
171                         {
172                                 i = (*s++ - '0') << 6;
173                                 i |= (*s++ - '0') << 3;
174                                 i |= *s - '0';
175                                 *p = i;
176                         }
177                         else if (*s == '0')
178                                 *p = '\0';
179                         else
180                                 *p = *s;
181                 }
182                 else
183                         *p = *s;
184         }
185
186         return db;
187 }
188
189
190 char *
191 key2s(datum db)
192 {
193         char *buf;
194         char *p1, *p2;
195
196         buf = (char *) malloc((db.dsize + 1) * sizeof(char));
197         if (!buf)
198             oops("cannot get memory");
199         for (p1 = buf, p2 = db.dptr; *p2 != '\0'; *p1++ = *p2++);
200         *p1 = '\0';
201         return buf;
202 }
203
204 int
205 main(int argc, char **argv)
206 {
207         typedef enum {
208                 YOW, FETCH, STORE, DELETE, SCAN, REGEXP
209         } commands;
210         char opt;
211         int flags;
212         int giveusage = 0;
213         int verbose = 0;
214         commands what = YOW;
215         char *comarg[3];
216         int st_flag = DBM_INSERT;
217         int argn;
218         DBM *db;
219         datum key;
220         datum content;
221
222         flags = O_RDWR;
223         argn = 0;
224
225         while ((opt = getopt(argc, argv, "acdfFm:rstvx")) != ':') {
226                 switch (opt) {
227                 case 'a':
228                         what = SCAN;
229                         break;
230                 case 'c':
231                         flags |= O_CREAT;
232                         break;
233                 case 'd':
234                         what = DELETE;
235                         break;
236                 case 'f':
237                         what = FETCH;
238                         break;
239                 case 'F':
240                         what = REGEXP;
241                         break;
242                 case 'm':
243                         flags &= ~(000007);
244                         if (strcmp(optarg, "r") == 0)
245                                 flags |= O_RDONLY;
246                         else if (strcmp(optarg, "w") == 0)
247                                 flags |= O_WRONLY;
248                         else if (strcmp(optarg, "rw") == 0)
249                                 flags |= O_RDWR;
250                         else {
251                                 fprintf(stderr, "Invalid mode: \"%s\"\n", optarg);
252                                 giveusage = 1;
253                         }
254                         break;
255                 case 'r':
256                         st_flag = DBM_REPLACE;
257                         break;
258                 case 's':
259                         what = STORE;
260                         break;
261                 case 't':
262                         flags |= O_TRUNC;
263                         break;
264                 case 'v':
265                         verbose = 1;
266                         break;
267                 case 'x':
268                         flags |= O_EXCL;
269                         break;
270                 case '!':
271                         giveusage = 1;
272                         break;
273                 case '?':
274                         if (argn < 3)
275                                 comarg[argn++] = optarg;
276                         else {
277                                 fprintf(stderr, "Too many arguments.\n");
278                                 giveusage = 1;
279                         }
280                         break;
281                 }
282         }
283
284         if (giveusage || what == YOW || argn < 1) {
285                 fprintf(stderr, "Usage: %s database [-m r|w|rw] [-crtx] -a|-d|-f|-F|-s [key [content]]\n", argv[0]);
286                 exit(-1);
287         }
288
289         if ((db = dbm_open(comarg[0], flags, 0777)) == NULL) {
290                 fprintf(stderr, "Error opening database \"%s\"\n", comarg[0]);
291                 exit(-1);
292         }
293
294         if (argn > 1)
295                 key = read_datum(comarg[1]);
296         if (argn > 2)
297                 content = read_datum(comarg[2]);
298
299         switch (what) {
300
301         case SCAN:
302                 key = dbm_firstkey(db);
303                 if (dbm_error(db)) {
304                         fprintf(stderr, "Error when fetching first key\n");
305                         goto db_exit;
306                 }
307                 while (key.dptr != NULL) {
308                         content = dbm_fetch(db, key);
309                         if (dbm_error(db)) {
310                                 fprintf(stderr, "Error when fetching ");
311                                 print_datum(key);
312                                 printf("\n");
313                                 goto db_exit;
314                         }
315                         print_datum(key);
316                         printf(": ");
317                         print_datum(content);
318                         printf("\n");
319                         if (dbm_error(db)) {
320                                 fprintf(stderr, "Error when fetching next key\n");
321                                 goto db_exit;
322                         }
323                         key = dbm_nextkey(db);
324                 }
325                 break;
326
327         case REGEXP:
328                 if (argn < 2) {
329                         fprintf(stderr, "Missing regular expression.\n");
330                         goto db_exit;
331                 }
332                 if (re_comp(comarg[1])) {
333                         fprintf(stderr, "Invalid regular expression\n");
334                         goto db_exit;
335                 }
336                 key = dbm_firstkey(db);
337                 if (dbm_error(db)) {
338                         fprintf(stderr, "Error when fetching first key\n");
339                         goto db_exit;
340                 }
341                 while (key.dptr != NULL) {
342                         if (re_exec(key2s(key))) {
343                                 content = dbm_fetch(db, key);
344                                 if (dbm_error(db)) {
345                                         fprintf(stderr, "Error when fetching ");
346                                         print_datum(key);
347                                         printf("\n");
348                                         goto db_exit;
349                                 }
350                                 print_datum(key);
351                                 printf(": ");
352                                 print_datum(content);
353                                 printf("\n");
354                                 if (dbm_error(db)) {
355                                         fprintf(stderr, "Error when fetching next key\n");
356                                         goto db_exit;
357                                 }
358                         }
359                         key = dbm_nextkey(db);
360                 }
361                 break;
362
363         case FETCH:
364                 if (argn < 2) {
365                         fprintf(stderr, "Missing fetch key.\n");
366                         goto db_exit;
367                 }
368                 content = dbm_fetch(db, key);
369                 if (dbm_error(db)) {
370                         fprintf(stderr, "Error when fetching ");
371                         print_datum(key);
372                         printf("\n");
373                         goto db_exit;
374                 }
375                 if (content.dptr == NULL) {
376                         fprintf(stderr, "Cannot find ");
377                         print_datum(key);
378                         printf("\n");
379                         goto db_exit;
380                 }
381                 print_datum(key);
382                 printf(": ");
383                 print_datum(content);
384                 printf("\n");
385                 break;
386
387         case DELETE:
388                 if (argn < 2) {
389                         fprintf(stderr, "Missing delete key.\n");
390                         goto db_exit;
391                 }
392                 if (dbm_delete(db, key) || dbm_error(db)) {
393                         fprintf(stderr, "Error when deleting ");
394                         print_datum(key);
395                         printf("\n");
396                         goto db_exit;
397                 }
398                 if (verbose) {
399                         print_datum(key);
400                         printf(": DELETED\n");
401                 }
402                 break;
403
404         case STORE:
405                 if (argn < 3) {
406                         fprintf(stderr, "Missing key and/or content.\n");
407                         goto db_exit;
408                 }
409                 if (dbm_store(db, key, content, st_flag) || dbm_error(db)) {
410                         fprintf(stderr, "Error when storing ");
411                         print_datum(key);
412                         printf("\n");
413                         goto db_exit;
414                 }
415                 if (verbose) {
416                         print_datum(key);
417                         printf(": ");
418                         print_datum(content);
419                         printf(" STORED\n");
420                 }
421                 break;
422         }
423
424 db_exit:
425         dbm_clearerr(db);
426         dbm_close(db);
427         if (dbm_error(db)) {
428                 fprintf(stderr, "Error closing database \"%s\"\n", comarg[0]);
429                 exit(-1);
430         }
431 }