2005-10-02 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / tests / asschk.c
blob83a8ca5afef34974f54ff1719c28a6c9b53bf735
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 2 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 /* This is a simple stand-alone Assuan server test program. We don't
22 want to use the assuan library because we don't want to hide errors
23 in that library.
25 The script language is line based. Empty lines or lines containing
26 only white spaces are ignored, line with a hash sign as first non
27 white space character are treated as comments.
29 A simple macro mechanism is implemnted. Macros are expanded before
30 a line is processed but after comment processing. Macros are only
31 expanded once and non existing macros expand to the empty string.
32 A macro is dereferenced by prefixing its name with a dollar sign;
33 the end of the name is currently indicated by a white space, a
34 dollar sign or a slash. To use a dollor sign verbatim, double it.
36 A macro is assigned by prefixing a statement with the macro name
37 and an equal sign. The value is assigned verbatim if it does not
38 resemble a command, otherwise the return value of the command will
39 get assigned. The command "let" may be used to assign values
40 unambigiously and it should be used if the value starts with a
41 letter.
43 Conditions are not yes implemented except for a simple evaluation
44 which yields false for an empty string or the string "0". The
45 result may be negated by prefixing with a '!'.
47 The general syntax of a command is:
49 [<name> =] <statement> [<args>]
51 If NAME is not specifed but the statement returns a value it is
52 assigned to the name "?" so that it can be referenced using "$?".
53 The following commands are implemented:
55 let <value>
56 Return VALUE.
58 echo <value>
59 Print VALUE.
61 openfile <filename>
62 Open file FILENAME for read access and retrun the file descriptor.
64 createfile <filename>
65 Create file FILENAME, open for write access and retrun the file
66 descriptor.
68 pipeserver <program>
69 Connect to the Assuan server PROGRAM.
71 send <line>
72 Send LINE to the server.
74 expect-ok
75 Expect an OK response from the server. Status and data out put
76 is ignored.
78 expect-err
79 Expect an ERR response from the server. Status and data out put
80 is ignored.
82 count-status <code>
83 Initialize the assigned variable to 0 and assign it as an counter for
84 status code CODE. This command must be called with an assignment.
86 quit
87 Terminate the process.
89 quit-if <condition>
90 Terminate the process if CONDITION evaluates to true.
92 fail-if <condition>
93 Terminate the process with an exit code of 1 if CONDITION
94 evaluates to true.
96 cmpfiles <first> <second>
97 Returns true when the content of the files FIRST and SECOND match.
99 getenv <name>
100 Return the value of the environment variable NAME.
104 #include <stdio.h>
105 #include <stdlib.h>
106 #include <string.h>
107 #include <errno.h>
108 #include <stdarg.h>
109 #include <assert.h>
110 #include <unistd.h>
111 #include <fcntl.h>
113 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
114 # define ATTR_PRINTF(f,a) __attribute__ ((format (printf,f,a)))
115 #else
116 # define ATTR_PRINTF(f,a)
117 #endif
119 #define spacep(p) (*(p) == ' ' || *(p) == '\t')
121 #define MAX_LINELEN 2048
123 typedef enum {
124 LINE_OK = 0,
125 LINE_ERR,
126 LINE_STAT,
127 LINE_DATA,
128 LINE_END,
129 } LINETYPE;
131 typedef enum {
132 VARTYPE_SIMPLE = 0,
133 VARTYPE_FD,
134 VARTYPE_COUNTER
135 } VARTYPE;
138 struct variable_s {
139 struct variable_s *next;
140 VARTYPE type;
141 unsigned int count;
142 char *value;
143 char name[1];
145 typedef struct variable_s *VARIABLE;
148 static void die (const char *format, ...) ATTR_PRINTF(1,2);
151 /* Name of this program to be printed in error messages. */
152 static const char *invocation_name;
154 /* Talk a bit about what is going on. */
155 static int opt_verbose;
157 /* Option to ignore the echo command. */
158 static int opt_no_echo;
160 /* File descriptors used to communicate with the current server. */
161 static int server_send_fd = -1;
162 static int server_recv_fd = -1;
164 /* The Assuan protocol limits the line length to 1024, so we can
165 safely use a (larger) buffer. The buffer is filled using the
166 read_assuan(). */
167 static char recv_line[MAX_LINELEN];
168 /* Tell the status of the current line. */
169 static LINETYPE recv_type;
171 /* This is our variable storage. */
172 static VARIABLE variable_list;
175 static void
176 die (const char *format, ...)
178 va_list arg_ptr;
180 fflush (stdout);
181 fprintf (stderr, "%s: ", invocation_name);
183 va_start (arg_ptr, format);
184 vfprintf (stderr, format, arg_ptr);
185 va_end (arg_ptr);
186 putc ('\n', stderr);
188 exit (1);
191 #define die(format, args...) (die) ("%s: " format, __FUNCTION__ , ##args)
193 static void
194 err (const char *format, ...)
196 va_list arg_ptr;
198 fflush (stdout);
199 fprintf (stderr, "%s: ", invocation_name);
201 va_start (arg_ptr, format);
202 vfprintf (stderr, format, arg_ptr);
203 va_end (arg_ptr);
204 putc ('\n', stderr);
207 static void *
208 xmalloc (size_t n)
210 void *p = malloc (n);
211 if (!p)
212 die ("out of core");
213 return p;
216 static void *
217 xcalloc (size_t n, size_t m)
219 void *p = calloc (n, m);
220 if (!p)
221 die ("out of core");
222 return p;
225 static char *
226 xstrdup (const char *s)
228 char *p = xmalloc (strlen (s)+1);
229 strcpy (p, s);
230 return p;
234 /* Write LENGTH bytes from BUFFER to FD. */
235 static int
236 writen (int fd, const char *buffer, size_t length)
238 while (length)
240 int nwritten = write (fd, buffer, length);
242 if (nwritten < 0)
244 if (errno == EINTR)
245 continue;
246 return -1; /* write error */
248 length -= nwritten;
249 buffer += nwritten;
251 return 0; /* okay */
257 /* Assuan specific stuff. */
259 /* Read a line from FD, store it in the global recv_line, analyze the
260 type and store that in recv_type. The function terminates on a
261 communication error. Returns a pointer into the inputline to the
262 first byte of the arguments. The parsing is very strict to match
263 excalty what we want to send. */
264 static char *
265 read_assuan (int fd)
267 static char pending[MAX_LINELEN];
268 static size_t pending_len;
269 size_t nleft = sizeof recv_line;
270 char *buf = recv_line;
271 char *p;
273 while (nleft > 0)
275 int n;
277 if (pending_len)
279 if (pending_len >= nleft)
280 die ("received line too large");
281 memcpy (buf, pending, pending_len);
282 n = pending_len;
283 pending_len = 0;
285 else
286 n = read (fd, buf, nleft);
288 if (opt_verbose)
290 int i;
291 printf ("%s: read \"", __FUNCTION__);
292 for (i = 0; i < n; i ++)
293 putc (buf[i], stdout);
294 printf ("\"\n");
297 if (n < 0)
299 if (errno == EINTR)
300 continue;
301 die ("reading fd %d failed: %s", fd, strerror (errno));
303 else if (!n)
304 die ("received incomplete line on fd %d", fd);
305 p = buf;
306 nleft -= n;
307 buf += n;
309 for (; n && *p != '\n'; n--, p++)
311 if (n)
313 if (n>1)
315 n--;
316 memcpy (pending, p + 1, n);
317 pending_len = n;
319 *p = '\0';
320 break;
323 if (!nleft)
324 die ("received line too large");
326 p = recv_line;
327 if (p[0] == 'O' && p[1] == 'K' && (p[2] == ' ' || !p[2]))
329 recv_type = LINE_OK;
330 p += 3;
332 else if (p[0] == 'E' && p[1] == 'R' && p[2] == 'R'
333 && (p[3] == ' ' || !p[3]))
335 recv_type = LINE_ERR;
336 p += 4;
338 else if (p[0] == 'S' && (p[1] == ' ' || !p[1]))
340 recv_type = LINE_STAT;
341 p += 2;
343 else if (p[0] == 'D' && p[1] == ' ')
345 recv_type = LINE_DATA;
346 p += 2;
348 else if (p[0] == 'E' && p[1] == 'N' && p[2] == 'D' && !p[3])
350 recv_type = LINE_END;
351 p += 3;
353 else
354 die ("invalid line type (%.5s)", p);
356 return p;
359 /* Write LINE to the server using FD. It is expected that the line
360 contains the terminating linefeed as last character. */
361 static void
362 write_assuan (int fd, const char *line)
364 char buffer[1026];
365 size_t n = strlen (line);
367 if (n > 1024)
368 die ("line too long for Assuan protocol");
369 strcpy (buffer, line);
370 if (!n || buffer[n-1] != '\n')
371 buffer[n++] = '\n';
373 if (writen (fd, buffer, n))
374 die ("sending line (\"%s\") to %d failed: %s", buffer, fd,
375 strerror (errno));
379 /* Start the server with path PGMNAME and connect its stdout and
380 strerr to a newly created pipes; the file descriptors are then
381 store in the gloabl variables SERVER_SEND_FD and
382 SERVER_RECV_FD. The initial handcheck is performed.*/
383 static void
384 start_server (const char *pgmname)
386 int rp[2];
387 int wp[2];
388 pid_t pid;
390 if (pipe (rp) < 0)
391 die ("pipe creation failed: %s", strerror (errno));
392 if (pipe (wp) < 0)
393 die ("pipe creation failed: %s", strerror (errno));
395 fflush (stdout);
396 fflush (stderr);
397 pid = fork ();
398 if (pid < 0)
399 die ("fork failed");
401 if (!pid)
403 const char *arg0;
405 arg0 = strrchr (pgmname, '/');
406 if (arg0)
407 arg0++;
408 else
409 arg0 = pgmname;
411 if (wp[0] != STDIN_FILENO)
413 if (dup2 (wp[0], STDIN_FILENO) == -1)
414 die ("dup2 failed in child: %s", strerror (errno));
415 close (wp[0]);
417 if (rp[1] != STDOUT_FILENO)
419 if (dup2 (rp[1], STDOUT_FILENO) == -1)
420 die ("dup2 failed in child: %s", strerror (errno));
421 close (rp[1]);
423 if (!opt_verbose)
425 int fd = open ("/dev/null", O_WRONLY);
426 if (fd == -1)
427 die ("can't open `/dev/null': %s", strerror (errno));
428 if (dup2 (fd, STDERR_FILENO) == -1)
429 die ("dup2 failed in child: %s", strerror (errno));
430 close (fd);
433 close (wp[1]);
434 close (rp[0]);
435 execl (pgmname, arg0, "--server", NULL);
436 die ("exec failed for `%s': %s", pgmname, strerror (errno));
438 close (wp[0]);
439 close (rp[1]);
440 server_send_fd = wp[1];
441 server_recv_fd = rp[0];
443 read_assuan (server_recv_fd);
444 if (recv_type != LINE_OK)
445 die ("no greating message");
452 /* Script intepreter. */
454 static void
455 unset_var (const char *name)
457 VARIABLE var;
459 for (var=variable_list; var && strcmp (var->name, name); var = var->next)
461 if (!var)
462 return;
463 /* fprintf (stderr, "unsetting `%s'\n", name); */
465 if (var->type == VARTYPE_FD && var->value)
467 int fd;
469 fd = atoi (var->value);
470 if (fd != -1 && fd != 0 && fd != 1 && fd != 2)
471 close (fd);
474 free (var->value);
475 var->value = NULL;
476 var->type = 0;
477 var->count = 0;
481 static void
482 set_type_var (const char *name, const char *value, VARTYPE type)
484 VARIABLE var;
486 if (!name)
487 name = "?";
488 for (var=variable_list; var && strcmp (var->name, name); var = var->next)
490 if (!var)
492 var = xcalloc (1, sizeof *var + strlen (name));
493 strcpy (var->name, name);
494 var->next = variable_list;
495 variable_list = var;
497 else
498 free (var->value);
500 if (var->type == VARTYPE_FD && var->value)
502 int fd;
504 fd = atoi (var->value);
505 if (fd != -1 && fd != 0 && fd != 1 && fd != 2)
506 close (fd);
509 var->type = type;
510 var->count = 0;
511 if (var->type == VARTYPE_COUNTER)
513 /* We need some extra sapce as scratch area for get_var. */
514 var->value = xmalloc (strlen (value) + 1 + 20);
515 strcpy (var->value, value);
517 else
518 var->value = xstrdup (value);
521 static void
522 set_var (const char *name, const char *value)
524 set_type_var (name, value, 0);
528 static const char *
529 get_var (const char *name)
531 VARIABLE var;
533 for (var=variable_list; var && strcmp (var->name, name); var = var->next)
535 if (!var)
536 return NULL;
537 if (var->type == VARTYPE_COUNTER && var->value)
538 { /* Use the scratch space allocated by set_var. */
539 char *p = var->value + strlen(var->value)+1;
540 sprintf (p, "%u", var->count);
541 return p;
543 else
544 return var->value;
548 /* Incremente all counter type variables with NAME in their VALUE. */
549 static void
550 inc_counter (const char *name)
552 VARIABLE var;
554 if (!*name)
555 return;
556 for (var=variable_list; var; var = var->next)
558 if (var->type == VARTYPE_COUNTER
559 && var->value && !strcmp (var->value, name))
560 var->count++;
565 /* Expand variables in LINE and return a new allocated buffer if
566 required. The function might modify LINE if the expanded version
567 fits into it. */
568 static char *
569 expand_line (char *buffer)
571 char *line = buffer;
572 char *p, *pend;
573 const char *value;
574 size_t valuelen, n;
575 char *result = NULL;
577 while (*line)
579 p = strchr (line, '$');
580 if (!p)
581 return result; /* nothing more to expand */
583 if (p[1] == '$') /* quoted */
585 memmove (p, p+1, strlen (p+1)+1);
586 line = p + 1;
587 continue;
589 for (pend=p+1; *pend && !spacep (pend)
590 && *pend != '$' && *pend != '/'; pend++)
592 if (*pend)
594 int save = *pend;
595 *pend = 0;
596 value = get_var (p+1);
597 *pend = save;
599 else
600 value = get_var (p+1);
601 if (!value)
602 value = "";
603 valuelen = strlen (value);
604 if (valuelen <= pend - p)
606 memcpy (p, value, valuelen);
607 p += valuelen;
608 n = pend - p;
609 if (n)
610 memmove (p, p+n, strlen (p+n)+1);
611 line = p;
613 else
615 char *src = result? result : buffer;
616 char *dst;
618 dst = xmalloc (strlen (src) + valuelen + 1);
619 n = p - src;
620 memcpy (dst, src, n);
621 memcpy (dst + n, value, valuelen);
622 n += valuelen;
623 strcpy (dst + n, pend);
624 line = dst + n;
625 free (result);
626 result = dst;
629 return result;
633 /* Evaluate COND and return the result. */
634 static int
635 eval_boolean (const char *cond)
637 int true = 1;
639 for ( ; *cond == '!'; cond++)
640 true = !true;
641 if (!*cond || (*cond == '0' && !cond[1]))
642 return !true;
643 return true;
650 static void
651 cmd_let (const char *assign_to, char *arg)
653 set_var (assign_to, arg);
657 static void
658 cmd_echo (const char *assign_to, char *arg)
660 if (!opt_no_echo)
661 printf ("%s\n", arg);
664 static void
665 cmd_send (const char *assign_to, char *arg)
667 if (opt_verbose)
668 fprintf (stderr, "sending `%s'\n", arg);
669 write_assuan (server_send_fd, arg);
672 static void
673 handle_status_line (char *arg)
675 char *p;
677 for (p=arg; *p && !spacep (p); p++)
679 if (*p)
681 int save = *p;
682 *p = 0;
683 inc_counter (arg);
684 *p = save;
686 else
687 inc_counter (arg);
690 static void
691 cmd_expect_ok (const char *assign_to, char *arg)
693 if (opt_verbose)
694 fprintf (stderr, "expecting OK\n");
697 char *p = read_assuan (server_recv_fd);
698 if (opt_verbose > 1)
699 fprintf (stderr, "got line `%s'\n", recv_line);
700 if (recv_type == LINE_STAT)
701 handle_status_line (p);
703 while (recv_type != LINE_OK && recv_type != LINE_ERR);
704 if (recv_type != LINE_OK)
705 die ("expected OK but got `%s'", recv_line);
708 static void
709 cmd_expect_err (const char *assign_to, char *arg)
711 if (opt_verbose)
712 fprintf (stderr, "expecting ERR\n");
715 char *p = read_assuan (server_recv_fd);
716 if (opt_verbose > 1)
717 fprintf (stderr, "got line `%s'\n", recv_line);
718 if (recv_type == LINE_STAT)
719 handle_status_line (p);
721 while (recv_type != LINE_OK && recv_type != LINE_ERR);
722 if (recv_type != LINE_ERR)
723 die ("expected ERR but got `%s'", recv_line);
726 static void
727 cmd_count_status (const char *assign_to, char *arg)
729 char *p;
731 if (!*assign_to || !*arg)
732 die ("syntax error: count-status requires an argument and a variable");
734 for (p=arg; *p && !spacep (p); p++)
736 if (*p)
738 for (*p++ = 0; spacep (p); p++)
740 if (*p)
741 die ("cmpfiles: syntax error");
743 set_type_var (assign_to, arg, VARTYPE_COUNTER);
746 static void
747 cmd_openfile (const char *assign_to, char *arg)
749 int fd;
750 char numbuf[20];
753 fd = open (arg, O_RDONLY);
754 while (fd == -1 && errno == EINTR);
755 if (fd == -1)
756 die ("error opening `%s': %s", arg, strerror (errno));
758 sprintf (numbuf, "%d", fd);
759 set_type_var (assign_to, numbuf, VARTYPE_FD);
762 static void
763 cmd_createfile (const char *assign_to, char *arg)
765 int fd;
766 char numbuf[20];
769 fd = open (arg, O_WRONLY|O_CREAT|O_TRUNC, 0666);
770 while (fd == -1 && errno == EINTR);
771 if (fd == -1)
772 die ("error creating `%s': %s", arg, strerror (errno));
774 sprintf (numbuf, "%d", fd);
775 set_type_var (assign_to, numbuf, VARTYPE_FD);
779 static void
780 cmd_pipeserver (const char *assign_to, char *arg)
782 if (!*arg)
783 die ("syntax error: servername missing");
785 start_server (arg);
789 static void
790 cmd_quit_if(const char *assign_to, char *arg)
792 if (eval_boolean (arg))
793 exit (0);
796 static void
797 cmd_fail_if(const char *assign_to, char *arg)
799 if (eval_boolean (arg))
800 exit (1);
804 static void
805 cmd_cmpfiles (const char *assign_to, char *arg)
807 char *p = arg;
808 char *second;
809 FILE *fp1, *fp2;
810 char buffer1[2048]; /* note: both must be of equal size. */
811 char buffer2[2048];
812 size_t nread1, nread2;
813 int rc = 0;
815 set_var (assign_to, "0");
816 for (p=arg; *p && !spacep (p); p++)
818 if (!*p)
819 die ("cmpfiles: syntax error");
820 for (*p++ = 0; spacep (p); p++)
822 second = p;
823 for (; *p && !spacep (p); p++)
825 if (*p)
827 for (*p++ = 0; spacep (p); p++)
829 if (*p)
830 die ("cmpfiles: syntax error");
833 fp1 = fopen (arg, "rb");
834 if (!fp1)
836 err ("can't open `%s': %s", arg, strerror (errno));
837 return;
839 fp2 = fopen (second, "rb");
840 if (!fp2)
842 err ("can't open `%s': %s", second, strerror (errno));
843 fclose (fp1);
844 return;
846 while ( (nread1 = fread (buffer1, 1, sizeof buffer1, fp1)))
848 if (ferror (fp1))
849 break;
850 nread2 = fread (buffer2, 1, sizeof buffer2, fp2);
851 if (ferror (fp2))
852 break;
853 if (nread1 != nread2 || memcmp (buffer1, buffer2, nread1))
855 rc = 1;
856 break;
859 if (feof (fp1) && feof (fp2) && !rc)
861 if (opt_verbose)
862 err ("files match");
863 set_var (assign_to, "1");
865 else if (!rc)
866 err ("cmpfiles: read error: %s", strerror (errno));
867 else
868 err ("cmpfiles: mismatch");
869 fclose (fp1);
870 fclose (fp2);
873 static void
874 cmd_getenv (const char *assign_to, char *arg)
876 const char *s;
877 s = *arg? getenv (arg):"";
878 set_var (assign_to, s? s:"");
884 /* Process the current script line LINE. */
885 static int
886 interpreter (char *line)
888 static struct {
889 const char *name;
890 void (*fnc)(const char*, char*);
891 } cmdtbl[] = {
892 { "let" , cmd_let },
893 { "echo" , cmd_echo },
894 { "send" , cmd_send },
895 { "expect-ok" , cmd_expect_ok },
896 { "expect-err", cmd_expect_err },
897 { "count-status", cmd_count_status },
898 { "openfile" , cmd_openfile },
899 { "createfile", cmd_createfile },
900 { "pipeserver", cmd_pipeserver },
901 { "quit" , NULL },
902 { "quit-if" , cmd_quit_if },
903 { "fail-if" , cmd_fail_if },
904 { "cmpfiles" , cmd_cmpfiles },
905 { "getenv" , cmd_getenv },
906 { NULL }
908 char *p, *save_p;
909 int i, save_c;
910 char *stmt = NULL;
911 char *assign_to = NULL;
912 char *must_free = NULL;
914 for ( ;spacep (line); line++)
916 if (!*line || *line == '#')
917 return 0; /* empty or comment */
918 p = expand_line (line);
919 if (p)
921 must_free = p;
922 line = p;
923 for ( ;spacep (line); line++)
925 if (!*line || *line == '#')
927 free (must_free);
928 return 0; /* empty or comment */
931 for (p=line; *p && !spacep (p) && *p != '='; p++)
933 if (*p == '=')
935 *p = 0;
936 assign_to = line;
938 else if (*p)
940 for (*p++ = 0; spacep (p); p++)
942 if (*p == '=')
943 assign_to = line;
945 if (!*line)
946 die ("syntax error");
947 stmt = line;
948 save_c = 0;
949 save_p = NULL;
950 if (assign_to)
951 { /* this is an assignment */
952 for (p++; spacep (p); p++)
954 if (!*p)
956 unset_var (assign_to);
957 free (must_free);
958 return 0;
960 stmt = p;
961 for (; *p && !spacep (p); p++)
963 if (*p)
965 save_p = p;
966 save_c = *p;
967 for (*p++ = 0; spacep (p); p++)
971 for (i=0; cmdtbl[i].name && strcmp (stmt, cmdtbl[i].name); i++)
973 if (!cmdtbl[i].name)
975 if (!assign_to)
976 die ("invalid statement `%s'\n", stmt);
977 if (save_p)
978 *save_p = save_c;
979 set_var (assign_to, stmt);
980 free (must_free);
981 return 0;
984 if (cmdtbl[i].fnc)
985 cmdtbl[i].fnc (assign_to, p);
986 free (must_free);
987 return cmdtbl[i].fnc? 0:1;
993 main (int argc, char **argv)
995 char buffer[2048];
996 char *p, *pend;
998 if (!argc)
999 invocation_name = "asschk";
1000 else
1002 invocation_name = *argv++;
1003 argc--;
1004 p = strrchr (invocation_name, '/');
1005 if (p)
1006 invocation_name = p+1;
1010 set_var ("?","1"); /* defaults to true */
1012 for (; argc; argc--, argv++)
1014 p = *argv;
1015 if (*p != '-')
1016 break;
1017 if (!strcmp (p, "--verbose"))
1018 opt_verbose++;
1019 else if (!strcmp (p, "--no-echo"))
1020 opt_no_echo++;
1021 else if (*p == '-' && p[1] == 'D')
1023 p += 2;
1024 pend = strchr (p, '=');
1025 if (pend)
1027 int tmp = *pend;
1028 *pend = 0;
1029 set_var (p, pend+1);
1030 *pend = tmp;
1032 else
1033 set_var (p, "1");
1035 else if (*p == '-' && p[1] == '-' && !p[2])
1037 argc--; argv++;
1038 break;
1040 else
1041 break;
1043 if (argc)
1044 die ("usage: asschk [--verbose] {-D<name>[=<value>]}");
1047 while (fgets (buffer, sizeof buffer, stdin))
1049 p = strchr (buffer,'\n');
1050 if (!p)
1051 die ("incomplete script line");
1052 *p = 0;
1053 if (interpreter (buffer))
1054 break;
1055 fflush (stdout);
1057 return 0;