2008-06-13 Marcus Brinkmann <marcus@ulysses.g10code.com>
[gnupg.git] / tests / asschk.c
blob176fcac6f00e0a574450a4e3bbba1d974a5bcba5
1 /* asschk.c - Assuan Server Checker
2 * Copyright (C) 2002 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 /* This is a simple stand-alone Assuan server test program. We don't
21 want to use the assuan library because we don't want to hide errors
22 in that library.
24 The script language is line based. Empty lines or lines containing
25 only white spaces are ignored, line with a hash sign as first non
26 white space character are treated as comments.
28 A simple macro mechanism is implemnted. Macros are expanded before
29 a line is processed but after comment processing. Macros are only
30 expanded once and non existing macros expand to the empty string.
31 A macro is dereferenced by prefixing its name with a dollar sign;
32 the end of the name is currently indicated by a white space, a
33 dollar sign or a slash. To use a dollor sign verbatim, double it.
35 A macro is assigned by prefixing a statement with the macro name
36 and an equal sign. The value is assigned verbatim if it does not
37 resemble a command, otherwise the return value of the command will
38 get assigned. The command "let" may be used to assign values
39 unambigiously and it should be used if the value starts with a
40 letter.
42 Conditions are not yes implemented except for a simple evaluation
43 which yields false for an empty string or the string "0". The
44 result may be negated by prefixing with a '!'.
46 The general syntax of a command is:
48 [<name> =] <statement> [<args>]
50 If NAME is not specifed but the statement returns a value it is
51 assigned to the name "?" so that it can be referenced using "$?".
52 The following commands are implemented:
54 let <value>
55 Return VALUE.
57 echo <value>
58 Print VALUE.
60 openfile <filename>
61 Open file FILENAME for read access and return the file descriptor.
63 createfile <filename>
64 Create file FILENAME, open for write access and return the file
65 descriptor.
67 pipeserver <program>
68 Connect to the Assuan server PROGRAM.
70 send <line>
71 Send LINE to the server.
73 expect-ok
74 Expect an OK response from the server. Status and data out put
75 is ignored.
77 expect-err
78 Expect an ERR response from the server. Status and data out put
79 is ignored.
81 count-status <code>
82 Initialize the assigned variable to 0 and assign it as an counter for
83 status code CODE. This command must be called with an assignment.
85 quit
86 Terminate the process.
88 quit-if <condition>
89 Terminate the process if CONDITION evaluates to true.
91 fail-if <condition>
92 Terminate the process with an exit code of 1 if CONDITION
93 evaluates to true.
95 cmpfiles <first> <second>
96 Returns true when the content of the files FIRST and SECOND match.
98 getenv <name>
99 Return the value of the environment variable NAME.
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <string.h>
106 #include <errno.h>
107 #include <stdarg.h>
108 #include <assert.h>
109 #include <unistd.h>
110 #include <fcntl.h>
112 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
113 # define ATTR_PRINTF(f,a) __attribute__ ((format (printf,f,a)))
114 #else
115 # define ATTR_PRINTF(f,a)
116 #endif
118 #if __STDC_VERSION__ < 199901L
119 # if __GNUC__ >= 2
120 # define __func__ __FUNCTION__
121 # else
122 /* Let's try our luck here. Some systems may provide __func__ without
123 providing __STDC_VERSION__ 199901L. */
124 # if 0
125 # define __func__ "<unknown>"
126 # endif
127 # endif
128 #endif
130 #define spacep(p) (*(p) == ' ' || *(p) == '\t')
132 #define MAX_LINELEN 2048
134 typedef enum {
135 LINE_OK = 0,
136 LINE_ERR,
137 LINE_STAT,
138 LINE_DATA,
139 LINE_END,
140 } LINETYPE;
142 typedef enum {
143 VARTYPE_SIMPLE = 0,
144 VARTYPE_FD,
145 VARTYPE_COUNTER
146 } VARTYPE;
149 struct variable_s {
150 struct variable_s *next;
151 VARTYPE type;
152 unsigned int count;
153 char *value;
154 char name[1];
156 typedef struct variable_s *VARIABLE;
159 static void die (const char *format, ...) ATTR_PRINTF(1,2);
162 /* Name of this program to be printed in error messages. */
163 static const char *invocation_name;
165 /* Talk a bit about what is going on. */
166 static int opt_verbose;
168 /* Option to ignore the echo command. */
169 static int opt_no_echo;
171 /* File descriptors used to communicate with the current server. */
172 static int server_send_fd = -1;
173 static int server_recv_fd = -1;
175 /* The Assuan protocol limits the line length to 1024, so we can
176 safely use a (larger) buffer. The buffer is filled using the
177 read_assuan(). */
178 static char recv_line[MAX_LINELEN];
179 /* Tell the status of the current line. */
180 static LINETYPE recv_type;
182 /* This is our variable storage. */
183 static VARIABLE variable_list;
186 static void
187 die (const char *format, ...)
189 va_list arg_ptr;
191 fflush (stdout);
192 fprintf (stderr, "%s: ", invocation_name);
194 va_start (arg_ptr, format);
195 vfprintf (stderr, format, arg_ptr);
196 va_end (arg_ptr);
197 putc ('\n', stderr);
199 exit (1);
202 #define die(format, args...) (die) ("%s: " format, __func__ , ##args)
204 static void
205 err (const char *format, ...)
207 va_list arg_ptr;
209 fflush (stdout);
210 fprintf (stderr, "%s: ", invocation_name);
212 va_start (arg_ptr, format);
213 vfprintf (stderr, format, arg_ptr);
214 va_end (arg_ptr);
215 putc ('\n', stderr);
218 static void *
219 xmalloc (size_t n)
221 void *p = malloc (n);
222 if (!p)
223 die ("out of core");
224 return p;
227 static void *
228 xcalloc (size_t n, size_t m)
230 void *p = calloc (n, m);
231 if (!p)
232 die ("out of core");
233 return p;
236 static char *
237 xstrdup (const char *s)
239 char *p = xmalloc (strlen (s)+1);
240 strcpy (p, s);
241 return p;
245 /* Write LENGTH bytes from BUFFER to FD. */
246 static int
247 writen (int fd, const char *buffer, size_t length)
249 while (length)
251 int nwritten = write (fd, buffer, length);
253 if (nwritten < 0)
255 if (errno == EINTR)
256 continue;
257 return -1; /* write error */
259 length -= nwritten;
260 buffer += nwritten;
262 return 0; /* okay */
268 /* Assuan specific stuff. */
270 /* Read a line from FD, store it in the global recv_line, analyze the
271 type and store that in recv_type. The function terminates on a
272 communication error. Returns a pointer into the inputline to the
273 first byte of the arguments. The parsing is very strict to match
274 exaclty what we want to send. */
275 static char *
276 read_assuan (int fd)
278 /* FIXME: For general robustness, the pending stuff needs to be
279 associated with FD. */
280 static char pending[MAX_LINELEN];
281 static size_t pending_len;
282 size_t nleft = sizeof recv_line;
283 char *buf = recv_line;
284 char *p;
286 while (nleft > 0)
288 int n;
290 if (pending_len)
292 if (pending_len >= nleft)
293 die ("received line too large");
294 memcpy (buf, pending, pending_len);
295 n = pending_len;
296 pending_len = 0;
298 else
302 n = read (fd, buf, nleft);
304 while (n < 0 && errno == EINTR);
307 if (opt_verbose && n >= 0 )
309 int i;
311 printf ("%s: read \"", __func__);
312 for (i = 0; i < n; i ++)
313 putc (buf[i], stdout);
314 printf ("\"\n");
317 if (n < 0)
318 die ("reading fd %d failed: %s", fd, strerror (errno));
319 else if (!n)
320 die ("received incomplete line on fd %d", fd);
321 p = buf;
322 nleft -= n;
323 buf += n;
325 for (; n && *p != '\n'; n--, p++)
327 if (n)
329 if (n>1)
331 n--;
332 memcpy (pending, p + 1, n);
333 pending_len = n;
335 *p = '\0';
336 break;
339 if (!nleft)
340 die ("received line too large");
342 p = recv_line;
343 if (p[0] == 'O' && p[1] == 'K' && (p[2] == ' ' || !p[2]))
345 recv_type = LINE_OK;
346 p += 3;
348 else if (p[0] == 'E' && p[1] == 'R' && p[2] == 'R'
349 && (p[3] == ' ' || !p[3]))
351 recv_type = LINE_ERR;
352 p += 4;
354 else if (p[0] == 'S' && (p[1] == ' ' || !p[1]))
356 recv_type = LINE_STAT;
357 p += 2;
359 else if (p[0] == 'D' && p[1] == ' ')
361 recv_type = LINE_DATA;
362 p += 2;
364 else if (p[0] == 'E' && p[1] == 'N' && p[2] == 'D' && !p[3])
366 recv_type = LINE_END;
367 p += 3;
369 else
370 die ("invalid line type (%.5s)", p);
372 return p;
375 /* Write LINE to the server using FD. It is expected that the line
376 contains the terminating linefeed as last character. */
377 static void
378 write_assuan (int fd, const char *line)
380 char buffer[1026];
381 size_t n = strlen (line);
383 if (n > 1024)
384 die ("line too long for Assuan protocol");
385 strcpy (buffer, line);
386 if (!n || buffer[n-1] != '\n')
387 buffer[n++] = '\n';
389 if (writen (fd, buffer, n))
390 die ("sending line (\"%s\") to %d failed: %s", buffer, fd,
391 strerror (errno));
395 /* Start the server with path PGMNAME and connect its stdout and
396 strerr to a newly created pipes; the file descriptors are then
397 store in the gloabl variables SERVER_SEND_FD and
398 SERVER_RECV_FD. The initial handcheck is performed.*/
399 static void
400 start_server (const char *pgmname)
402 int rp[2];
403 int wp[2];
404 pid_t pid;
406 if (pipe (rp) < 0)
407 die ("pipe creation failed: %s", strerror (errno));
408 if (pipe (wp) < 0)
409 die ("pipe creation failed: %s", strerror (errno));
411 fflush (stdout);
412 fflush (stderr);
413 pid = fork ();
414 if (pid < 0)
415 die ("fork failed");
417 if (!pid)
419 const char *arg0;
421 arg0 = strrchr (pgmname, '/');
422 if (arg0)
423 arg0++;
424 else
425 arg0 = pgmname;
427 if (wp[0] != STDIN_FILENO)
429 if (dup2 (wp[0], STDIN_FILENO) == -1)
430 die ("dup2 failed in child: %s", strerror (errno));
431 close (wp[0]);
433 if (rp[1] != STDOUT_FILENO)
435 if (dup2 (rp[1], STDOUT_FILENO) == -1)
436 die ("dup2 failed in child: %s", strerror (errno));
437 close (rp[1]);
439 if (!opt_verbose)
441 int fd = open ("/dev/null", O_WRONLY);
442 if (fd == -1)
443 die ("can't open `/dev/null': %s", strerror (errno));
444 if (dup2 (fd, STDERR_FILENO) == -1)
445 die ("dup2 failed in child: %s", strerror (errno));
446 close (fd);
449 close (wp[1]);
450 close (rp[0]);
451 execl (pgmname, arg0, "--server", NULL);
452 die ("exec failed for `%s': %s", pgmname, strerror (errno));
454 close (wp[0]);
455 close (rp[1]);
456 server_send_fd = wp[1];
457 server_recv_fd = rp[0];
459 read_assuan (server_recv_fd);
460 if (recv_type != LINE_OK)
461 die ("no greating message");
468 /* Script intepreter. */
470 static void
471 unset_var (const char *name)
473 VARIABLE var;
475 for (var=variable_list; var && strcmp (var->name, name); var = var->next)
477 if (!var)
478 return;
479 /* fprintf (stderr, "unsetting `%s'\n", name); */
481 if (var->type == VARTYPE_FD && var->value)
483 int fd;
485 fd = atoi (var->value);
486 if (fd != -1 && fd != 0 && fd != 1 && fd != 2)
487 close (fd);
490 free (var->value);
491 var->value = NULL;
492 var->type = 0;
493 var->count = 0;
497 static void
498 set_type_var (const char *name, const char *value, VARTYPE type)
500 VARIABLE var;
502 if (!name)
503 name = "?";
504 for (var=variable_list; var && strcmp (var->name, name); var = var->next)
506 if (!var)
508 var = xcalloc (1, sizeof *var + strlen (name));
509 strcpy (var->name, name);
510 var->next = variable_list;
511 variable_list = var;
513 else
514 free (var->value);
516 if (var->type == VARTYPE_FD && var->value)
518 int fd;
520 fd = atoi (var->value);
521 if (fd != -1 && fd != 0 && fd != 1 && fd != 2)
522 close (fd);
525 var->type = type;
526 var->count = 0;
527 if (var->type == VARTYPE_COUNTER)
529 /* We need some extra sapce as scratch area for get_var. */
530 var->value = xmalloc (strlen (value) + 1 + 20);
531 strcpy (var->value, value);
533 else
534 var->value = xstrdup (value);
537 static void
538 set_var (const char *name, const char *value)
540 set_type_var (name, value, 0);
544 static const char *
545 get_var (const char *name)
547 VARIABLE var;
549 for (var=variable_list; var && strcmp (var->name, name); var = var->next)
551 if (!var)
552 return NULL;
553 if (var->type == VARTYPE_COUNTER && var->value)
554 { /* Use the scratch space allocated by set_var. */
555 char *p = var->value + strlen(var->value)+1;
556 sprintf (p, "%u", var->count);
557 return p;
559 else
560 return var->value;
564 /* Incremente all counter type variables with NAME in their VALUE. */
565 static void
566 inc_counter (const char *name)
568 VARIABLE var;
570 if (!*name)
571 return;
572 for (var=variable_list; var; var = var->next)
574 if (var->type == VARTYPE_COUNTER
575 && var->value && !strcmp (var->value, name))
576 var->count++;
581 /* Expand variables in LINE and return a new allocated buffer if
582 required. The function might modify LINE if the expanded version
583 fits into it. */
584 static char *
585 expand_line (char *buffer)
587 char *line = buffer;
588 char *p, *pend;
589 const char *value;
590 size_t valuelen, n;
591 char *result = NULL;
593 while (*line)
595 p = strchr (line, '$');
596 if (!p)
597 return result; /* nothing more to expand */
599 if (p[1] == '$') /* quoted */
601 memmove (p, p+1, strlen (p+1)+1);
602 line = p + 1;
603 continue;
605 for (pend=p+1; *pend && !spacep (pend)
606 && *pend != '$' && *pend != '/'; pend++)
608 if (*pend)
610 int save = *pend;
611 *pend = 0;
612 value = get_var (p+1);
613 *pend = save;
615 else
616 value = get_var (p+1);
617 if (!value)
618 value = "";
619 valuelen = strlen (value);
620 if (valuelen <= pend - p)
622 memcpy (p, value, valuelen);
623 p += valuelen;
624 n = pend - p;
625 if (n)
626 memmove (p, p+n, strlen (p+n)+1);
627 line = p;
629 else
631 char *src = result? result : buffer;
632 char *dst;
634 dst = xmalloc (strlen (src) + valuelen + 1);
635 n = p - src;
636 memcpy (dst, src, n);
637 memcpy (dst + n, value, valuelen);
638 n += valuelen;
639 strcpy (dst + n, pend);
640 line = dst + n;
641 free (result);
642 result = dst;
645 return result;
649 /* Evaluate COND and return the result. */
650 static int
651 eval_boolean (const char *cond)
653 int true = 1;
655 for ( ; *cond == '!'; cond++)
656 true = !true;
657 if (!*cond || (*cond == '0' && !cond[1]))
658 return !true;
659 return true;
666 static void
667 cmd_let (const char *assign_to, char *arg)
669 set_var (assign_to, arg);
673 static void
674 cmd_echo (const char *assign_to, char *arg)
676 if (!opt_no_echo)
677 printf ("%s\n", arg);
680 static void
681 cmd_send (const char *assign_to, char *arg)
683 if (opt_verbose)
684 fprintf (stderr, "sending `%s'\n", arg);
685 write_assuan (server_send_fd, arg);
688 static void
689 handle_status_line (char *arg)
691 char *p;
693 for (p=arg; *p && !spacep (p); p++)
695 if (*p)
697 int save = *p;
698 *p = 0;
699 inc_counter (arg);
700 *p = save;
702 else
703 inc_counter (arg);
706 static void
707 cmd_expect_ok (const char *assign_to, char *arg)
709 if (opt_verbose)
710 fprintf (stderr, "expecting OK\n");
713 char *p = read_assuan (server_recv_fd);
714 if (opt_verbose > 1)
715 fprintf (stderr, "got line `%s'\n", recv_line);
716 if (recv_type == LINE_STAT)
717 handle_status_line (p);
719 while (recv_type != LINE_OK && recv_type != LINE_ERR);
720 if (recv_type != LINE_OK)
721 die ("expected OK but got `%s'", recv_line);
724 static void
725 cmd_expect_err (const char *assign_to, char *arg)
727 if (opt_verbose)
728 fprintf (stderr, "expecting ERR\n");
731 char *p = read_assuan (server_recv_fd);
732 if (opt_verbose > 1)
733 fprintf (stderr, "got line `%s'\n", recv_line);
734 if (recv_type == LINE_STAT)
735 handle_status_line (p);
737 while (recv_type != LINE_OK && recv_type != LINE_ERR);
738 if (recv_type != LINE_ERR)
739 die ("expected ERR but got `%s'", recv_line);
742 static void
743 cmd_count_status (const char *assign_to, char *arg)
745 char *p;
747 if (!*assign_to || !*arg)
748 die ("syntax error: count-status requires an argument and a variable");
750 for (p=arg; *p && !spacep (p); p++)
752 if (*p)
754 for (*p++ = 0; spacep (p); p++)
756 if (*p)
757 die ("cmpfiles: syntax error");
759 set_type_var (assign_to, arg, VARTYPE_COUNTER);
762 static void
763 cmd_openfile (const char *assign_to, char *arg)
765 int fd;
766 char numbuf[20];
769 fd = open (arg, O_RDONLY);
770 while (fd == -1 && errno == EINTR);
771 if (fd == -1)
772 die ("error opening `%s': %s", arg, strerror (errno));
774 sprintf (numbuf, "%d", fd);
775 set_type_var (assign_to, numbuf, VARTYPE_FD);
778 static void
779 cmd_createfile (const char *assign_to, char *arg)
781 int fd;
782 char numbuf[20];
785 fd = open (arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
786 while (fd == -1 && errno == EINTR);
787 if (fd == -1)
788 die ("error creating `%s': %s", arg, strerror (errno));
790 sprintf (numbuf, "%d", fd);
791 set_type_var (assign_to, numbuf, VARTYPE_FD);
795 static void
796 cmd_pipeserver (const char *assign_to, char *arg)
798 if (!*arg)
799 die ("syntax error: servername missing");
801 start_server (arg);
805 static void
806 cmd_quit_if(const char *assign_to, char *arg)
808 if (eval_boolean (arg))
809 exit (0);
812 static void
813 cmd_fail_if(const char *assign_to, char *arg)
815 if (eval_boolean (arg))
816 exit (1);
820 static void
821 cmd_cmpfiles (const char *assign_to, char *arg)
823 char *p = arg;
824 char *second;
825 FILE *fp1, *fp2;
826 char buffer1[2048]; /* note: both must be of equal size. */
827 char buffer2[2048];
828 size_t nread1, nread2;
829 int rc = 0;
831 set_var (assign_to, "0");
832 for (p=arg; *p && !spacep (p); p++)
834 if (!*p)
835 die ("cmpfiles: syntax error");
836 for (*p++ = 0; spacep (p); p++)
838 second = p;
839 for (; *p && !spacep (p); p++)
841 if (*p)
843 for (*p++ = 0; spacep (p); p++)
845 if (*p)
846 die ("cmpfiles: syntax error");
849 fp1 = fopen (arg, "rb");
850 if (!fp1)
852 err ("can't open `%s': %s", arg, strerror (errno));
853 return;
855 fp2 = fopen (second, "rb");
856 if (!fp2)
858 err ("can't open `%s': %s", second, strerror (errno));
859 fclose (fp1);
860 return;
862 while ( (nread1 = fread (buffer1, 1, sizeof buffer1, fp1)))
864 if (ferror (fp1))
865 break;
866 nread2 = fread (buffer2, 1, sizeof buffer2, fp2);
867 if (ferror (fp2))
868 break;
869 if (nread1 != nread2 || memcmp (buffer1, buffer2, nread1))
871 rc = 1;
872 break;
875 if (feof (fp1) && feof (fp2) && !rc)
877 if (opt_verbose)
878 err ("files match");
879 set_var (assign_to, "1");
881 else if (!rc)
882 err ("cmpfiles: read error: %s", strerror (errno));
883 else
884 err ("cmpfiles: mismatch");
885 fclose (fp1);
886 fclose (fp2);
889 static void
890 cmd_getenv (const char *assign_to, char *arg)
892 const char *s;
893 s = *arg? getenv (arg):"";
894 set_var (assign_to, s? s:"");
900 /* Process the current script line LINE. */
901 static int
902 interpreter (char *line)
904 static struct {
905 const char *name;
906 void (*fnc)(const char*, char*);
907 } cmdtbl[] = {
908 { "let" , cmd_let },
909 { "echo" , cmd_echo },
910 { "send" , cmd_send },
911 { "expect-ok" , cmd_expect_ok },
912 { "expect-err", cmd_expect_err },
913 { "count-status", cmd_count_status },
914 { "openfile" , cmd_openfile },
915 { "createfile", cmd_createfile },
916 { "pipeserver", cmd_pipeserver },
917 { "quit" , NULL },
918 { "quit-if" , cmd_quit_if },
919 { "fail-if" , cmd_fail_if },
920 { "cmpfiles" , cmd_cmpfiles },
921 { "getenv" , cmd_getenv },
922 { NULL }
924 char *p, *save_p;
925 int i, save_c;
926 char *stmt = NULL;
927 char *assign_to = NULL;
928 char *must_free = NULL;
930 for ( ;spacep (line); line++)
932 if (!*line || *line == '#')
933 return 0; /* empty or comment */
934 p = expand_line (line);
935 if (p)
937 must_free = p;
938 line = p;
939 for ( ;spacep (line); line++)
941 if (!*line || *line == '#')
943 free (must_free);
944 return 0; /* empty or comment */
947 for (p=line; *p && !spacep (p) && *p != '='; p++)
949 if (*p == '=')
951 *p = 0;
952 assign_to = line;
954 else if (*p)
956 for (*p++ = 0; spacep (p); p++)
958 if (*p == '=')
959 assign_to = line;
961 if (!*line)
962 die ("syntax error");
963 stmt = line;
964 save_c = 0;
965 save_p = NULL;
966 if (assign_to)
967 { /* this is an assignment */
968 for (p++; spacep (p); p++)
970 if (!*p)
972 unset_var (assign_to);
973 free (must_free);
974 return 0;
976 stmt = p;
977 for (; *p && !spacep (p); p++)
979 if (*p)
981 save_p = p;
982 save_c = *p;
983 for (*p++ = 0; spacep (p); p++)
987 for (i=0; cmdtbl[i].name && strcmp (stmt, cmdtbl[i].name); i++)
989 if (!cmdtbl[i].name)
991 if (!assign_to)
992 die ("invalid statement `%s'\n", stmt);
993 if (save_p)
994 *save_p = save_c;
995 set_var (assign_to, stmt);
996 free (must_free);
997 return 0;
1000 if (cmdtbl[i].fnc)
1001 cmdtbl[i].fnc (assign_to, p);
1002 free (must_free);
1003 return cmdtbl[i].fnc? 0:1;
1009 main (int argc, char **argv)
1011 char buffer[2048];
1012 char *p, *pend;
1014 if (!argc)
1015 invocation_name = "asschk";
1016 else
1018 invocation_name = *argv++;
1019 argc--;
1020 p = strrchr (invocation_name, '/');
1021 if (p)
1022 invocation_name = p+1;
1026 set_var ("?","1"); /* defaults to true */
1028 for (; argc; argc--, argv++)
1030 p = *argv;
1031 if (*p != '-')
1032 break;
1033 if (!strcmp (p, "--verbose"))
1034 opt_verbose++;
1035 else if (!strcmp (p, "--no-echo"))
1036 opt_no_echo++;
1037 else if (*p == '-' && p[1] == 'D')
1039 p += 2;
1040 pend = strchr (p, '=');
1041 if (pend)
1043 int tmp = *pend;
1044 *pend = 0;
1045 set_var (p, pend+1);
1046 *pend = tmp;
1048 else
1049 set_var (p, "1");
1051 else if (*p == '-' && p[1] == '-' && !p[2])
1053 argc--; argv++;
1054 break;
1056 else
1057 break;
1059 if (argc)
1060 die ("usage: asschk [--verbose] {-D<name>[=<value>]}");
1063 while (fgets (buffer, sizeof buffer, stdin))
1065 p = strchr (buffer,'\n');
1066 if (!p)
1067 die ("incomplete script line");
1068 *p = 0;
1069 if (interpreter (buffer))
1070 break;
1071 fflush (stdout);
1073 return 0;