Commit 128efb9c 128efb9c9b268678f477fb39aa427c7c939019a7 by Sergey Poznyakoff

Fix imap4d input tokenizer.

The proper delimiters are ( and ), listed in RFC as atom_specials.
The characters "[]<>." are delimiters for FETCH, and "." is  a
delimiter for STORE.  Fix tokenizer to recognize these only in the
corresponding contexts.

In particular, it fixes parsing of input atoms containing dots, as
foo@bar.baz, which previous versions incorrectly splitted in three.

* imap4d/util.c (ISDELIM): Delimiters are only ( and )
* imap4d/imap4d.h (struct imap4d_parsebuf): new data type.
(imap4d_parsebuf_t): New data type.
(imap4d_parsebuf_exit, imap4d_parsebuf_peek)
(imap4d_parsebuf_next, imap4d_parsebuf_token)
(imap4d_parsebuf_data, imap4d_with_parsebuf): New prototypes.
* imap4d/parsebuf.c: New file.
* imap4d/Makefile.am: Add parsebuf.c
* imap4d/fetch.c, imap4d/store.c: Rewrite using parsebuf functions.
1 parent 37fcd5c1
1 ## Process this file with GNU Automake to create Makefile.in 1 ## Process this file with GNU Automake to create Makefile.in
2 2
3 ## Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 3 ## Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005,
4 ## 2007, 2008 Free Software Foundation, Inc. 4 ## 2007, 2008, 2009 Free Software Foundation, Inc.
5 ## 5 ##
6 ## GNU Mailutils is free software; you can redistribute it and/or 6 ## GNU Mailutils is free software; you can redistribute it and/or
7 ## modify it under the terms of the GNU General Public License as 7 ## modify it under the terms of the GNU General Public License as
...@@ -47,6 +47,7 @@ imap4d_SOURCES = \ ...@@ -47,6 +47,7 @@ imap4d_SOURCES = \
47 lsub.c\ 47 lsub.c\
48 namespace.c\ 48 namespace.c\
49 noop.c\ 49 noop.c\
50 parsebuf.c\
50 preauth.c\ 51 preauth.c\
51 rename.c\ 52 rename.c\
52 search.c\ 53 search.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2 Copyright (C) 1999, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 3 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -218,7 +218,35 @@ int imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes); ...@@ -218,7 +218,35 @@ int imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes);
218 #define IMAP4_ARG_2 3 218 #define IMAP4_ARG_2 3
219 #define IMAP4_ARG_3 4 219 #define IMAP4_ARG_3 4
220 #define IMAP4_ARG_4 5 220 #define IMAP4_ARG_4 5
221
222 /* Specialized buffer parsing */
223 struct imap4d_parsebuf
224 {
225 imap4d_tokbuf_t tok;
226 int arg; /* Argument number in tok */
227 char *tokptr; /* Current token */
228 size_t tokoff; /* Offset of next delimiter in tokptr */
229 int save_char; /* Character saved from tokptr[tokoff] */
230 char *token; /* Pointer to the current token */
231 const char *delim; /* Array of delimiters */
232 char *peek_ptr; /* Peeked token */
233 jmp_buf errjmp;
234 char *err_text;
235 void *data;
236 };
237
238 typedef struct imap4d_parsebuf *imap4d_parsebuf_t;
221 239
240 void imap4d_parsebuf_exit (imap4d_parsebuf_t pb, char *text);
241 char *imap4d_parsebuf_peek (imap4d_parsebuf_t pb);
242 char *imap4d_parsebuf_next (imap4d_parsebuf_t pb, int req);
243 int imap4d_with_parsebuf (imap4d_tokbuf_t tok, int arg,
244 const char *delim,
245 int (*thunk) (imap4d_parsebuf_t), void *data,
246 char **err_text);
247 #define imap4d_parsebuf_token(p) ((p)->token)
248 #define imap4d_parsebuf_data(p) ((p)->data)
249
222 /* Imap4 commands */ 250 /* Imap4 commands */
223 extern int imap4d_append (struct imap4d_command *, imap4d_tokbuf_t); 251 extern int imap4d_append (struct imap4d_command *, imap4d_tokbuf_t);
224 extern int imap4d_authenticate (struct imap4d_command *, imap4d_tokbuf_t); 252 extern int imap4d_authenticate (struct imap4d_command *, imap4d_tokbuf_t);
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2009 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 MA 02110-1301 USA */
18
19 #include "imap4d.h"
20
21 static void
22 parsebuf_free (struct imap4d_parsebuf *p)
23 {
24 if (p->peek_ptr)
25 free (p->peek_ptr);
26 }
27
28 void
29 imap4d_parsebuf_exit (struct imap4d_parsebuf *p, char *text)
30 {
31 p->err_text = text;
32 longjmp (p->errjmp, 1);
33 }
34
35 static char *
36 pbcopy (const char *str, size_t len)
37 {
38 char *p = malloc (len + 1);
39 if (!p)
40 imap4d_bye (ERR_NO_MEM);
41 memcpy (p, str, len);
42 p[len] = 0;
43 return p;
44 }
45
46 static char *
47 pbcopy_char (int c)
48 {
49 char ch = c;
50 return pbcopy (&ch, 1);
51 }
52
53 char *
54 imap4d_parsebuf_peek (struct imap4d_parsebuf *p)
55 {
56 if (!p->peek_ptr)
57 {
58 if (!p->tokptr || p->save_char == 0)
59 {
60 char *token = imap4d_tokbuf_getarg (p->tok, p->arg);
61 if (!token)
62 return NULL;
63 if (p->delim)
64 {
65 if (strchr (p->delim, token[0]))
66 p->peek_ptr = pbcopy_char (token[0]);
67 else
68 p->peek_ptr = pbcopy (token, strcspn (token, p->delim));
69 }
70 else
71 p->peek_ptr = pbcopy (token, strlen (token));
72 }
73 else
74 {
75 char *token = p->token + p->tokoff;
76
77 if (strchr (p->delim, p->save_char))
78 p->peek_ptr = pbcopy_char (p->save_char);
79 else
80 {
81 size_t off = strcspn (token + 1, p->delim);
82 p->peek_ptr = pbcopy (token, off + 1);
83 p->peek_ptr[0] = p->save_char;
84 }
85 }
86 }
87 return p->peek_ptr;
88 }
89
90 char *
91 imap4d_parsebuf_next (struct imap4d_parsebuf *p, int req)
92 {
93 if (p->peek_ptr)
94 {
95 free (p->peek_ptr);
96 p->peek_ptr = NULL;
97 }
98
99 if (!p->tokptr || p->save_char == 0)
100 {
101 p->tokptr = imap4d_tokbuf_getarg (p->tok, p->arg++);
102 p->token = p->tokptr;
103 p->tokoff = 0;
104 if (!p->token)
105 {
106 if (req)
107 imap4d_parsebuf_exit (p, "Too few arguments");
108 return NULL;
109 }
110 if (p->delim)
111 {
112 if (strchr (p->delim, p->token[0]))
113 {
114 p->save_char = p->token[1];
115 p->tokoff = 1;
116 p->token[1] = 0;
117 }
118 else
119 {
120 p->tokoff = strcspn (p->token, p->delim);
121 if ((p->save_char = p->token[p->tokoff]))
122 p->token[p->tokoff] = 0;
123 }
124 }
125 else
126 p->save_char = 0;
127 }
128 else
129 {
130 p->token[p->tokoff] = p->save_char;
131 p->token += p->tokoff;
132 if (strchr (p->delim, p->save_char))
133 {
134 p->save_char = p->token[1];
135 p->token[1] = 0;
136 p->tokoff = 1;
137 }
138 else
139 {
140 p->tokoff = strcspn (p->token, p->delim);
141 if ((p->save_char = p->token[p->tokoff]))
142 p->token[p->tokoff] = 0;
143 }
144 }
145
146 return p->token;
147 }
148
149 int
150 imap4d_with_parsebuf (imap4d_tokbuf_t tok, int arg, const char *delim,
151 int (*thunk) (imap4d_parsebuf_t), void *data,
152 char **err_text)
153 {
154 struct imap4d_parsebuf pbuf;
155 int rc;
156
157 memset (&pbuf, 0, sizeof pbuf);
158 pbuf.tok = tok;
159 pbuf.arg = arg;
160 pbuf.delim = delim;
161 pbuf.data = data;
162 pbuf.err_text = "Syntax error";
163 pbuf.data = data;
164
165 if (setjmp (pbuf.errjmp))
166 {
167 *err_text = pbuf.err_text;
168 parsebuf_free (&pbuf);
169 return RESP_BAD;
170 }
171
172 rc = thunk (&pbuf);
173 parsebuf_free (&pbuf);
174 return rc;
175 }
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2007, 2008,
3 2009 Free Software Foundation, Inc.
3 4
4 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -18,165 +19,165 @@ ...@@ -18,165 +19,165 @@
18 19
19 #include "imap4d.h" 20 #include "imap4d.h"
20 21
21 /* 22 enum value_type { STORE_SET, STORE_ADD, STORE_UNSET };
22 * Now you're messing with a sumbitch
23 */
24 23
25 int 24 struct store_parse_closure
26 imap4d_store (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 25 {
28 int rc; 26 enum value_type how;
29 char *err_text; 27 int ack;
30 28 int type;
31 rc = imap4d_store0 (tok, 0, &err_text); 29 int isuid;
32 return util_finish (command, rc, "%s", err_text); 30 size_t *set;
33 } 31 size_t count;
34
35 struct parsebuf
36 {
37 char *token;
38 imap4d_tokbuf_t tok;
39 int arg;
40 jmp_buf errjmp;
41 char *err_text;
42 }; 32 };
43 33
44 static void 34 static int
45 parsebuf_exit (struct parsebuf *p, char *text) 35 store_thunk (imap4d_parsebuf_t p)
46 {
47 p->err_text = text;
48 longjmp (p->errjmp, 1);
49 }
50
51 static char *
52 parsebuf_next (struct parsebuf *p, int req)
53 {
54 p->token = imap4d_tokbuf_getarg (p->tok, p->arg++);
55 if (!p->token && req)
56 parsebuf_exit (p, "Too few arguments");
57 return p->token;
58 }
59
60 int
61 imap4d_store0 (imap4d_tokbuf_t tok, int isuid, char **ptext)
62 { 36 {
37 struct store_parse_closure *pclos = imap4d_parsebuf_data (p);
63 char *msgset; 38 char *msgset;
64 int status;
65 int ack = 1;
66 size_t i;
67 int n = 0;
68 size_t *set = NULL;
69 enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how;
70 struct parsebuf pb;
71 char *data; 39 char *data;
72 int type = 0; 40 int status;
73 41
74 pb.tok = tok; 42 msgset = imap4d_parsebuf_next (p, 1);
75 pb.arg = IMAP4_ARG_1 + !!isuid; 43 data = imap4d_parsebuf_next (p, 1);
76 pb.err_text = NULL;
77 if (setjmp (pb.errjmp))
78 {
79 *ptext = pb.err_text;
80 free (set);
81 return RESP_BAD;
82 }
83
84 msgset = parsebuf_next (&pb, 1);
85 data = parsebuf_next (&pb, 1);
86 44
87 if (*data == '+') 45 if (*data == '+')
88 { 46 {
89 how = STORE_ADD; 47 pclos->how = STORE_ADD;
90 data++; 48 data++;
91 } 49 }
92 else if (*data == '-') 50 else if (*data == '-')
93 { 51 {
94 how = STORE_UNSET; 52 pclos->how = STORE_UNSET;
95 data++; 53 data++;
96 } 54 }
97 else 55 else
98 how = STORE_SET; 56 pclos->how = STORE_SET;
99 57
100 if (strcasecmp (data, "FLAGS")) 58 if (strcasecmp (data, "FLAGS"))
101 parsebuf_exit (&pb, "Bogus data item"); 59 imap4d_parsebuf_exit (p, "Bogus data item");
102 data = parsebuf_next (&pb, 1); 60 data = imap4d_parsebuf_next (p, 1);
103 61
104 if (*data == '.') 62 if (*data == '.')
105 { 63 {
106 data = parsebuf_next (&pb, 1); 64 data = imap4d_parsebuf_next (p, 1);
107 if (strcasecmp (data, "SILENT") == 0) 65 if (strcasecmp (data, "SILENT") == 0)
108 { 66 {
109 ack = 0; 67 pclos->ack = 0;
110 parsebuf_next (&pb, 1); 68 imap4d_parsebuf_next (p, 1);
111 } 69 }
112 else 70 else
113 parsebuf_exit (&pb, "Bogus data suffix"); 71 imap4d_parsebuf_exit (p, "Bogus data suffix");
114 } 72 }
115 73
116 /* Get the message numbers in set[]. */ 74 /* Get the message numbers in set[]. */
117 status = util_msgset (msgset, &set, &n, isuid); 75 status = util_msgset (msgset, &pclos->set, &pclos->count, pclos->isuid);
118 if (status != 0) 76 switch (status)
119 { 77 {
78 case 0:
79 break;
80
81 case EINVAL:
120 /* See RFC 3501, section 6.4.8, and a comment to the equivalent code 82 /* See RFC 3501, section 6.4.8, and a comment to the equivalent code
121 in fetch.c */ 83 in fetch.c */
122 *ptext = "Completed"; 84 p->err_text = "Completed";
123 return RESP_OK; 85 return RESP_OK;
86
87 default:
88 p->err_text = "Failed to parse message set";
89 return RESP_NO;
124 } 90 }
125 91
126 if (pb.token[0] != '(') 92 if (p->token[0] != '(')
127 parsebuf_exit (&pb, "Syntax error"); 93 imap4d_parsebuf_exit (p, "Syntax error");
128 parsebuf_next (&pb, 1); 94 imap4d_parsebuf_next (p, 1);
129 95
130 do 96 do
131 { 97 {
132 int t; 98 int t;
133 if (!util_attribute_to_type (pb.token, &t)) 99 if (!util_attribute_to_type (p->token, &t))
134 type |= t; 100 pclos->type |= t;
135 } 101 }
136 while (parsebuf_next (&pb, 1) && pb.token[0] != ')'); 102 while (imap4d_parsebuf_next (p, 1) && p->token[0] != ')');
103 return RESP_OK;
104 }
105
106 int
107 imap4d_store0 (imap4d_tokbuf_t tok, int isuid, char **ptext)
108 {
109 int rc;
110 struct store_parse_closure pclos;
137 111
138 for (i = 0; i < n; i++) 112 memset (&pclos, 0, sizeof pclos);
113 pclos.ack = 1;
114 pclos.isuid = isuid;
115
116 rc = imap4d_with_parsebuf (tok,
117 IMAP4_ARG_1 + !!isuid,
118 ".",
119 store_thunk, &pclos,
120 ptext);
121 if (rc == RESP_OK)
139 { 122 {
140 mu_message_t msg = NULL; 123 size_t i;
141 mu_attribute_t attr = NULL;
142 size_t msgno = isuid ? uid_to_msgno (set[i]) : set[i];
143 124
144 if (msgno) 125 for (i = 0; i < pclos.count; i++)
145 { 126 {
146 mu_mailbox_get_message (mbox, msgno, &msg); 127 mu_message_t msg = NULL;
147 mu_message_get_attribute (msg, &attr); 128 mu_attribute_t attr = NULL;
148 129 size_t msgno = isuid ? uid_to_msgno (pclos.set[i]) : pclos.set[i];
149 switch (how)
150 {
151 case STORE_ADD:
152 mu_attribute_set_flags (attr, type);
153 break;
154 130
155 case STORE_UNSET: 131 if (msgno)
156 mu_attribute_unset_flags (attr, type); 132 {
157 break; 133 mu_mailbox_get_message (mbox, msgno, &msg);
134 mu_message_get_attribute (msg, &attr);
135
136 switch (pclos.how)
137 {
138 case STORE_ADD:
139 mu_attribute_set_flags (attr, pclos.type);
140 break;
141
142 case STORE_UNSET:
143 mu_attribute_unset_flags (attr, pclos.type);
144 break;
158 145
159 case STORE_SET: 146 case STORE_SET:
160 mu_attribute_unset_flags (attr, 0xffffffff); /* FIXME */ 147 mu_attribute_unset_flags (attr, 0xffffffff); /* FIXME */
161 mu_attribute_set_flags (attr, type); 148 mu_attribute_set_flags (attr, pclos.type);
149 }
150 }
151
152 if (pclos.ack)
153 {
154 util_send ("* %d FETCH (", msgno);
155
156 if (isuid)
157 util_send ("UID %lu ", (unsigned long) msgno);
158 util_send ("FLAGS (");
159 util_print_flags (attr);
160 util_send ("))\r\n");
162 } 161 }
162 /* Update the flags of uid table. */
163 imap4d_sync_flags (pclos.set[i]);
163 } 164 }
164 165
165 if (ack) 166 *ptext = "Completed";
166 {
167 util_send ("* %d FETCH (", msgno);
168
169 if (isuid)
170 util_send ("UID %lu ", (unsigned long) msgno);
171 util_send ("FLAGS (");
172 util_print_flags (attr);
173 util_send ("))\r\n");
174 }
175 /* Update the flags of uid table. */
176 imap4d_sync_flags (set[i]);
177 } 167 }
178 free (set); 168
179 *ptext = "Completed"; 169 free (pclos.set);
180 return RESP_OK; 170
171 return rc;
172 }
173
174 int
175 imap4d_store (struct imap4d_command *command, imap4d_tokbuf_t tok)
176 {
177 int rc;
178 char *err_text;
179
180 rc = imap4d_store0 (tok, 0, &err_text);
181 return util_finish (command, rc, "%s", err_text);
181 } 182 }
182 183
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2 Copyright (C) 1999, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 3 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -121,6 +121,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) ...@@ -121,6 +121,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid)
121 { 121 {
122 if (*set) 122 if (*set)
123 free (*set); 123 free (*set);
124 *set = NULL;
124 *n = 0; 125 *n = 0;
125 return EINVAL; 126 return EINVAL;
126 } 127 }
...@@ -133,6 +134,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) ...@@ -133,6 +134,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid)
133 } 134 }
134 if (*set) 135 if (*set)
135 free (*set); 136 free (*set);
137 *set = NULL;
136 *n = 0; 138 *n = 0;
137 return EINVAL; 139 return EINVAL;
138 } 140 }
...@@ -147,6 +149,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) ...@@ -147,6 +149,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid)
147 if (tmp < 0 || val == 0) 149 if (tmp < 0 || val == 0)
148 { 150 {
149 free (*set); 151 free (*set);
152 *set = NULL;
150 *n = 0; 153 *n = 0;
151 return EINVAL; 154 return EINVAL;
152 } 155 }
...@@ -206,6 +209,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) ...@@ -206,6 +209,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid)
206 done = 1; 209 done = 1;
207 if (*set) 210 if (*set)
208 free (*set); 211 free (*set);
212 *set = NULL;
209 *n = 0; 213 *n = 0;
210 return EINVAL; 214 return EINVAL;
211 215
...@@ -238,6 +242,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) ...@@ -238,6 +242,7 @@ util_msgset (char *s, size_t ** set, int *n, int isuid)
238 if (tmp < 0 || val == 0) 242 if (tmp < 0 || val == 0)
239 { 243 {
240 free (*set); 244 free (*set);
245 *set = NULL;
241 *n = 0; 246 *n = 0;
242 return EINVAL; 247 return EINVAL;
243 } 248 }
...@@ -1221,7 +1226,7 @@ imap4d_tokbuf_expand (struct imap4d_tokbuf *tok, size_t size) ...@@ -1221,7 +1226,7 @@ imap4d_tokbuf_expand (struct imap4d_tokbuf *tok, size_t size)
1221 } 1226 }
1222 } 1227 }
1223 1228
1224 #define ISDELIM(c) (strchr (".()[]<>", (c)) != NULL) 1229 #define ISDELIM(c) (strchr ("()", (c)) != NULL)
1225 #define ISWS(c) (c == ' ' || c == '\t') 1230 #define ISWS(c) (c == ' ' || c == '\t')
1226 1231
1227 int 1232 int
...@@ -1257,7 +1262,7 @@ gettok (struct imap4d_tokbuf *tok, size_t off) ...@@ -1257,7 +1262,7 @@ gettok (struct imap4d_tokbuf *tok, size_t off)
1257 tok->argmax = 16; 1262 tok->argmax = 16;
1258 else 1263 else
1259 tok->argmax *= 2; 1264 tok->argmax *= 2;
1260 tok->argp = realloc(tok->argp, tok->argmax * sizeof (tok->argp[0])); 1265 tok->argp = realloc (tok->argp, tok->argmax * sizeof (tok->argp[0]));
1261 if (!tok->argp) 1266 if (!tok->argp)
1262 imap4d_bye (ERR_NO_MEM); 1267 imap4d_bye (ERR_NO_MEM);
1263 } 1268 }
...@@ -1278,7 +1283,7 @@ gettok (struct imap4d_tokbuf *tok, size_t off) ...@@ -1278,7 +1283,7 @@ gettok (struct imap4d_tokbuf *tok, size_t off)
1278 { 1283 {
1279 size_t len; 1284 size_t len;
1280 off++; 1285 off++;
1281 len = unquote(buf + off, p - (buf + off)); 1286 len = unquote (buf + off, p - (buf + off));
1282 buf[off + len] = 0; 1287 buf[off + len] = 0;
1283 tok->argp[tok->argc++] = off; 1288 tok->argp[tok->argc++] = off;
1284 return p - buf + 1; 1289 return p - buf + 1;
......