Make use of the card's extended capabilities.
[gnupg.git] / tests / asschk.c
blobc4a50acb3efda4ce2dbf28ea1307abf2ceaee541
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 (void)assign_to;
677 if (!opt_no_echo)
678 printf ("%s\n", arg);
681 static void
682 cmd_send (const char *assign_to, char *arg)
684 (void)assign_to;
685 if (opt_verbose)
686 fprintf (stderr, "sending `%s'\n", arg);
687 write_assuan (server_send_fd, arg);
690 static void
691 handle_status_line (char *arg)
693 char *p;
695 for (p=arg; *p && !spacep (p); p++)
697 if (*p)
699 int save = *p;
700 *p = 0;
701 inc_counter (arg);
702 *p = save;
704 else
705 inc_counter (arg);
708 static void
709 cmd_expect_ok (const char *assign_to, char *arg)
711 (void)assign_to;
712 (void)arg;
714 if (opt_verbose)
715 fprintf (stderr, "expecting OK\n");
718 char *p = read_assuan (server_recv_fd);
719 if (opt_verbose > 1)
720 fprintf (stderr, "got line `%s'\n", recv_line);
721 if (recv_type == LINE_STAT)
722 handle_status_line (p);
724 while (recv_type != LINE_OK && recv_type != LINE_ERR);
725 if (recv_type != LINE_OK)
726 die ("expected OK but got `%s'", recv_line);
729 static void
730 cmd_expect_err (const char *assign_to, char *arg)
732 (void)assign_to;
733 (void)arg;
735 if (opt_verbose)
736 fprintf (stderr, "expecting ERR\n");
739 char *p = read_assuan (server_recv_fd);
740 if (opt_verbose > 1)
741 fprintf (stderr, "got line `%s'\n", recv_line);
742 if (recv_type == LINE_STAT)
743 handle_status_line (p);
745 while (recv_type != LINE_OK && recv_type != LINE_ERR);
746 if (recv_type != LINE_ERR)
747 die ("expected ERR but got `%s'", recv_line);
750 static void
751 cmd_count_status (const char *assign_to, char *arg)
753 char *p;
755 if (!*assign_to || !*arg)
756 die ("syntax error: count-status requires an argument and a variable");
758 for (p=arg; *p && !spacep (p); p++)
760 if (*p)
762 for (*p++ = 0; spacep (p); p++)
764 if (*p)
765 die ("cmpfiles: syntax error");
767 set_type_var (assign_to, arg, VARTYPE_COUNTER);
770 static void
771 cmd_openfile (const char *assign_to, char *arg)
773 int fd;
774 char numbuf[20];
777 fd = open (arg, O_RDONLY);
778 while (fd == -1 && errno == EINTR);
779 if (fd == -1)
780 die ("error opening `%s': %s", arg, strerror (errno));
782 sprintf (numbuf, "%d", fd);
783 set_type_var (assign_to, numbuf, VARTYPE_FD);
786 static void
787 cmd_createfile (const char *assign_to, char *arg)
789 int fd;
790 char numbuf[20];
793 fd = open (arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
794 while (fd == -1 && errno == EINTR);
795 if (fd == -1)
796 die ("error creating `%s': %s", arg, strerror (errno));
798 sprintf (numbuf, "%d", fd);
799 set_type_var (assign_to, numbuf, VARTYPE_FD);
803 static void
804 cmd_pipeserver (const char *assign_to, char *arg)
806 (void)assign_to;
808 if (!*arg)
809 die ("syntax error: servername missing");
811 start_server (arg);
815 static void
816 cmd_quit_if(const char *assign_to, char *arg)
818 (void)assign_to;
820 if (eval_boolean (arg))
821 exit (0);
824 static void
825 cmd_fail_if(const char *assign_to, char *arg)
827 (void)assign_to;
829 if (eval_boolean (arg))
830 exit (1);
834 static void
835 cmd_cmpfiles (const char *assign_to, char *arg)
837 char *p = arg;
838 char *second;
839 FILE *fp1, *fp2;
840 char buffer1[2048]; /* note: both must be of equal size. */
841 char buffer2[2048];
842 size_t nread1, nread2;
843 int rc = 0;
845 set_var (assign_to, "0");
846 for (p=arg; *p && !spacep (p); p++)
848 if (!*p)
849 die ("cmpfiles: syntax error");
850 for (*p++ = 0; spacep (p); p++)
852 second = p;
853 for (; *p && !spacep (p); p++)
855 if (*p)
857 for (*p++ = 0; spacep (p); p++)
859 if (*p)
860 die ("cmpfiles: syntax error");
863 fp1 = fopen (arg, "rb");
864 if (!fp1)
866 err ("can't open `%s': %s", arg, strerror (errno));
867 return;
869 fp2 = fopen (second, "rb");
870 if (!fp2)
872 err ("can't open `%s': %s", second, strerror (errno));
873 fclose (fp1);
874 return;
876 while ( (nread1 = fread (buffer1, 1, sizeof buffer1, fp1)))
878 if (ferror (fp1))
879 break;
880 nread2 = fread (buffer2, 1, sizeof buffer2, fp2);
881 if (ferror (fp2))
882 break;
883 if (nread1 != nread2 || memcmp (buffer1, buffer2, nread1))
885 rc = 1;
886 break;
889 if (feof (fp1) && feof (fp2) && !rc)
891 if (opt_verbose)
892 err ("files match");
893 set_var (assign_to, "1");
895 else if (!rc)
896 err ("cmpfiles: read error: %s", strerror (errno));
897 else
898 err ("cmpfiles: mismatch");
899 fclose (fp1);
900 fclose (fp2);
903 static void
904 cmd_getenv (const char *assign_to, char *arg)
906 const char *s;
907 s = *arg? getenv (arg):"";
908 set_var (assign_to, s? s:"");
914 /* Process the current script line LINE. */
915 static int
916 interpreter (char *line)
918 static struct {
919 const char *name;
920 void (*fnc)(const char*, char*);
921 } cmdtbl[] = {
922 { "let" , cmd_let },
923 { "echo" , cmd_echo },
924 { "send" , cmd_send },
925 { "expect-ok" , cmd_expect_ok },
926 { "expect-err", cmd_expect_err },
927 { "count-status", cmd_count_status },
928 { "openfile" , cmd_openfile },
929 { "createfile", cmd_createfile },
930 { "pipeserver", cmd_pipeserver },
931 { "quit" , NULL },
932 { "quit-if" , cmd_quit_if },
933 { "fail-if" , cmd_fail_if },
934 { "cmpfiles" , cmd_cmpfiles },
935 { "getenv" , cmd_getenv },
936 { NULL }
938 char *p, *save_p;
939 int i, save_c;
940 char *stmt = NULL;
941 char *assign_to = NULL;
942 char *must_free = NULL;
944 for ( ;spacep (line); line++)
946 if (!*line || *line == '#')
947 return 0; /* empty or comment */
948 p = expand_line (line);
949 if (p)
951 must_free = p;
952 line = p;
953 for ( ;spacep (line); line++)
955 if (!*line || *line == '#')
957 free (must_free);
958 return 0; /* empty or comment */
961 for (p=line; *p && !spacep (p) && *p != '='; p++)
963 if (*p == '=')
965 *p = 0;
966 assign_to = line;
968 else if (*p)
970 for (*p++ = 0; spacep (p); p++)
972 if (*p == '=')
973 assign_to = line;
975 if (!*line)
976 die ("syntax error");
977 stmt = line;
978 save_c = 0;
979 save_p = NULL;
980 if (assign_to)
981 { /* this is an assignment */
982 for (p++; spacep (p); p++)
984 if (!*p)
986 unset_var (assign_to);
987 free (must_free);
988 return 0;
990 stmt = p;
991 for (; *p && !spacep (p); p++)
993 if (*p)
995 save_p = p;
996 save_c = *p;
997 for (*p++ = 0; spacep (p); p++)
1001 for (i=0; cmdtbl[i].name && strcmp (stmt, cmdtbl[i].name); i++)
1003 if (!cmdtbl[i].name)
1005 if (!assign_to)
1006 die ("invalid statement `%s'\n", stmt);
1007 if (save_p)
1008 *save_p = save_c;
1009 set_var (assign_to, stmt);
1010 free (must_free);
1011 return 0;
1014 if (cmdtbl[i].fnc)
1015 cmdtbl[i].fnc (assign_to, p);
1016 free (must_free);
1017 return cmdtbl[i].fnc? 0:1;
1023 main (int argc, char **argv)
1025 char buffer[2048];
1026 char *p, *pend;
1028 if (!argc)
1029 invocation_name = "asschk";
1030 else
1032 invocation_name = *argv++;
1033 argc--;
1034 p = strrchr (invocation_name, '/');
1035 if (p)
1036 invocation_name = p+1;
1040 set_var ("?","1"); /* defaults to true */
1042 for (; argc; argc--, argv++)
1044 p = *argv;
1045 if (*p != '-')
1046 break;
1047 if (!strcmp (p, "--verbose"))
1048 opt_verbose++;
1049 else if (!strcmp (p, "--no-echo"))
1050 opt_no_echo++;
1051 else if (*p == '-' && p[1] == 'D')
1053 p += 2;
1054 pend = strchr (p, '=');
1055 if (pend)
1057 int tmp = *pend;
1058 *pend = 0;
1059 set_var (p, pend+1);
1060 *pend = tmp;
1062 else
1063 set_var (p, "1");
1065 else if (*p == '-' && p[1] == '-' && !p[2])
1067 argc--; argv++;
1068 break;
1070 else
1071 break;
1073 if (argc)
1074 die ("usage: asschk [--verbose] {-D<name>[=<value>]}");
1077 while (fgets (buffer, sizeof buffer, stdin))
1079 p = strchr (buffer,'\n');
1080 if (!p)
1081 die ("incomplete script line");
1082 *p = 0;
1083 if (interpreter (buffer))
1084 break;
1085 fflush (stdout);
1087 return 0;