|
1 //builtin.c - builtin commands |
|
2 // |
|
3 // © Portions Copyright (c) Symbian Software Ltd 2007 - 2008. All rights reserved. |
|
4 // |
|
5 /* |
|
6 * This file is part of zsh, the Z shell. |
|
7 * |
|
8 * Copyright (c) 1992-1997 Paul Falstad |
|
9 * All rights reserved. |
|
10 * |
|
11 * Permission is hereby granted, without written agreement and without |
|
12 * license or royalty fees, to use, copy, modify, and distribute this |
|
13 * software and to distribute modified versions of this software for any |
|
14 * purpose, provided that the above copyright notice and the following |
|
15 * two paragraphs appear in all copies of this software. |
|
16 * |
|
17 * In no event shall Paul Falstad or the Zsh Development Group be liable |
|
18 * to any party for direct, indirect, special, incidental, or consequential |
|
19 * damages arising out of the use of this software and its documentation, |
|
20 * even if Paul Falstad and the Zsh Development Group have been advised of |
|
21 * the possibility of such damage. |
|
22 * |
|
23 * Paul Falstad and the Zsh Development Group specifically disclaim any |
|
24 * warranties, including, but not limited to, the implied warranties of |
|
25 * merchantability and fitness for a particular purpose. The software |
|
26 * provided hereunder is on an "as is" basis, and Paul Falstad and the |
|
27 * Zsh Development Group have no obligation to provide maintenance, |
|
28 * support, updates, enhancements, or modifications. |
|
29 * |
|
30 */ |
|
31 |
|
32 #ifdef __SYMBIAN32__ |
|
33 #ifdef __WINSCW__ |
|
34 #pragma warn_unusedarg off |
|
35 #pragma warn_possunwant off |
|
36 #endif//__WINSCW__ |
|
37 #endif//__SYMBIAN32__ |
|
38 |
|
39 /* this is defined so we get the prototype for open_memstream */ |
|
40 #define _GNU_SOURCE 1 |
|
41 |
|
42 #include "zsh.mdh" |
|
43 #include "builtin.pro" |
|
44 |
|
45 #ifdef __SYMBIAN32__ |
|
46 #include "dummy.h" |
|
47 #endif//__SYMBIAN32__ |
|
48 /* Builtins in the main executable */ |
|
49 |
|
50 static struct builtin builtins[] = |
|
51 { |
|
52 BIN_PREFIX("-", BINF_DASH), |
|
53 BIN_PREFIX("builtin", BINF_BUILTIN), |
|
54 BIN_PREFIX("command", BINF_COMMAND), |
|
55 BIN_PREFIX("exec", BINF_EXEC), |
|
56 BIN_PREFIX("noglob", BINF_NOGLOB), |
|
57 BUILTIN("[", 0, bin_test, 0, -1, BIN_BRACKET, NULL, NULL), |
|
58 BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL), |
|
59 BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL), |
|
60 BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmrs", NULL), |
|
61 BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "tUXkz", "u"), |
|
62 #ifndef __SYMBIAN32__ |
|
63 BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL), |
|
64 #endif |
|
65 BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL), |
|
66 BUILTIN("bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL), |
|
67 BUILTIN("cd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_CD, "sPL", NULL), |
|
68 BUILTIN("chdir", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_CD, "sPL", NULL), |
|
69 BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL), |
|
70 BUILTIN("declare", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klmprtuxz", NULL), |
|
71 BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "clpv", NULL), |
|
72 #ifndef __SYMBIAN32__ |
|
73 BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmrs", NULL), |
|
74 BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), |
|
75 #endif |
|
76 BUILTIN("echo", BINF_PRINTOPTS | BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"), |
|
77 BUILTIN("emulate", 0, bin_emulate, 1, 1, 0, "LR", NULL), |
|
78 #ifndef __SYMBIAN32__ |
|
79 BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmrs", NULL), |
|
80 #endif |
|
81 BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL), |
|
82 BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL), |
|
83 BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"), |
|
84 BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL), |
|
85 /* |
|
86 * We used to behave as if the argument to -e was optional. |
|
87 * But that's actually not useful, so it's more consistent to |
|
88 * cause an error. |
|
89 */ |
|
90 BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "nlre:IRWAdDfEimpPa", NULL), |
|
91 #ifndef __SYMBIAN32__ |
|
92 BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), |
|
93 #endif |
|
94 BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"), |
|
95 BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmtuUz", NULL), |
|
96 BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"), |
|
97 BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL), |
|
98 #ifndef __SYMBIAN32__ |
|
99 BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv", NULL), |
|
100 |
|
101 #ifdef ZSH_HASH_DEBUG |
|
102 BUILTIN("hashinfo", 0, bin_hashinfo, 0, 0, 0, NULL, NULL), |
|
103 #endif |
|
104 #endif //__SYMBIAN32__ |
|
105 |
|
106 BUILTIN("history", 0, bin_fc, 0, -1, BIN_FC, "nrdDfEimpPa", "l"), |
|
107 BUILTIN("integer", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "HL:%R:%Z:%ghi:%lprtux", "i"), |
|
108 #ifndef __SYMBIAN32__ |
|
109 BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL), |
|
110 BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL), |
|
111 #endif |
|
112 BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL), |
|
113 BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lprtux", NULL), |
|
114 #ifndef __SYMBIAN32__ |
|
115 BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL), |
|
116 #endif |
|
117 BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL), |
|
118 #if defined(ZSH_MEM) & defined(ZSH_MEM_DEBUG) |
|
119 BUILTIN("mem", 0, bin_mem, 0, 0, 0, "v", NULL), |
|
120 #endif |
|
121 |
|
122 #if defined(ZSH_PAT_DEBUG) |
|
123 BUILTIN("patdebug", 0, bin_patdebug, 1, -1, 0, "p", NULL), |
|
124 #endif |
|
125 |
|
126 BUILTIN("popd", 0, bin_cd, 0, 1, BIN_POPD, NULL, NULL), |
|
127 BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "acC:f:ilmnNoOPrRsu:z-", NULL), |
|
128 BUILTIN("printf", 0, bin_print, 1, -1, BIN_PRINTF, NULL, NULL), |
|
129 BUILTIN("pushd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_PUSHD, "sPL", NULL), |
|
130 BUILTIN("pushln", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"), |
|
131 BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), |
|
132 BUILTIN("r", 0, bin_fc, 0, -1, BIN_R, "nrl", NULL), |
|
133 BUILTIN("read", 0, bin_read, 0, -1, 0, "cd:ek:%lnpqrst:%zu:AE", NULL), |
|
134 BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"), |
|
135 #ifndef __SYMBIAN32__ |
|
136 BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "df", "r"), |
|
137 #endif |
|
138 BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), |
|
139 BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL), |
|
140 BUILTIN("setopt", 0, bin_setopt, 0, -1, BIN_SETOPT, NULL, NULL), |
|
141 BUILTIN("shift", BINF_PSPECIAL, bin_shift, 0, -1, 0, NULL, NULL), |
|
142 BUILTIN("source", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL), |
|
143 #ifndef __SYMBIAN32__ |
|
144 BUILTIN("suspend", 0, bin_suspend, 0, 0, 0, "f", NULL), |
|
145 #endif |
|
146 BUILTIN("test", 0, bin_test, 0, -1, BIN_TEST, NULL, NULL), |
|
147 #ifndef __SYMBIAN32__ |
|
148 BUILTIN("ttyctl", 0, bin_ttyctl, 0, 0, 0, "fu", NULL), |
|
149 BUILTIN("times", BINF_PSPECIAL, bin_times, 0, 0, 0, NULL, NULL), |
|
150 BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL), |
|
151 #endif |
|
152 BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL), |
|
153 BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"), |
|
154 BUILTIN("typeset", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klprtuxmz", NULL), |
|
155 #ifndef __SYMBIAN32__ |
|
156 BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), |
|
157 #endif |
|
158 BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "ms", "a"), |
|
159 BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"), |
|
160 BUILTIN("unhash", 0, bin_unhash, 1, -1, 0, "adfms", NULL), |
|
161 BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmv", NULL), |
|
162 BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL), |
|
163 #ifndef __SYMBIAN32__ |
|
164 BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL), |
|
165 #endif |
|
166 BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL), |
|
167 BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"), |
|
168 BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"), |
|
169 #ifndef __SYMBIAN32__ |
|
170 BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ARILabcfdipue", NULL), |
|
171 BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL), |
|
172 #endif |
|
173 |
|
174 BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "p", NULL), |
|
175 BUILTIN("mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL), |
|
176 BUILTIN("rm", 0, bin_rm, 1, -1, 0, "dfir", NULL), |
|
177 BUILTIN("rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL), |
|
178 BUILTIN("ls", 0, bin_ls, 0, -1, 0, "1ACFRSWacdfklmpqrstux", NULL), |
|
179 BUILTIN("touch", 0, bin_touch, 1, -1, 0, "acfmrt", NULL), |
|
180 BUILTIN("cp", 0, bin_cp, 2, -1, 0, "Rfipr", NULL), |
|
181 BUILTIN("cat", 0, bin_cat, 0, -1, 0, "benstu", NULL), |
|
182 BUILTIN("more", 0, bin_more, 0, -1, 0, NULL, NULL), |
|
183 }; |
|
184 |
|
185 /****************************************/ |
|
186 /* Builtin Command Hash Table Functions */ |
|
187 /****************************************/ |
|
188 |
|
189 /* hash table containing builtin commands */ |
|
190 |
|
191 /**/ |
|
192 mod_export HashTable builtintab; |
|
193 |
|
194 #ifdef __SYMBIAN32__ |
|
195 extern int pipeUsed; |
|
196 #endif |
|
197 /**/ |
|
198 void |
|
199 createbuiltintable(void) |
|
200 { |
|
201 builtintab = newhashtable(85, "builtintab", NULL); |
|
202 |
|
203 builtintab->hash = hasher; |
|
204 builtintab->emptytable = NULL; |
|
205 builtintab->filltable = NULL; |
|
206 builtintab->cmpnodes = strcmp; |
|
207 builtintab->addnode = addhashnode; |
|
208 builtintab->getnode = gethashnode; |
|
209 builtintab->getnode2 = gethashnode2; |
|
210 builtintab->removenode = removehashnode; |
|
211 builtintab->disablenode = disablehashnode; |
|
212 builtintab->enablenode = enablehashnode; |
|
213 builtintab->freenode = freebuiltinnode; |
|
214 builtintab->printnode = printbuiltinnode; |
|
215 |
|
216 addbuiltins("zsh", builtins, sizeof(builtins)/sizeof(*builtins)); |
|
217 } |
|
218 |
|
219 /* Print a builtin */ |
|
220 |
|
221 /**/ |
|
222 static void |
|
223 printbuiltinnode(HashNode hn, int printflags) |
|
224 { |
|
225 Builtin bn = (Builtin) hn; |
|
226 |
|
227 if (printflags & PRINT_WHENCE_WORD) { |
|
228 printf("%s: builtin command\n", bn->nam); |
|
229 return; |
|
230 } |
|
231 |
|
232 if (printflags & PRINT_WHENCE_CSH) { |
|
233 printf("%s: shell built-in command\n", bn->nam); |
|
234 return; |
|
235 } |
|
236 |
|
237 if (printflags & PRINT_WHENCE_VERBOSE) { |
|
238 printf("%s is a shell builtin\n", bn->nam); |
|
239 return; |
|
240 } |
|
241 |
|
242 /* default is name only */ |
|
243 printf("%s\n", bn->nam); |
|
244 } |
|
245 |
|
246 /**/ |
|
247 static void |
|
248 freebuiltinnode(HashNode hn) |
|
249 { |
|
250 Builtin bn = (Builtin) hn; |
|
251 |
|
252 if(!(bn->flags & BINF_ADDED)) { |
|
253 zsfree(bn->nam); |
|
254 zsfree(bn->optstr); |
|
255 zfree(bn, sizeof(struct builtin)); |
|
256 } |
|
257 } |
|
258 |
|
259 /* Make sure we have space for a new option and increment. */ |
|
260 |
|
261 #define OPT_ALLOC_CHUNK 16 |
|
262 |
|
263 /**/ |
|
264 static int |
|
265 new_optarg(Options ops) |
|
266 { |
|
267 /* Argument index must be a non-zero 6-bit number. */ |
|
268 if (ops->argscount == 63) |
|
269 return 1; |
|
270 if (ops->argsalloc == ops->argscount) { |
|
271 char **newptr = |
|
272 (char **)zhalloc((ops->argsalloc + OPT_ALLOC_CHUNK) * |
|
273 sizeof(char *)); |
|
274 if (ops->argsalloc) |
|
275 memcpy(newptr, ops->args, ops->argsalloc * sizeof(char *)); |
|
276 ops->args = newptr; |
|
277 ops->argsalloc += OPT_ALLOC_CHUNK; |
|
278 } |
|
279 ops->argscount++; |
|
280 return 0; |
|
281 } |
|
282 |
|
283 #ifdef __SYMBIAN32__ |
|
284 |
|
285 #define MAX_CMD_LEN 50 |
|
286 #define SCREEN_SIZE 20 |
|
287 |
|
288 size_t fd_total=0; //holds the current index in the table |
|
289 |
|
290 //need to be filled in the order of command execution... |
|
291 typedef struct fd_tab |
|
292 { |
|
293 char command[MAX_CMD_LEN]; //command name |
|
294 int index; //index of this command in the array... |
|
295 pid_t pid; //pid of this command... |
|
296 int fds[3]; //stdin, stdout, stderr of this command... |
|
297 int hasTerminated; |
|
298 }FD_PERSIST; |
|
299 |
|
300 //interfaces to access this table entry.. |
|
301 FD_PERSIST *fds_root=NULL; |
|
302 |
|
303 FD_PERSIST* getPrev(FD_PERSIST* curr) |
|
304 { |
|
305 if(curr==NULL || curr->index<=0) |
|
306 return NULL; |
|
307 else |
|
308 { |
|
309 return &fds_root[curr->index-1]; |
|
310 } |
|
311 } |
|
312 |
|
313 FD_PERSIST* getNext(FD_PERSIST* curr) |
|
314 { |
|
315 if(curr==NULL || curr->index>=fd_total-1) |
|
316 return NULL; |
|
317 else |
|
318 { |
|
319 return &fds_root[curr->index+1]; |
|
320 } |
|
321 } |
|
322 |
|
323 FD_PERSIST* getFirst() |
|
324 { |
|
325 return fds_root; |
|
326 } |
|
327 |
|
328 FD_PERSIST* GetNextInLoop(FD_PERSIST* curr) |
|
329 { |
|
330 if(curr==NULL || curr->index>=fd_total-1) |
|
331 return fds_root; |
|
332 else |
|
333 { |
|
334 return &fds_root[curr->index+1]; |
|
335 } |
|
336 } |
|
337 |
|
338 FD_PERSIST* getLast() |
|
339 { |
|
340 if(fds_root==NULL || fd_total<=0) |
|
341 return fds_root; |
|
342 else |
|
343 { |
|
344 return &fds_root[fd_total-1]; |
|
345 } |
|
346 } |
|
347 |
|
348 //generate the command arguments to be passed to popen3... |
|
349 char* getCommand(char* name, char** argv, struct options ops, int funcid) |
|
350 { |
|
351 char *pcmd=NULL; |
|
352 size_t tot_allocated=0, curwrite=0; |
|
353 char* ret=NULL; |
|
354 |
|
355 //update the command.. |
|
356 tot_allocated=strlen(name)+2; //for space and \0 |
|
357 pcmd=(char*)calloc(tot_allocated, sizeof(char)); |
|
358 if(pcmd==NULL) |
|
359 { |
|
360 free(pcmd); |
|
361 return ret; |
|
362 } |
|
363 |
|
364 sprintf(pcmd, "%s ", name); |
|
365 curwrite=tot_allocated-1; |
|
366 |
|
367 //update the arguments for the command... |
|
368 if(argv && *argv) |
|
369 { |
|
370 int back_cur=curwrite; |
|
371 int arg_cnt=0; |
|
372 char temp[2]; |
|
373 |
|
374 //hold the count of args... |
|
375 pcmd=(char*)realloc(pcmd, tot_allocated+=2); |
|
376 if(pcmd==NULL) |
|
377 { |
|
378 free(pcmd); |
|
379 return ret; |
|
380 } |
|
381 sprintf(pcmd+curwrite, "%d ", 0); |
|
382 curwrite+=2; |
|
383 |
|
384 //start updating args... |
|
385 while(argv && *argv) |
|
386 { |
|
387 tot_allocated=strlen(*argv)+tot_allocated+1; |
|
388 pcmd=(char*)realloc(pcmd, tot_allocated); |
|
389 if(pcmd==NULL) |
|
390 { |
|
391 free(pcmd); |
|
392 return ret; |
|
393 } |
|
394 sprintf(pcmd+curwrite, "%s ", *argv); |
|
395 curwrite=curwrite+strlen(*argv)+1; |
|
396 |
|
397 arg_cnt++; |
|
398 ++argv; |
|
399 } |
|
400 |
|
401 sprintf(temp,"%d", arg_cnt); |
|
402 pcmd[back_cur]=temp[0]; |
|
403 } |
|
404 else |
|
405 { |
|
406 //update with zero if no args... |
|
407 pcmd=(char*)realloc(pcmd, tot_allocated+=2); |
|
408 if(pcmd==NULL) |
|
409 { |
|
410 free(pcmd); |
|
411 return ret; |
|
412 } |
|
413 |
|
414 sprintf(pcmd+curwrite, "%d ", 0); |
|
415 curwrite+=2; |
|
416 } |
|
417 |
|
418 //START: start updating the options |
|
419 |
|
420 //update ops.ind |
|
421 { |
|
422 int idx=0; |
|
423 pcmd=(char*)realloc(pcmd, tot_allocated+=2); |
|
424 if(pcmd==NULL) |
|
425 { |
|
426 free(pcmd); |
|
427 return ret; |
|
428 } |
|
429 sprintf(pcmd+curwrite, "%d ", 1); |
|
430 curwrite+=2; |
|
431 |
|
432 tot_allocated=tot_allocated+MAX_OPS+2; |
|
433 pcmd=(char*)realloc(pcmd, tot_allocated); |
|
434 if(pcmd==NULL) |
|
435 { |
|
436 free(pcmd); |
|
437 return ret; |
|
438 } |
|
439 |
|
440 while(idx<MAX_OPS) |
|
441 { |
|
442 sprintf(pcmd+curwrite, "%d", ops.ind[idx]); |
|
443 idx++; |
|
444 curwrite++; |
|
445 } |
|
446 |
|
447 sprintf(pcmd+curwrite, " "); |
|
448 curwrite=curwrite+1; |
|
449 } |
|
450 |
|
451 |
|
452 //update ops.args |
|
453 if(ops.args && *ops.args) |
|
454 { |
|
455 int back_cur=curwrite; |
|
456 int arg_cnt=0; |
|
457 char temp[2]; |
|
458 //hold the count of args... |
|
459 pcmd=(char*)realloc(pcmd, tot_allocated+=2); |
|
460 if(pcmd==NULL) |
|
461 { |
|
462 free(pcmd); |
|
463 return ret; |
|
464 } |
|
465 sprintf(pcmd+curwrite, "%d ", 0); |
|
466 curwrite+=2; |
|
467 |
|
468 while(ops.args && *ops.args) |
|
469 { |
|
470 tot_allocated=strlen(*ops.args)+tot_allocated+1; |
|
471 pcmd=(char*)realloc(pcmd, tot_allocated); |
|
472 if(pcmd==NULL) |
|
473 { |
|
474 free(pcmd); |
|
475 return ret; |
|
476 } |
|
477 |
|
478 sprintf(pcmd+curwrite, "%s ", *ops.args); |
|
479 curwrite=curwrite+strlen(*ops.args)+1; |
|
480 |
|
481 ops.args++; |
|
482 arg_cnt++; |
|
483 } |
|
484 |
|
485 sprintf(temp,"%d", arg_cnt); |
|
486 pcmd[back_cur]=temp[0]; |
|
487 } |
|
488 else |
|
489 { |
|
490 //update with zero if no args... |
|
491 pcmd=(char*)realloc(pcmd, tot_allocated+=2); |
|
492 if(pcmd==NULL) |
|
493 { |
|
494 free(pcmd); |
|
495 return ret; |
|
496 } |
|
497 |
|
498 sprintf(pcmd+curwrite, "%d ", 0); |
|
499 curwrite+=2; |
|
500 } |
|
501 |
|
502 //update the ops.argscount |
|
503 pcmd=(char*)realloc(pcmd, tot_allocated+=2); |
|
504 if(pcmd==NULL) |
|
505 { |
|
506 free(pcmd); |
|
507 return ret; |
|
508 } |
|
509 sprintf(pcmd+curwrite, "%d ", ops.argscount); |
|
510 curwrite+=2; |
|
511 |
|
512 //update the ops.argsalloc |
|
513 pcmd=(char*)realloc(pcmd, tot_allocated+=2); |
|
514 if(pcmd==NULL) |
|
515 { |
|
516 free(pcmd); |
|
517 return ret; |
|
518 } |
|
519 sprintf(pcmd+curwrite, "%d ", ops.argsalloc); |
|
520 curwrite+=2; |
|
521 //End: end of options update... |
|
522 |
|
523 |
|
524 //update the function id ... |
|
525 pcmd=(char*)realloc(pcmd, tot_allocated+=1); |
|
526 if(pcmd==NULL) |
|
527 { |
|
528 free(pcmd); |
|
529 return ret; |
|
530 } |
|
531 |
|
532 sprintf(pcmd+curwrite, "%d", funcid); |
|
533 |
|
534 return pcmd; |
|
535 } |
|
536 |
|
537 void clearfds(void) |
|
538 { |
|
539 FD_PERSIST* fdset=getFirst(); |
|
540 while(fdset) |
|
541 { |
|
542 close(fdset->fds[0]); |
|
543 close(fdset->fds[1]); |
|
544 close(fdset->fds[2]); |
|
545 fdset=getNext(fdset); |
|
546 } |
|
547 free(fds_root); |
|
548 fds_root=0; |
|
549 } |
|
550 |
|
551 //this functions handles the transfer of data between commands in |
|
552 //the pipe list |
|
553 |
|
554 int handlePipeCmds(char* name, pid_t pid, int fds[3], int output) |
|
555 { |
|
556 int ret=0; |
|
557 if(fds_root==NULL) |
|
558 { |
|
559 fds_root= (FD_PERSIST*)calloc(1, sizeof(FD_PERSIST)); |
|
560 if(fds_root==NULL) |
|
561 { |
|
562 return (1); |
|
563 } |
|
564 fd_total=1; |
|
565 memset(fds_root->command, 0, MAX_CMD_LEN); |
|
566 strcpy(fds_root->command, name); |
|
567 fds_root->index=0; |
|
568 fds_root->pid=pid; |
|
569 memcpy(fds_root->fds, fds, sizeof(int)*3); |
|
570 fds_root->hasTerminated=0; |
|
571 } |
|
572 else |
|
573 { |
|
574 fds_root=(FD_PERSIST*)realloc(fds_root, |
|
575 sizeof(FD_PERSIST)* (fd_total+1)); |
|
576 |
|
577 if(fds_root==NULL) |
|
578 { |
|
579 free(fds_root); |
|
580 return (1); |
|
581 } |
|
582 |
|
583 memset(fds_root[fd_total].command, 0, MAX_CMD_LEN); |
|
584 strcpy(fds_root[fd_total].command, name); |
|
585 fds_root[fd_total].index=fd_total; |
|
586 fds_root[fd_total].pid=pid; |
|
587 memcpy(fds_root[fd_total].fds, fds, sizeof(int)*3); |
|
588 fds_root[fd_total].hasTerminated=0; |
|
589 fd_total++; |
|
590 } |
|
591 |
|
592 if(output==0 && fd_total>1)//if previous command is the last command |
|
593 { |
|
594 struct timeval tv; |
|
595 char read_buf[512]; |
|
596 int read_cnt=0; |
|
597 fd_set readfds, exceptfds; |
|
598 int line_cnt=0; |
|
599 int nterminated = 0; |
|
600 FD_PERSIST* curr=getFirst(); |
|
601 |
|
602 while(curr!=NULL && (curr->index<fd_total)) |
|
603 { |
|
604 |
|
605 if(nterminated == fd_total) |
|
606 { |
|
607 break; |
|
608 } |
|
609 |
|
610 if(curr->hasTerminated == 1) |
|
611 goto jump_out; |
|
612 |
|
613 for(;;) |
|
614 { |
|
615 int read_idx=0; |
|
616 int max=0; |
|
617 |
|
618 FD_ZERO(&readfds); |
|
619 |
|
620 FD_SET(curr->fds[1], &readfds); |
|
621 FD_SET(curr->fds[2], &readfds); |
|
622 max=MAX(curr->fds[1], curr->fds[2]); |
|
623 |
|
624 |
|
625 FD_ZERO(&exceptfds); |
|
626 FD_SET(curr->fds[1], &exceptfds); |
|
627 FD_SET(curr->fds[2], &exceptfds); |
|
628 if(curr->index==0) |
|
629 { |
|
630 FD_SET(0, &readfds); |
|
631 } |
|
632 |
|
633 tv.tv_sec = 0; |
|
634 tv.tv_usec = 1; |
|
635 if(select(max+1, &readfds, NULL, &exceptfds, &tv) > 0) |
|
636 { |
|
637 if(FD_ISSET(curr->fds[1], &readfds)) |
|
638 { |
|
639 memset(&read_buf[0], 0, 512); |
|
640 read_cnt=read(curr->fds[1], &read_buf[0], 512); |
|
641 |
|
642 if(read_cnt>0) |
|
643 { |
|
644 if(curr->index==(fd_total-1) && |
|
645 strcmp("more", curr->command)) //is the last command |
|
646 { |
|
647 write(1, read_buf, read_cnt); |
|
648 } |
|
649 else |
|
650 { |
|
651 //is more the last command, Zsh's stdio is used |
|
652 //for more |
|
653 if(strcmp("more", curr->command)==0 && |
|
654 curr->index==(fd_total-1)) |
|
655 { |
|
656 if(line_cnt<SCREEN_SIZE) |
|
657 { |
|
658 while(read_idx<read_cnt) |
|
659 { |
|
660 write(1, &read_buf[read_idx], 1); |
|
661 if(read_buf[++read_idx]=='\n') |
|
662 line_cnt++; |
|
663 |
|
664 if(line_cnt==SCREEN_SIZE) |
|
665 break; |
|
666 } |
|
667 } |
|
668 |
|
669 if(line_cnt>=SCREEN_SIZE) |
|
670 { |
|
671 char temp; |
|
672 while(read_idx<read_cnt) |
|
673 { |
|
674 read(0, &temp, 1); |
|
675 switch(temp) |
|
676 { |
|
677 case '\n': |
|
678 { |
|
679 while(read_idx<read_cnt) |
|
680 { |
|
681 if (read_buf[read_idx] == '\n') |
|
682 { |
|
683 read_idx++; |
|
684 break; |
|
685 } |
|
686 |
|
687 write(1, &read_buf[read_idx++], 1); |
|
688 } |
|
689 |
|
690 } |
|
691 break; |
|
692 case 'q': |
|
693 write(1, "\n", 1); |
|
694 goto jump_out; |
|
695 break; |
|
696 case ' ': |
|
697 { |
|
698 line_cnt=0; |
|
699 while(read_idx<read_cnt) |
|
700 { |
|
701 write(1, &read_buf[read_idx], 1); |
|
702 if(read_buf[++read_idx]=='\n') |
|
703 line_cnt++; |
|
704 |
|
705 if(line_cnt==SCREEN_SIZE) |
|
706 break; |
|
707 } |
|
708 } |
|
709 break; |
|
710 default: |
|
711 break; |
|
712 } |
|
713 } |
|
714 } |
|
715 } |
|
716 else |
|
717 //write the output to next command |
|
718 write(getNext(curr)->fds[0], read_buf, read_cnt); |
|
719 |
|
720 } |
|
721 } |
|
722 } |
|
723 |
|
724 if(FD_ISSET(curr->fds[2], &readfds)) |
|
725 { |
|
726 memset(&read_buf[0], 0, 512); |
|
727 read_cnt=read(curr->fds[2], &read_buf[0], 512); |
|
728 |
|
729 if(read_cnt>0) |
|
730 { |
|
731 //write the error on stderr.... |
|
732 write(2, read_buf, read_cnt); |
|
733 } |
|
734 } |
|
735 |
|
736 if(curr->index==0 && FD_ISSET(0, &readfds)) |
|
737 { |
|
738 char temp; |
|
739 read(0, &temp, 1); |
|
740 write(curr->fds[0], &temp, 1); |
|
741 continue; |
|
742 } |
|
743 |
|
744 if(FD_ISSET(curr->fds[1], &exceptfds) || (FD_ISSET(curr->fds[2], &exceptfds))) |
|
745 { |
|
746 if(curr->hasTerminated != 1) |
|
747 nterminated++; |
|
748 curr->hasTerminated = 1; |
|
749 goto jump_out; |
|
750 } |
|
751 break; |
|
752 } |
|
753 else |
|
754 { |
|
755 int status; |
|
756 int wait_pid; |
|
757 FD_PERSIST* prev=getPrev(curr); |
|
758 |
|
759 /* |
|
760 * As signals are not supported(when this code was written) |
|
761 * there is no obvious way to terminate a proces. |
|
762 * |
|
763 * Waiting for a process to terminate may hang the shell as there is no certainity |
|
764 * that the launched process shall terminate and hence |
|
765 * the below logic is used to decide when to wait for a process termination. |
|
766 */ |
|
767 |
|
768 //break if current command is terminated by now... |
|
769 if (curr->hasTerminated) |
|
770 { |
|
771 break; |
|
772 } |
|
773 |
|
774 |
|
775 //break if the current command is terminated... |
|
776 wait_pid = waitpid(curr->pid, &status, WNOHANG); |
|
777 if ((wait_pid == curr->pid) || (wait_pid == -1)) |
|
778 { |
|
779 if(curr->hasTerminated != 1) |
|
780 nterminated++; |
|
781 curr->hasTerminated=1; |
|
782 continue; //To check for the data being output by the curr command ... |
|
783 } |
|
784 |
|
785 /* |
|
786 * Break if the previous command in the pipe list exited. |
|
787 * This is the toughest decision(to break even if the current command exist), because |
|
788 * we will endup in losing the data that the current command might output at later point in time. |
|
789 */ |
|
790 else if (!prev || prev->hasTerminated) |
|
791 { |
|
792 tv.tv_sec = 1; |
|
793 tv.tv_usec = 0; |
|
794 FD_ZERO(&readfds); |
|
795 |
|
796 FD_SET(curr->fds[1], &readfds); |
|
797 FD_SET(curr->fds[2], &readfds); |
|
798 if(!prev) |
|
799 FD_SET(0,&readfds); |
|
800 |
|
801 max=MAX(curr->fds[1], curr->fds[2]); |
|
802 if(select(max+1, &readfds, NULL, NULL, &tv) <=0) |
|
803 { |
|
804 if(curr->hasTerminated != 1) |
|
805 nterminated++; |
|
806 curr->hasTerminated = 1; |
|
807 break; |
|
808 } |
|
809 } |
|
810 |
|
811 //continue the look up again... |
|
812 else |
|
813 { |
|
814 continue; |
|
815 } |
|
816 } |
|
817 } |
|
818 jump_out: |
|
819 curr=GetNextInLoop(curr); |
|
820 } |
|
821 clearfds(); |
|
822 } |
|
823 return ret; |
|
824 } |
|
825 |
|
826 #endif //__SYMBIAN32__ |
|
827 |
|
828 /* execute a builtin handler function after parsing the arguments */ |
|
829 |
|
830 /**/ |
|
831 int |
|
832 execbuiltin(LinkList args, Builtin bn, int input, int output) |
|
833 { |
|
834 char *pp, *name, *optstr; |
|
835 int flags, sense, argc, execop, xtr = isset(XTRACE); |
|
836 struct options ops; |
|
837 int ret; |
|
838 /* initialise options structure */ |
|
839 memset(ops.ind, 0, MAX_OPS*sizeof(unsigned char)); |
|
840 ops.args = NULL; |
|
841 ops.argscount = ops.argsalloc = 0; |
|
842 |
|
843 /* initialize some local variables */ |
|
844 name = (char *) ugetnode(args); |
|
845 |
|
846 if (!bn->handlerfunc) { |
|
847 zwarnnam(name, "autoload failed", NULL, 0); |
|
848 deletebuiltin(bn->nam); |
|
849 return 1; |
|
850 } |
|
851 /* get some information about the command */ |
|
852 flags = bn->flags; |
|
853 optstr = bn->optstr; |
|
854 |
|
855 /* Set up the argument list. */ |
|
856 /* count the arguments */ |
|
857 argc = countlinknodes(args); |
|
858 |
|
859 { |
|
860 /* |
|
861 * Keep all arguments, including options, in an array. |
|
862 * We don't actually need the option part of the argument |
|
863 * after option processing, but it makes XTRACE output |
|
864 * much simpler. |
|
865 */ |
|
866 VARARR(char *, argarr, argc + 1); |
|
867 char **argv; |
|
868 |
|
869 /* |
|
870 * Get the actual arguments, into argv. Remember argarr |
|
871 * may be an array declaration, depending on the compiler. |
|
872 */ |
|
873 argv = argarr; |
|
874 while ((*argv++ = (char *)ugetnode(args))); |
|
875 argv = argarr; |
|
876 |
|
877 /* Sort out the options. */ |
|
878 if (optstr) { |
|
879 char *arg = *argv; |
|
880 /* while arguments look like options ... */ |
|
881 while (arg && |
|
882 /* Must begin with - or maybe + */ |
|
883 ((sense = (*arg == '-')) || |
|
884 ((flags & BINF_PLUSOPTS) && *arg == '+'))) { |
|
885 /* Digits aren't arguments unless the command says they are. */ |
|
886 if (!(flags & BINF_KEEPNUM) && idigit(arg[1])) |
|
887 break; |
|
888 /* For cd and friends, a single dash is not an option. */ |
|
889 if ((flags & BINF_SKIPDASH) && !arg[1]) |
|
890 break; |
|
891 if ((flags & BINF_DASHDASHVALID) && !strcmp(arg, "--")) { |
|
892 /* |
|
893 * Need to skip this before checking whether this is |
|
894 * really an option. |
|
895 */ |
|
896 argv++; |
|
897 break; |
|
898 } |
|
899 /* |
|
900 * Unrecognised options to echo etc. are not really |
|
901 * options. |
|
902 * |
|
903 * Note this flag is not smart enough to handle option |
|
904 * arguments. In fact, ideally it shouldn't be added |
|
905 * to any new builtins, to preserve standard option |
|
906 * handling as much as possible. |
|
907 */ |
|
908 if (flags & BINF_SKIPINVALID) { |
|
909 char *p = arg; |
|
910 if (optstr) |
|
911 while (*++p && strchr(optstr, (int) *p)); |
|
912 else |
|
913 p++; |
|
914 if (*p) |
|
915 break; |
|
916 } |
|
917 /* handle -- or - (ops.ind['-']), and + |
|
918 * (ops.ind['-'] and ops.ind['+']) */ |
|
919 if (arg[1] == '-') |
|
920 arg++; |
|
921 if (!arg[1]) { |
|
922 ops.ind['-'] = 1; |
|
923 if (!sense) |
|
924 ops.ind['+'] = 1; |
|
925 } |
|
926 /* save options in ops, as long as they are in bn->optstr */ |
|
927 while (*++arg) { |
|
928 char *optptr; |
|
929 if ((optptr = strchr(optstr, execop = (int)*arg))) { |
|
930 ops.ind[(int)*arg] = (sense) ? 1 : 2; |
|
931 if (optptr[1] == ':') { |
|
932 char *argptr = NULL; |
|
933 if (optptr[2] == ':') { |
|
934 if (arg[1]) |
|
935 argptr = arg+1; |
|
936 /* Optional argument in same word*/ |
|
937 } else if (optptr[2] == '%') { |
|
938 /* Optional numeric argument in same |
|
939 * or next word. */ |
|
940 if (arg[1] && idigit(arg[1])) |
|
941 argptr = arg+1; |
|
942 else if (argv[1] && idigit(*argv[1])) |
|
943 argptr = arg = *++argv; |
|
944 } else { |
|
945 /* Mandatory argument */ |
|
946 if (arg[1]) |
|
947 argptr = arg+1; |
|
948 else if ((arg = *++argv)) |
|
949 argptr = arg; |
|
950 else { |
|
951 zwarnnam(name, "argument expected: -%c", |
|
952 NULL, execop); |
|
953 return 1; |
|
954 } |
|
955 } |
|
956 if (argptr) { |
|
957 if (new_optarg(&ops)) { |
|
958 zwarnnam(name, |
|
959 "too many option arguments", |
|
960 NULL, 0); |
|
961 return 1; |
|
962 } |
|
963 ops.ind[execop] |= ops.argscount << 2; |
|
964 ops.args[ops.argscount-1] = argptr; |
|
965 while (arg[1]) |
|
966 arg++; |
|
967 } |
|
968 } |
|
969 } else |
|
970 break; |
|
971 } |
|
972 /* The above loop may have exited on an invalid option. (We * |
|
973 * assume that any option requiring metafication is invalid.) */ |
|
974 if (*arg) { |
|
975 if(*arg == Meta) |
|
976 *++arg ^= 32; |
|
977 zwarn("bad option: -%c", NULL, *arg); |
|
978 return 1; |
|
979 } |
|
980 arg = *++argv; |
|
981 /* for the "print" builtin, the options after -R are treated as |
|
982 options to "echo" */ |
|
983 if ((flags & BINF_PRINTOPTS) && ops.ind['R'] && |
|
984 !ops.ind['f']) { |
|
985 optstr = "ne"; |
|
986 flags |= BINF_SKIPINVALID; |
|
987 } |
|
988 /* the option -- indicates the end of the options */ |
|
989 if (ops.ind['-']) |
|
990 break; |
|
991 } |
|
992 } |
|
993 |
|
994 /* handle built-in options, for overloaded handler functions */ |
|
995 if ((pp = bn->defopts)) { |
|
996 while (*pp) { |
|
997 /* only if not already set */ |
|
998 if (!ops.ind[(int)*pp]) |
|
999 ops.ind[(int)*pp] = 1; |
|
1000 pp++; |
|
1001 } |
|
1002 } |
|
1003 |
|
1004 /* Fix the argument count by subtracting option arguments */ |
|
1005 argc -= argv - argarr; |
|
1006 |
|
1007 if (errflag) { |
|
1008 errflag = 0; |
|
1009 return 1; |
|
1010 } |
|
1011 |
|
1012 /* check that the argument count lies within the specified bounds */ |
|
1013 if (argc < bn->minargs || (argc > bn->maxargs && bn->maxargs != -1)) { |
|
1014 zwarnnam(name, (argc < bn->minargs) |
|
1015 ? "not enough arguments" : "too many arguments", NULL, 0); |
|
1016 return 1; |
|
1017 } |
|
1018 |
|
1019 /* display execution trace information, if required */ |
|
1020 if (xtr) { |
|
1021 /* Use full argument list including options for trace output */ |
|
1022 char **fullargv = argarr; |
|
1023 printprompt4(); |
|
1024 fprintf(xtrerr, "%s", name); |
|
1025 while (*fullargv) { |
|
1026 fputc(' ', xtrerr); |
|
1027 quotedzputs(*fullargv++, xtrerr); |
|
1028 } |
|
1029 fputc('\n', xtrerr); |
|
1030 fflush(xtrerr); |
|
1031 } |
|
1032 |
|
1033 if(input||output) |
|
1034 { |
|
1035 int fds[3]; |
|
1036 int pid; |
|
1037 char* pcmd=getCommand(name, argv, ops, bn->funcid); |
|
1038 //zsh should call a builtin function.. |
|
1039 // so have a flag to denote that |
|
1040 if ( (pid=popen3("zsh", pcmd, environ, fds)) == -1) |
|
1041 { |
|
1042 printf("zsh: process creation failed for command %s\n",name); |
|
1043 } |
|
1044 else |
|
1045 { |
|
1046 ret=handlePipeCmds(name, pid, &fds[0], output); |
|
1047 } |
|
1048 free(pcmd); |
|
1049 } |
|
1050 else |
|
1051 { |
|
1052 #ifdef __SYMBIAN32__ |
|
1053 /* The part of code added here is to handle the Unix style root directory name. * |
|
1054 * Here, On Symbian OS, the root dir name is the root dir of the PWD. So, we check * |
|
1055 * to see if the first char is "/", it is supposed to be changed with root of the present * |
|
1056 * working directory. Also, for this the space allocated for the *argv is increases by 2 * |
|
1057 * bytes in "string.c" to accomodate a maximum of 2 letter more. Since a drive name can be * |
|
1058 * of maxlength 2, drive name followed by a colon (":") |
|
1059 */ |
|
1060 if(*argv && *argv[0] == '\\') |
|
1061 { |
|
1062 char dir[MAXPATHLEN]; |
|
1063 getcwd(dir,MAXPATHLEN); |
|
1064 dir[2] = '\0'; |
|
1065 strcat(dir,*argv); |
|
1066 strcpy(*argv,dir); |
|
1067 } |
|
1068 #endif |
|
1069 |
|
1070 /* call the handler function, and return its return value */ |
|
1071 ret= (*(bn->handlerfunc)) (name, argv, &ops, bn->funcid); |
|
1072 } |
|
1073 } |
|
1074 return ret; |
|
1075 } |
|
1076 |
|
1077 #ifndef __SYMBIAN32__ |
|
1078 /* Enable/disable an element in one of the internal hash tables. * |
|
1079 * With no arguments, it lists all the currently enabled/disabled * |
|
1080 * elements in that particular hash table. */ |
|
1081 |
|
1082 /**/ |
|
1083 int |
|
1084 bin_enable(char *name, char **argv, Options ops, int func) |
|
1085 { |
|
1086 HashTable ht; |
|
1087 HashNode hn; |
|
1088 ScanFunc scanfunc; |
|
1089 Patprog pprog; |
|
1090 int flags1 = 0, flags2 = 0; |
|
1091 int match = 0, returnval = 0; |
|
1092 |
|
1093 /* Find out which hash table we are working with. */ |
|
1094 if (OPT_ISSET(ops,'f')) |
|
1095 ht = shfunctab; |
|
1096 else if (OPT_ISSET(ops,'r')) |
|
1097 ht = reswdtab; |
|
1098 else if (OPT_ISSET(ops,'s')) |
|
1099 ht = sufaliastab; |
|
1100 else if (OPT_ISSET(ops,'a')) |
|
1101 ht = aliastab; |
|
1102 else |
|
1103 ht = builtintab; |
|
1104 |
|
1105 /* Do we want to enable or disable? */ |
|
1106 if (func == BIN_ENABLE) { |
|
1107 flags2 = DISABLED; |
|
1108 scanfunc = ht->enablenode; |
|
1109 } else { |
|
1110 flags1 = DISABLED; |
|
1111 scanfunc = ht->disablenode; |
|
1112 } |
|
1113 |
|
1114 /* Given no arguments, print the names of the enabled/disabled elements * |
|
1115 * in this hash table. If func == BIN_ENABLE, then scanhashtable will * |
|
1116 * print nodes NOT containing the DISABLED flag, else scanhashtable will * |
|
1117 * print nodes containing the DISABLED flag. */ |
|
1118 if (!*argv) { |
|
1119 queue_signals(); |
|
1120 scanhashtable(ht, 1, flags1, flags2, ht->printnode, 0); |
|
1121 unqueue_signals(); |
|
1122 return 0; |
|
1123 } |
|
1124 |
|
1125 /* With -m option, treat arguments as glob patterns. */ |
|
1126 if (OPT_ISSET(ops,'m')) { |
|
1127 for (; *argv; argv++) { |
|
1128 /* parse pattern */ |
|
1129 tokenize(*argv); |
|
1130 if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { |
|
1131 queue_signals(); |
|
1132 match += scanmatchtable(ht, pprog, 0, 0, scanfunc, 0); |
|
1133 unqueue_signals(); |
|
1134 } |
|
1135 else { |
|
1136 untokenize(*argv); |
|
1137 zwarnnam(name, "bad pattern : %s", *argv, 0); |
|
1138 returnval = 1; |
|
1139 } |
|
1140 } |
|
1141 /* If we didn't match anything, we return 1. */ |
|
1142 if (!match) |
|
1143 returnval = 1; |
|
1144 return returnval; |
|
1145 } |
|
1146 |
|
1147 /* Take arguments literally -- do not glob */ |
|
1148 queue_signals(); |
|
1149 for (; *argv; argv++) { |
|
1150 if ((hn = ht->getnode2(ht, *argv))) { |
|
1151 scanfunc(hn, 0); |
|
1152 } else { |
|
1153 zwarnnam(name, "no such hash table element: %s", *argv, 0); |
|
1154 returnval = 1; |
|
1155 } |
|
1156 } |
|
1157 unqueue_signals(); |
|
1158 return returnval; |
|
1159 } |
|
1160 #endif //__SYMBIAN32__ |
|
1161 |
|
1162 /* set: either set the shell options, or set the shell arguments, * |
|
1163 * or declare an array, or show various things */ |
|
1164 |
|
1165 /**/ |
|
1166 int |
|
1167 bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) |
|
1168 { |
|
1169 int action, optno, array = 0, hadopt = 0, |
|
1170 hadplus = 0, hadend = 0, sort = 0; |
|
1171 char **x, *arrayname = NULL; |
|
1172 |
|
1173 /* Obsolescent sh compatibility: set - is the same as set +xv * |
|
1174 * and set - args is the same as set +xv -- args */ |
|
1175 if (*args && **args == '-' && !args[0][1]) { |
|
1176 dosetopt(VERBOSE, 0, 0); |
|
1177 dosetopt(XTRACE, 0, 0); |
|
1178 if (!args[1]) |
|
1179 return 0; |
|
1180 } |
|
1181 |
|
1182 /* loop through command line options (begins with "-" or "+") */ |
|
1183 while (*args && (**args == '-' || **args == '+')) { |
|
1184 action = (**args == '-'); |
|
1185 hadplus |= !action; |
|
1186 if(!args[0][1]) |
|
1187 *args = "--"; |
|
1188 while (*++*args) { |
|
1189 if(**args == Meta) |
|
1190 *++*args ^= 32; |
|
1191 if(**args != '-' || action) |
|
1192 hadopt = 1; |
|
1193 /* The pseudo-option `--' signifies the end of options. */ |
|
1194 if (**args == '-') { |
|
1195 hadend = 1; |
|
1196 args++; |
|
1197 goto doneoptions; |
|
1198 } else if (**args == 'o') { |
|
1199 if (!*++*args) |
|
1200 args++; |
|
1201 if (!*args) { |
|
1202 printoptionstates(hadplus); |
|
1203 inittyptab(); |
|
1204 return 0; |
|
1205 } |
|
1206 if(!(optno = optlookup(*args))) |
|
1207 zwarnnam(nam, "no such option: %s", *args, 0); |
|
1208 else if(dosetopt(optno, action, 0)) |
|
1209 zwarnnam(nam, "can't change option: %s", *args, 0); |
|
1210 break; |
|
1211 } else if(**args == 'A') { |
|
1212 if(!*++*args) |
|
1213 args++; |
|
1214 array = action ? 1 : -1; |
|
1215 arrayname = *args; |
|
1216 if (!arrayname) |
|
1217 goto doneoptions; |
|
1218 else if (!isset(KSHARRAYS)) |
|
1219 { |
|
1220 args++; |
|
1221 goto doneoptions; |
|
1222 } |
|
1223 break; |
|
1224 } else if (**args == 's') |
|
1225 sort = action ? 1 : -1; |
|
1226 else { |
|
1227 if (!(optno = optlookupc(**args))) |
|
1228 zwarnnam(nam, "bad option: -%c", NULL, **args); |
|
1229 else if(dosetopt(optno, action, 0)) |
|
1230 zwarnnam(nam, "can't change option: -%c", NULL, **args); |
|
1231 } |
|
1232 } |
|
1233 args++; |
|
1234 } |
|
1235 doneoptions: |
|
1236 inittyptab(); |
|
1237 |
|
1238 /* Show the parameters, possibly with values */ |
|
1239 queue_signals(); |
|
1240 if (!arrayname) |
|
1241 { |
|
1242 if (!hadopt && !*args) |
|
1243 scanhashtable(paramtab, 1, 0, 0, paramtab->printnode, |
|
1244 hadplus ? PRINT_NAMEONLY : 0); |
|
1245 |
|
1246 if (array) { |
|
1247 /* display arrays */ |
|
1248 scanhashtable(paramtab, 1, PM_ARRAY, 0, paramtab->printnode, |
|
1249 hadplus ? PRINT_NAMEONLY : 0); |
|
1250 } |
|
1251 if (!*args && !hadend) { |
|
1252 unqueue_signals(); |
|
1253 return 0; |
|
1254 } |
|
1255 } |
|
1256 if (sort) |
|
1257 qsort(args, arrlen(args), sizeof(char *), |
|
1258 sort > 0 ? strpcmp : invstrpcmp); |
|
1259 if (array) { |
|
1260 /* create an array with the specified elements */ |
|
1261 char **a = NULL, **y; |
|
1262 int len = arrlen(args); |
|
1263 |
|
1264 if (array < 0 && (a = getaparam(arrayname))) { |
|
1265 int al = arrlen(a); |
|
1266 |
|
1267 if (al > len) |
|
1268 len = al; |
|
1269 } |
|
1270 for (x = y = zalloc((len + 1) * sizeof(char *)); len--; a++) { |
|
1271 if (!*args) |
|
1272 args = a; |
|
1273 *y++ = ztrdup(*args++); |
|
1274 } |
|
1275 *y++ = NULL; |
|
1276 setaparam(arrayname, x); |
|
1277 } else { |
|
1278 /* set shell arguments */ |
|
1279 freearray(pparams); |
|
1280 pparams = zarrdup(args); |
|
1281 } |
|
1282 unqueue_signals(); |
|
1283 return 0; |
|
1284 } |
|
1285 |
|
1286 /**** directory-handling builtins ****/ |
|
1287 |
|
1288 /**/ |
|
1289 int doprintdir = 0; /* set in exec.c (for autocd) */ |
|
1290 |
|
1291 /* pwd: display the name of the current directory */ |
|
1292 |
|
1293 /**/ |
|
1294 int |
|
1295 bin_pwd(UNUSED(char *name), UNUSED(char **argv), Options ops, UNUSED(int func)) |
|
1296 { |
|
1297 char maxpath[126]; |
|
1298 |
|
1299 if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'P') || |
|
1300 (isset(CHASELINKS) && !OPT_ISSET(ops,'L'))) |
|
1301 printf("%s\n", getcwd(maxpath, 126)); |
|
1302 else { |
|
1303 zputs(pwd, stdout); |
|
1304 putchar('\n'); |
|
1305 } |
|
1306 return 0; |
|
1307 } |
|
1308 |
|
1309 |
|
1310 /* the directory stack */ |
|
1311 |
|
1312 /**/ |
|
1313 mod_export LinkList dirstack; |
|
1314 |
|
1315 /* dirs: list the directory stack, or replace it with a provided list */ |
|
1316 |
|
1317 /**/ |
|
1318 int |
|
1319 bin_dirs(UNUSED(char *name), char **argv, Options ops, UNUSED(int func)) |
|
1320 { |
|
1321 LinkList l; |
|
1322 |
|
1323 queue_signals(); |
|
1324 /* with -v, -p or no arguments display the directory stack */ |
|
1325 if (!(*argv || OPT_ISSET(ops,'c')) || OPT_ISSET(ops,'v') || |
|
1326 OPT_ISSET(ops,'p')) { |
|
1327 LinkNode node; |
|
1328 char *fmt; |
|
1329 int pos = 1; |
|
1330 |
|
1331 /* with the -v option, display a numbered list, starting at zero */ |
|
1332 if (OPT_ISSET(ops,'v')) { |
|
1333 printf("0\t"); |
|
1334 fmt = "\n%d\t"; |
|
1335 /* with the -p option, display entries one per line */ |
|
1336 } else if (OPT_ISSET(ops,'p')) |
|
1337 fmt = "\n"; |
|
1338 else |
|
1339 fmt = " "; |
|
1340 if (OPT_ISSET(ops,'l')) |
|
1341 fputs(pwd, stdout); |
|
1342 else |
|
1343 fprintdir(pwd, stdout); |
|
1344 for (node = firstnode(dirstack); node; incnode(node)) { |
|
1345 printf(fmt, pos++); |
|
1346 if (OPT_ISSET(ops,'l')) |
|
1347 fputs(getdata(node), stdout); |
|
1348 else |
|
1349 fprintdir(getdata(node), stdout); |
|
1350 |
|
1351 } |
|
1352 unqueue_signals(); |
|
1353 putchar('\n'); |
|
1354 return 0; |
|
1355 } |
|
1356 /* replace the stack with the specified directories */ |
|
1357 l = znewlinklist(); |
|
1358 while (*argv) |
|
1359 zaddlinknode(l, ztrdup(*argv++)); |
|
1360 freelinklist(dirstack, freestr); |
|
1361 dirstack = l; |
|
1362 unqueue_signals(); |
|
1363 return 0; |
|
1364 } |
|
1365 |
|
1366 /* cd, chdir, pushd, popd */ |
|
1367 |
|
1368 /**/ |
|
1369 void |
|
1370 set_pwd_env(void) |
|
1371 { |
|
1372 Param pm; |
|
1373 |
|
1374 /* update the PWD and OLDPWD shell parameters */ |
|
1375 |
|
1376 pm = (Param) paramtab->getnode(paramtab, "PWD"); |
|
1377 if (pm && PM_TYPE(pm->flags) != PM_SCALAR) { |
|
1378 pm->flags &= ~PM_READONLY; |
|
1379 unsetparam_pm(pm, 0, 1); |
|
1380 } |
|
1381 |
|
1382 pm = (Param) paramtab->getnode(paramtab, "OLDPWD"); |
|
1383 if (pm && PM_TYPE(pm->flags) != PM_SCALAR) { |
|
1384 pm->flags &= ~PM_READONLY; |
|
1385 unsetparam_pm(pm, 0, 1); |
|
1386 } |
|
1387 |
|
1388 setsparam("PWD", ztrdup(pwd)); |
|
1389 setsparam("OLDPWD", ztrdup(oldpwd)); |
|
1390 |
|
1391 pm = (Param) paramtab->getnode(paramtab, "PWD"); |
|
1392 if (!(pm->flags & PM_EXPORTED)) |
|
1393 addenv(pm, pwd); |
|
1394 pm = (Param) paramtab->getnode(paramtab, "OLDPWD"); |
|
1395 if (!(pm->flags & PM_EXPORTED)) |
|
1396 addenv(pm, oldpwd); |
|
1397 } |
|
1398 |
|
1399 /* set if we are resolving links to their true paths */ |
|
1400 static int chasinglinks; |
|
1401 |
|
1402 /* The main pwd changing function. The real work is done by other * |
|
1403 * functions. cd_get_dest() does the initial argument processing; * |
|
1404 * cd_do_chdir() actually changes directory, if possible; cd_new_pwd() * |
|
1405 * does the ancillary processing associated with actually changing * |
|
1406 * directory. */ |
|
1407 |
|
1408 /**/ |
|
1409 int |
|
1410 bin_cd(char *nam, char **argv, Options ops, int func) |
|
1411 { |
|
1412 LinkNode dir; |
|
1413 struct stat st1, st2; |
|
1414 |
|
1415 if (isset(RESTRICTED)) { |
|
1416 zwarnnam(nam, "restricted", NULL, 0); |
|
1417 return 1; |
|
1418 } |
|
1419 doprintdir = (doprintdir == -1); |
|
1420 |
|
1421 chasinglinks = OPT_ISSET(ops,'P') || |
|
1422 (isset(CHASELINKS) && !OPT_ISSET(ops,'L')); |
|
1423 queue_signals(); |
|
1424 zpushnode(dirstack, ztrdup(pwd)); |
|
1425 if (!(dir = cd_get_dest(nam, argv, OPT_ISSET(ops,'s'), func))) { |
|
1426 zsfree(getlinknode(dirstack)); |
|
1427 unqueue_signals(); |
|
1428 return 1; |
|
1429 } |
|
1430 cd_new_pwd(func, dir); |
|
1431 |
|
1432 if (stat(unmeta(pwd), &st1) < 0 && errno!=EACCES) { |
|
1433 setjobpwd(); |
|
1434 zsfree(pwd); |
|
1435 pwd = metafy(zgetcwd(), -1, META_DUP); |
|
1436 } else if (stat(".", &st2) < 0) |
|
1437 chdir(unmeta(pwd)); |
|
1438 else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) { |
|
1439 if (chasinglinks) { |
|
1440 setjobpwd(); |
|
1441 zsfree(pwd); |
|
1442 pwd = metafy(zgetcwd(), -1, META_DUP); |
|
1443 } else { |
|
1444 chdir(unmeta(pwd)); |
|
1445 } |
|
1446 } |
|
1447 unqueue_signals(); |
|
1448 return 0; |
|
1449 } |
|
1450 |
|
1451 /* Get directory to chdir to */ |
|
1452 |
|
1453 /**/ |
|
1454 static LinkNode |
|
1455 cd_get_dest(char *nam, char **argv, int hard, int func) |
|
1456 { |
|
1457 LinkNode dir = NULL; |
|
1458 LinkNode target; |
|
1459 char *dest; |
|
1460 |
|
1461 if (!argv[0]) { |
|
1462 if (func == BIN_POPD && !nextnode(firstnode(dirstack))) { |
|
1463 zwarnnam(nam, "directory stack empty", NULL, 0); |
|
1464 return NULL; |
|
1465 } |
|
1466 if (func == BIN_PUSHD && unset(PUSHDTOHOME)) |
|
1467 dir = nextnode(firstnode(dirstack)); |
|
1468 if (dir) |
|
1469 zinsertlinknode(dirstack, dir, getlinknode(dirstack)); |
|
1470 else if (func != BIN_POPD) |
|
1471 zpushnode(dirstack, ztrdup(home)); |
|
1472 } else if (!argv[1]) { |
|
1473 int dd; |
|
1474 char *end; |
|
1475 |
|
1476 doprintdir++; |
|
1477 if (argv[0][1] && (argv[0][0] == '+' || argv[0][0] == '-')) { |
|
1478 dd = zstrtol(argv[0] + 1, &end, 10); |
|
1479 if (*end == '\0') { |
|
1480 if ((argv[0][0] == '+') ^ isset(PUSHDMINUS)) |
|
1481 for (dir = firstnode(dirstack); dir && dd; dd--, incnode(dir)); |
|
1482 else |
|
1483 for (dir = lastnode(dirstack); dir != (LinkNode) dirstack && dd; |
|
1484 dd--, dir = prevnode(dir)); |
|
1485 if (!dir || dir == (LinkNode) dirstack) { |
|
1486 zwarnnam(nam, "no such entry in dir stack", NULL, 0); |
|
1487 return NULL; |
|
1488 } |
|
1489 } |
|
1490 } |
|
1491 if (!dir) |
|
1492 zpushnode(dirstack, ztrdup(strcmp(argv[0], "-") |
|
1493 ? (doprintdir--, argv[0]) : oldpwd)); |
|
1494 } else { |
|
1495 char *u, *d; |
|
1496 int len1, len2, len3; |
|
1497 |
|
1498 if (!(u = strstr(pwd, argv[0]))) { |
|
1499 zwarnnam(nam, "string not in pwd: %s", argv[0], 0); |
|
1500 return NULL; |
|
1501 } |
|
1502 len1 = strlen(argv[0]); |
|
1503 len2 = strlen(argv[1]); |
|
1504 len3 = u - pwd; |
|
1505 d = (char *)zalloc(len3 + len2 + strlen(u + len1) + 1); |
|
1506 strncpy(d, pwd, len3); |
|
1507 strcpy(d + len3, argv[1]); |
|
1508 strcat(d, u + len1); |
|
1509 zpushnode(dirstack, d); |
|
1510 doprintdir++; |
|
1511 } |
|
1512 |
|
1513 target = dir; |
|
1514 if (func == BIN_POPD) { |
|
1515 if (!dir) { |
|
1516 target = dir = firstnode(dirstack); |
|
1517 } else if (dir != firstnode(dirstack)) { |
|
1518 return dir; |
|
1519 } |
|
1520 dir = nextnode(dir); |
|
1521 } |
|
1522 if (!dir) { |
|
1523 dir = firstnode(dirstack); |
|
1524 } |
|
1525 if (!(dest = cd_do_chdir(nam, getdata(dir), hard))) { |
|
1526 if (!target) |
|
1527 zsfree(getlinknode(dirstack)); |
|
1528 if (func == BIN_POPD) |
|
1529 zsfree(remnode(dirstack, dir)); |
|
1530 return NULL; |
|
1531 } |
|
1532 if (dest != (char *)getdata(dir)) { |
|
1533 zsfree(getdata(dir)); |
|
1534 setdata(dir, dest); |
|
1535 } |
|
1536 return target ? target : dir; |
|
1537 } |
|
1538 |
|
1539 /* Change to given directory, if possible. This function works out * |
|
1540 * exactly how the directory should be interpreted, including cdpath * |
|
1541 * and CDABLEVARS. For each possible interpretation of the given * |
|
1542 * path, this calls cd_try_chdir(), which attempts to chdir to that * |
|
1543 * particular path. */ |
|
1544 |
|
1545 /**/ |
|
1546 static char * |
|
1547 cd_do_chdir(char *cnam, char *dest, int hard) |
|
1548 { |
|
1549 char **pp, *ret; |
|
1550 int hasdot = 0, eno = ENOENT; |
|
1551 /* |
|
1552 * nocdpath indicates that cdpath should not be used. |
|
1553 * This is the case iff dest is a relative path |
|
1554 * whose first segment is . or .., but if the path is |
|
1555 * absolute then cdpath won't be used anyway. |
|
1556 */ |
|
1557 int nocdpath; |
|
1558 #ifdef __CYGWIN__ |
|
1559 /* |
|
1560 * Normalize path under Cygwin to avoid messing with |
|
1561 * DOS style names with drives in them |
|
1562 */ |
|
1563 static char buf[PATH_MAX]; |
|
1564 #ifndef _SYS_CYGWIN_H |
|
1565 void cygwin_conv_to_posix_path(const char *, char *); |
|
1566 #endif |
|
1567 |
|
1568 cygwin_conv_to_posix_path(dest, buf); |
|
1569 dest = buf; |
|
1570 #endif |
|
1571 nocdpath = dest[0] == '.' && |
|
1572 (dest[1] == '/' || dest[1] == '\\' || !dest[1] || (dest[1] == '.' && |
|
1573 (dest[2] == '/' || dest[2] == '\\' || !dest[2]))); |
|
1574 |
|
1575 /* |
|
1576 * If we have an absolute path, use it as-is only |
|
1577 */ |
|
1578 if (*dest == '/' || *dest == '\\') { |
|
1579 if ((ret = cd_try_chdir(NULL, dest, hard))) |
|
1580 return ret; |
|
1581 zwarnnam(cnam, "%e: %s", dest, errno); |
|
1582 return NULL; |
|
1583 } |
|
1584 |
|
1585 /* if cdpath is being used, check it for . */ |
|
1586 if (!nocdpath) |
|
1587 for (pp = cdpath; *pp; pp++) |
|
1588 if (!(*pp)[0] || ((*pp)[0] == '.' && (*pp)[1] == '\0')) |
|
1589 hasdot = 1; |
|
1590 /* if there is no . in cdpath (or it is not being used), try the directory |
|
1591 as-is (i.e. from .) */ |
|
1592 if (!hasdot) { |
|
1593 if ((ret = cd_try_chdir(NULL, dest, hard))) |
|
1594 return ret; |
|
1595 if (errno != ENOENT) |
|
1596 eno = errno; |
|
1597 } |
|
1598 /* if cdpath is being used, try given directory relative to each element in |
|
1599 cdpath in turn */ |
|
1600 if (!nocdpath) |
|
1601 for (pp = cdpath; *pp; pp++) { |
|
1602 if ((ret = cd_try_chdir(*pp, dest, hard))) { |
|
1603 if (strcmp(*pp, ".")) { |
|
1604 doprintdir++; |
|
1605 } |
|
1606 return ret; |
|
1607 } |
|
1608 if (errno != ENOENT) |
|
1609 eno = errno; |
|
1610 } |
|
1611 |
|
1612 /* handle the CDABLEVARS option */ |
|
1613 if ((ret = cd_able_vars(dest))) { |
|
1614 if ((ret = cd_try_chdir(NULL, ret,hard))) { |
|
1615 doprintdir++; |
|
1616 return ret; |
|
1617 } |
|
1618 if (errno != ENOENT) |
|
1619 eno = errno; |
|
1620 } |
|
1621 |
|
1622 /* If we got here, it means that we couldn't chdir to any of the |
|
1623 multitudinous possible paths allowed by zsh. We've run out of options! |
|
1624 Add more here! */ |
|
1625 |
|
1626 if(eno) |
|
1627 zwarnnam(cnam, "%e: %s", dest, eno); |
|
1628 |
|
1629 return NULL; |
|
1630 } |
|
1631 |
|
1632 /* If the CDABLEVARS option is set, return the new * |
|
1633 * interpretation of the given path. */ |
|
1634 |
|
1635 /**/ |
|
1636 char * |
|
1637 cd_able_vars(char *s) |
|
1638 { |
|
1639 char *rest, save; |
|
1640 |
|
1641 if (isset(CDABLEVARS)) { |
|
1642 for (rest = s; *rest && *rest != '/'; rest++); |
|
1643 save = *rest; |
|
1644 *rest = 0; |
|
1645 s = getnameddir(s); |
|
1646 *rest = save; |
|
1647 |
|
1648 if (s && *rest) |
|
1649 s = dyncat(s, rest); |
|
1650 |
|
1651 return s; |
|
1652 } |
|
1653 return NULL; |
|
1654 } |
|
1655 |
|
1656 /* Attempt to change to a single given directory. The directory, * |
|
1657 * for the convenience of the calling function, may be provided in * |
|
1658 * two parts, which must be concatenated before attempting to chdir. * |
|
1659 * Returns NULL if the chdir fails. If the directory change is * |
|
1660 * possible, it is performed, and a pointer to the new full pathname * |
|
1661 * is returned. */ |
|
1662 |
|
1663 /**/ |
|
1664 static char * |
|
1665 cd_try_chdir(char *pfix, char *dest, int hard) |
|
1666 { |
|
1667 char *buf; |
|
1668 int dlen, dochaselinks = 0; |
|
1669 |
|
1670 /* handle directory prefix */ |
|
1671 if (pfix && *pfix) { |
|
1672 if (*pfix == '/' || *pfix == '\\' ) |
|
1673 #ifdef __CYGWIN__ |
|
1674 /* NB: Don't turn "/"+"bin" into "//"+"bin" by mistake! "//bin" may * |
|
1675 * not be what user really wants (probably wants "/bin"), but * |
|
1676 * "//bin" could be valid too (see fixdir())! This is primarily for * |
|
1677 * handling CDPATH correctly. */ |
|
1678 buf = tricat(pfix, ( pfix[1] == '\0' ? "" : "/" ), dest); |
|
1679 #else |
|
1680 buf = tricat(pfix, "/", dest); |
|
1681 #endif |
|
1682 else { |
|
1683 int pfl = strlen(pfix); |
|
1684 dlen = strlen(pwd); |
|
1685 |
|
1686 buf = zalloc(dlen + pfl + strlen(dest) + 3); |
|
1687 strcpy(buf, pwd); |
|
1688 #ifdef __SYMBIAN32__ |
|
1689 buf[dlen] = '\\'; |
|
1690 #else |
|
1691 buf[dlen] = '/' |
|
1692 #endif |
|
1693 strcpy(buf + dlen + 1, pfix); |
|
1694 buf[dlen + 1 + pfl] = '/'; |
|
1695 strcpy(buf + dlen + pfl + 2, dest); |
|
1696 } |
|
1697 } else if (*dest == '/' || *dest == '\\') |
|
1698 buf = ztrdup(dest); |
|
1699 else { |
|
1700 dlen = strlen(pwd); |
|
1701 if (pwd[dlen-1] == '/' || pwd[dlen-1] == '\\') |
|
1702 --dlen; |
|
1703 buf = zalloc(dlen + strlen(dest) + 2); |
|
1704 |
|
1705 if(!strstr(dest, ":")) |
|
1706 { |
|
1707 //do only if destination path is actual path |
|
1708 strcpy(buf, pwd); |
|
1709 buf[dlen] = '\\'; |
|
1710 strcpy(buf + dlen + 1, dest); |
|
1711 } |
|
1712 else |
|
1713 { |
|
1714 size_t des=strlen(dest); |
|
1715 strcpy(buf, dest); |
|
1716 buf[des] = '\\'; |
|
1717 buf[des+1] = '\0'; |
|
1718 } |
|
1719 |
|
1720 } |
|
1721 |
|
1722 /* Normalise path. See the definition of fixdir() for what this means. |
|
1723 * We do not do this if we are chasing links. |
|
1724 */ |
|
1725 if (!chasinglinks) |
|
1726 dochaselinks = fixdir(buf); |
|
1727 else |
|
1728 unmetafy(buf, &dlen); |
|
1729 |
|
1730 /* We try the full path first. If that fails, try the |
|
1731 * argument to cd relatively. This is useful if the cwd |
|
1732 * or a parent directory is renamed in the interim. |
|
1733 */ |
|
1734 if (lchdir(buf, NULL, hard)/* && lchdir(dest, NULL, hard)*/) { |
|
1735 free(buf); |
|
1736 return NULL; |
|
1737 } |
|
1738 /* the chdir succeeded, so decide if we should force links to be chased */ |
|
1739 if (dochaselinks) |
|
1740 chasinglinks = 1; |
|
1741 return metafy(buf, -1, META_NOALLOC); |
|
1742 } |
|
1743 |
|
1744 /* do the extra processing associated with changing directory */ |
|
1745 |
|
1746 /**/ |
|
1747 static void |
|
1748 cd_new_pwd(int func, LinkNode dir) |
|
1749 { |
|
1750 Eprog prog; |
|
1751 char *new_pwd, *s; |
|
1752 int dirstacksize; |
|
1753 |
|
1754 if (func == BIN_PUSHD) |
|
1755 rolllist(dirstack, dir); |
|
1756 new_pwd = remnode(dirstack, dir); |
|
1757 |
|
1758 if (func == BIN_POPD && firstnode(dirstack)) { |
|
1759 zsfree(new_pwd); |
|
1760 new_pwd = getlinknode(dirstack); |
|
1761 } else if (func == BIN_CD && unset(AUTOPUSHD)) |
|
1762 zsfree(getlinknode(dirstack)); |
|
1763 |
|
1764 if (chasinglinks) { |
|
1765 s = new_pwd; |
|
1766 new_pwd = findpwd(s); |
|
1767 zsfree(s); |
|
1768 } |
|
1769 if (isset(PUSHDIGNOREDUPS)) { |
|
1770 LinkNode n; |
|
1771 for (n = firstnode(dirstack); n; incnode(n)) { |
|
1772 if (!strcmp(new_pwd, getdata(n))) { |
|
1773 zsfree(remnode(dirstack, n)); |
|
1774 break; |
|
1775 } |
|
1776 } |
|
1777 } |
|
1778 |
|
1779 /* shift around the pwd variables, to make oldpwd and pwd relate to the |
|
1780 current (i.e. new) pwd */ |
|
1781 zsfree(oldpwd); |
|
1782 oldpwd = pwd; |
|
1783 setjobpwd(); |
|
1784 pwd = new_pwd; |
|
1785 set_pwd_env(); |
|
1786 |
|
1787 if (isset(INTERACTIVE)) { |
|
1788 if (unset(PUSHDSILENT) && func != BIN_CD) |
|
1789 printdirstack(); |
|
1790 else if (doprintdir) { |
|
1791 fprintdir(pwd, stdout); |
|
1792 putchar('\n'); |
|
1793 } |
|
1794 } |
|
1795 |
|
1796 /* execute the chpwd function */ |
|
1797 if ((prog = getshfunc("chpwd")) != &dummy_eprog) { |
|
1798 int osc = sfcontext; |
|
1799 |
|
1800 fflush(stdout); |
|
1801 fflush(stderr); |
|
1802 sfcontext = SFC_HOOK; |
|
1803 doshfunc("chpwd", prog, NULL, 0, 1); |
|
1804 sfcontext = osc; |
|
1805 } |
|
1806 |
|
1807 dirstacksize = getiparam("DIRSTACKSIZE"); |
|
1808 /* handle directory stack sizes out of range */ |
|
1809 if (dirstacksize > 0) { |
|
1810 int remove = countlinknodes(dirstack) - |
|
1811 (dirstacksize < 2 ? 2 : dirstacksize); |
|
1812 while (remove-- >= 0) |
|
1813 zsfree(remnode(dirstack, lastnode(dirstack))); |
|
1814 } |
|
1815 } |
|
1816 |
|
1817 /* Print the directory stack */ |
|
1818 |
|
1819 /**/ |
|
1820 static void |
|
1821 printdirstack(void) |
|
1822 { |
|
1823 LinkNode node; |
|
1824 |
|
1825 fprintdir(pwd, stdout); |
|
1826 for (node = firstnode(dirstack); node; incnode(node)) { |
|
1827 putchar(' '); |
|
1828 fprintdir(getdata(node), stdout); |
|
1829 } |
|
1830 putchar('\n'); |
|
1831 } |
|
1832 |
|
1833 /* Normalise a path. Segments consisting of ., and foo/.. * |
|
1834 * combinations, are removed and the path is unmetafied. |
|
1835 * Returns 1 if we found a ../ path which should force links to |
|
1836 * be chased, 0 otherwise. |
|
1837 */ |
|
1838 |
|
1839 /**/ |
|
1840 int |
|
1841 fixdir(char *src) |
|
1842 { |
|
1843 char *dest = src, *d0 = dest; |
|
1844 #ifdef __CYGWIN__ |
|
1845 char *s0 = src; |
|
1846 #endif |
|
1847 int ret = 0; |
|
1848 |
|
1849 /*** if have RFS superroot directory ***/ |
|
1850 #ifdef HAVE_SUPERROOT |
|
1851 /* allow /.. segments to remain */ |
|
1852 while (*src == '/' && src[1] == '.' && src[2] == '.' && |
|
1853 (!src[3] || src[3] == '/')) { |
|
1854 *dest++ = '/'; |
|
1855 *dest++ = '.'; |
|
1856 *dest++ = '.'; |
|
1857 src += 3; |
|
1858 } |
|
1859 #endif |
|
1860 |
|
1861 for (;;) { |
|
1862 /* compress multiple /es into single */ |
|
1863 if (*src == '/'||*src == '\\') { |
|
1864 #ifdef __CYGWIN__ |
|
1865 /* allow leading // under cygwin */ |
|
1866 if (src == s0 && (src[1] == '/' || src[1] == '\\')) |
|
1867 *dest++ = *src++; |
|
1868 #endif |
|
1869 *dest++ = *src++; |
|
1870 while (*src == '/'||*src == '\\') |
|
1871 src++; |
|
1872 } |
|
1873 /* if we are at the end of the input path, remove a trailing / (if it |
|
1874 exists), and return ct */ |
|
1875 if (!*src) { |
|
1876 while (dest > d0 + 1 && (dest[-1] == '/' ||dest[-1] == '\\' )) |
|
1877 dest--; |
|
1878 *dest = '\0'; |
|
1879 return ret; |
|
1880 } |
|
1881 if (src[0] == '.' && src[1] == '.' && |
|
1882 (src[2] == '\0' || src[2] == '/' || src[2] == '\\')) { |
|
1883 if (isset(CHASEDOTS)) { |
|
1884 ret = 1; |
|
1885 /* and treat as normal path segment */ |
|
1886 } else { |
|
1887 if (dest > d0 + 1) { |
|
1888 /* |
|
1889 * remove a foo/.. combination: |
|
1890 * first check foo exists, else return. |
|
1891 */ |
|
1892 struct stat st; |
|
1893 *dest = '\0'; |
|
1894 if ( (stat(d0, &st) < 0 && errno!=EACCES) || !S_ISDIR(st.st_mode)) { |
|
1895 char *ptrd, *ptrs; |
|
1896 if (dest == src) |
|
1897 *dest = '.'; |
|
1898 for (ptrs = src, ptrd = dest; *ptrs; ptrs++, ptrd++) |
|
1899 *ptrd = (*ptrs == Meta) ? (*++ptrs ^ 32) : *ptrs; |
|
1900 *ptrd = '\0'; |
|
1901 return 1; |
|
1902 } |
|
1903 for (dest--; dest > d0 + 1 && (dest[-1] != '/'&&dest[-1] != '\\'); dest--); |
|
1904 if (dest[-1] != '/' && dest[-1] != '\\') |
|
1905 dest--; |
|
1906 } |
|
1907 src++; |
|
1908 while (*++src == '/' || *src == '\\'); |
|
1909 continue; |
|
1910 } |
|
1911 } |
|
1912 if (src[0] == '.' && (src[1] == '/' || src[1] == '\\'|| src[1] == '\0')) { |
|
1913 /* skip a . section */ |
|
1914 while (*++src == '/'||*src == '\\'); |
|
1915 } else { |
|
1916 /* copy a normal segment into the output */ |
|
1917 while ( (*src != '/' && *src != '\\') && *src != '\0') |
|
1918 if ((*dest++ = *src++) == Meta) |
|
1919 dest[-1] = *src++ ^ 32; |
|
1920 } |
|
1921 } |
|
1922 } |
|
1923 |
|
1924 #ifndef __SYMBIAN32__ |
|
1925 /**/ |
|
1926 mod_export void |
|
1927 printqt(char *str) |
|
1928 { |
|
1929 /* Print str, but turn any single quote into '\'' or ''. */ |
|
1930 for (; *str; str++) |
|
1931 if (*str == '\'') |
|
1932 printf(isset(RCQUOTES) ? "''" : "'\\''"); |
|
1933 else |
|
1934 putchar(*str); |
|
1935 } |
|
1936 |
|
1937 /**/ |
|
1938 mod_export void |
|
1939 printif(char *str, int c) |
|
1940 { |
|
1941 /* If flag c has an argument, print that */ |
|
1942 if (str) { |
|
1943 printf(" -%c ", c); |
|
1944 quotedzputs(str, stdout); |
|
1945 } |
|
1946 } |
|
1947 |
|
1948 #endif |
|
1949 /**** history list functions ****/ |
|
1950 |
|
1951 /* fc, history, r */ |
|
1952 |
|
1953 /**/ |
|
1954 int |
|
1955 bin_fc(char *nam, char **argv, Options ops, int func) |
|
1956 { |
|
1957 zlong first = -1, last = -1; |
|
1958 int retval; |
|
1959 char *s; |
|
1960 struct asgment *asgf = NULL, *asgl = NULL; |
|
1961 Patprog pprog = NULL; |
|
1962 |
|
1963 /* fc is only permitted in interactive shells */ |
|
1964 if (!interact) { |
|
1965 zwarnnam(nam, "not interactive shell", NULL, 0); |
|
1966 return 1; |
|
1967 } |
|
1968 if (OPT_ISSET(ops,'p')) { |
|
1969 char *hf = ""; |
|
1970 zlong hs = DEFAULT_HISTSIZE; |
|
1971 zlong shs = 0; |
|
1972 int level = OPT_ISSET(ops,'a') ? locallevel : -1; |
|
1973 if (*argv) { |
|
1974 hf = *argv++; |
|
1975 if (*argv) { |
|
1976 hs = zstrtol(*argv++, NULL, 10); |
|
1977 if (*argv) |
|
1978 shs = zstrtol(*argv++, NULL, 10); |
|
1979 else |
|
1980 shs = hs; |
|
1981 if (*argv) { |
|
1982 zwarnnam("fc", "too many arguments", NULL, 0); |
|
1983 return 1; |
|
1984 } |
|
1985 } else { |
|
1986 hs = histsiz; |
|
1987 shs = savehistsiz; |
|
1988 } |
|
1989 } |
|
1990 if (!pushhiststack(hf, hs, shs, level)) |
|
1991 return 1; |
|
1992 if (*hf) { |
|
1993 struct stat st; |
|
1994 if (stat(hf, &st) >= 0 || errno != ENOENT) |
|
1995 readhistfile(hf, 1, HFILE_USE_OPTIONS); |
|
1996 } |
|
1997 return 0; |
|
1998 } |
|
1999 if (OPT_ISSET(ops,'P')) { |
|
2000 if (*argv) { |
|
2001 zwarnnam("fc", "too many arguments", NULL, 0); |
|
2002 return 1; |
|
2003 } |
|
2004 return !saveandpophiststack(-1, HFILE_USE_OPTIONS); |
|
2005 } |
|
2006 /* with the -m option, the first argument is taken * |
|
2007 * as a pattern that history lines have to match */ |
|
2008 if (*argv && OPT_ISSET(ops,'m')) { |
|
2009 tokenize(*argv); |
|
2010 if (!(pprog = patcompile(*argv++, 0, NULL))) { |
|
2011 zwarnnam(nam, "invalid match pattern", NULL, 0); |
|
2012 return 1; |
|
2013 } |
|
2014 } |
|
2015 queue_signals(); |
|
2016 if (OPT_ISSET(ops,'R')) { |
|
2017 /* read history from a file */ |
|
2018 readhistfile(*argv, 1, OPT_ISSET(ops,'I') ? HFILE_SKIPOLD : 0); |
|
2019 unqueue_signals(); |
|
2020 return 0; |
|
2021 } |
|
2022 if (OPT_ISSET(ops,'W')) { |
|
2023 /* write history to a file */ |
|
2024 savehistfile(*argv, 1, OPT_ISSET(ops,'I') ? HFILE_SKIPOLD : 0); |
|
2025 unqueue_signals(); |
|
2026 return 0; |
|
2027 } |
|
2028 if (OPT_ISSET(ops,'A')) { |
|
2029 /* append history to a file */ |
|
2030 savehistfile(*argv, 1, HFILE_APPEND | |
|
2031 (OPT_ISSET(ops,'I') ? HFILE_SKIPOLD : 0)); |
|
2032 unqueue_signals(); |
|
2033 return 0; |
|
2034 } |
|
2035 /* put foo=bar type arguments into the substitution list */ |
|
2036 while (*argv && equalsplit(*argv, &s)) { |
|
2037 Asgment a = (Asgment) zhalloc(sizeof *a); |
|
2038 |
|
2039 if (!**argv) { |
|
2040 zwarnnam(nam, "invalid replacement pattern: =%s", s, 0); |
|
2041 return 1; |
|
2042 } |
|
2043 if (!asgf) |
|
2044 asgf = asgl = a; |
|
2045 else { |
|
2046 asgl->next = a; |
|
2047 asgl = a; |
|
2048 } |
|
2049 a->name = *argv; |
|
2050 a->value = s; |
|
2051 a->next = NULL; |
|
2052 argv++; |
|
2053 } |
|
2054 /* interpret and check first history line specifier */ |
|
2055 if (*argv) { |
|
2056 first = fcgetcomm(*argv); |
|
2057 if (first == -1) { |
|
2058 unqueue_signals(); |
|
2059 return 1; |
|
2060 } |
|
2061 argv++; |
|
2062 } |
|
2063 /* interpret and check second history line specifier */ |
|
2064 if (*argv) { |
|
2065 last = fcgetcomm(*argv); |
|
2066 if (last == -1) { |
|
2067 unqueue_signals(); |
|
2068 return 1; |
|
2069 } |
|
2070 argv++; |
|
2071 } |
|
2072 /* There is a maximum of two history specifiers. At least, there * |
|
2073 * will be as long as the history list is one-dimensional. */ |
|
2074 if (*argv) { |
|
2075 unqueue_signals(); |
|
2076 zwarnnam("fc", "too many arguments", NULL, 0); |
|
2077 return 1; |
|
2078 } |
|
2079 /* default values of first and last, and range checking */ |
|
2080 if (last == -1) { |
|
2081 if (OPT_ISSET(ops,'l') && first < curhist) { |
|
2082 last = addhistnum(curline.histnum,-1,0); |
|
2083 if (last < firsthist()) |
|
2084 last = firsthist(); |
|
2085 } |
|
2086 else |
|
2087 last = first; |
|
2088 } |
|
2089 if (first == -1) { |
|
2090 first = OPT_ISSET(ops,'l')? addhistnum(curline.histnum,-16,0) |
|
2091 : addhistnum(curline.histnum,-1,0); |
|
2092 if (first < 1) |
|
2093 first = 1; |
|
2094 if (last < first) |
|
2095 last = first; |
|
2096 } |
|
2097 if (OPT_ISSET(ops,'l')) { |
|
2098 /* list the required part of the history */ |
|
2099 retval = fclist(stdout, ops, first, last, asgf, pprog); |
|
2100 unqueue_signals(); |
|
2101 } |
|
2102 else { |
|
2103 /* edit history file, and (if successful) use the result as a new command */ |
|
2104 int tempfd; |
|
2105 FILE *out; |
|
2106 char *fil; |
|
2107 |
|
2108 retval = 1; |
|
2109 if ((tempfd = gettempfile(NULL, 1, &fil)) < 0 |
|
2110 || ((out = fdopen(tempfd, "w")) == NULL)) { |
|
2111 unqueue_signals(); |
|
2112 zwarnnam("fc", "can't open temp file: %e", NULL, errno); |
|
2113 } else { |
|
2114 ops->ind['n'] = 1; /* No line numbers here. */ |
|
2115 if (!fclist(out, ops, first, last, asgf, pprog)) { |
|
2116 char *editor; |
|
2117 |
|
2118 if (func == BIN_R) |
|
2119 editor = "-"; |
|
2120 else if (OPT_HASARG(ops, 'e')) |
|
2121 editor = OPT_ARG(ops, 'e'); |
|
2122 else |
|
2123 { |
|
2124 editor = getsparam("FCEDIT"); |
|
2125 |
|
2126 #ifdef __SYMBIAN32__ |
|
2127 if(editor) |
|
2128 { |
|
2129 zwarnnam("fc", "vi is not supported", NULL, errno); |
|
2130 editor=NULL; |
|
2131 } |
|
2132 #endif |
|
2133 } |
|
2134 |
|
2135 if (!editor) |
|
2136 editor = DEFAULT_FCEDIT; |
|
2137 |
|
2138 if (fcedit(editor, fil)) { |
|
2139 if (stuff(fil)) |
|
2140 zwarnnam("fc", "%e: %s", s, errno); |
|
2141 else { |
|
2142 loop(0,1); |
|
2143 retval = lastval; |
|
2144 } |
|
2145 } |
|
2146 |
|
2147 } else |
|
2148 unqueue_signals(); |
|
2149 } |
|
2150 unlink(fil); |
|
2151 } |
|
2152 return retval; |
|
2153 } |
|
2154 |
|
2155 /* History handling functions: these are called by ZLE, as well as * |
|
2156 * the actual builtins. fcgetcomm() gets a history line, specified * |
|
2157 * either by number or leading string. fcsubs() performs a given * |
|
2158 * set of simple old=new substitutions on a given command line. * |
|
2159 * fclist() outputs a given range of history lines to a text file. */ |
|
2160 |
|
2161 /* get the history event associated with s */ |
|
2162 |
|
2163 /**/ |
|
2164 static zlong |
|
2165 fcgetcomm(char *s) |
|
2166 { |
|
2167 zlong cmd; |
|
2168 |
|
2169 /* First try to match a history number. Negative * |
|
2170 * numbers indicate reversed numbering. */ |
|
2171 if ((cmd = atoi(s)) != 0 || *s == '0') { |
|
2172 if (cmd < 0) |
|
2173 cmd = addhistnum(curline.histnum,cmd,HIST_FOREIGN); |
|
2174 if (cmd < 0) |
|
2175 cmd = 0; |
|
2176 return cmd; |
|
2177 } |
|
2178 /* not a number, so search by string */ |
|
2179 cmd = hcomsearch(s); |
|
2180 if (cmd == -1) |
|
2181 zwarnnam("fc", "event not found: %s", s, 0); |
|
2182 return cmd; |
|
2183 } |
|
2184 |
|
2185 /* Perform old=new substitutions. Uses the asgment structure from zsh.h, * |
|
2186 * which is essentially a linked list of string,replacement pairs. */ |
|
2187 |
|
2188 /**/ |
|
2189 static int |
|
2190 fcsubs(char **sp, struct asgment *sub) |
|
2191 { |
|
2192 char *oldstr, *newstr, *oldpos, *newpos, *newmem, *s = *sp; |
|
2193 int subbed = 0; |
|
2194 |
|
2195 /* loop through the linked list */ |
|
2196 while (sub) { |
|
2197 oldstr = sub->name; |
|
2198 newstr = sub->value; |
|
2199 sub = sub->next; |
|
2200 oldpos = s; |
|
2201 /* loop over occurences of oldstr in s, replacing them with newstr */ |
|
2202 while ((newpos = (char *)strstr(oldpos, oldstr))) { |
|
2203 newmem = (char *) zhalloc(1 + (newpos - s) |
|
2204 + strlen(newstr) + strlen(newpos + strlen(oldstr))); |
|
2205 ztrncpy(newmem, s, newpos - s); |
|
2206 strcat(newmem, newstr); |
|
2207 oldpos = newmem + strlen(newmem); |
|
2208 strcat(newmem, newpos + strlen(oldstr)); |
|
2209 s = newmem; |
|
2210 subbed = 1; |
|
2211 } |
|
2212 } |
|
2213 *sp = s; |
|
2214 return subbed; |
|
2215 } |
|
2216 |
|
2217 /* Print a series of history events to a file. The file pointer is * |
|
2218 * given by f, and the required range of events by first and last. * |
|
2219 * subs is an optional list of foo=bar substitutions to perform on the * |
|
2220 * history lines before output. com is an optional comp structure * |
|
2221 * that the history lines are required to match. n, r, D and d are * |
|
2222 * options: n indicates that each line should be numbered. r indicates * |
|
2223 * that the lines should be output in reverse order (newest first). * |
|
2224 * D indicates that the real time taken by each command should be * |
|
2225 * output. d indicates that the time of execution of each command * |
|
2226 * should be output; d>1 means that the date should be output too; d>3 * |
|
2227 * means that mm/dd/yyyy form should be used for the dates, as opposed * |
|
2228 * to dd.mm.yyyy form; d>7 means that yyyy-mm-dd form should be used. */ |
|
2229 |
|
2230 /**/ |
|
2231 static int |
|
2232 fclist(FILE *f, Options ops, zlong first, zlong last, |
|
2233 struct asgment *subs, Patprog pprog) |
|
2234 { |
|
2235 int fclistdone = 0; |
|
2236 zlong tmp; |
|
2237 char *s; |
|
2238 Histent ent; |
|
2239 |
|
2240 /* reverse range if required */ |
|
2241 if (OPT_ISSET(ops,'r')) { |
|
2242 tmp = last; |
|
2243 last = first; |
|
2244 first = tmp; |
|
2245 } |
|
2246 /* suppress "no substitution" warning if no substitution is requested */ |
|
2247 if (!subs) |
|
2248 fclistdone = 1; |
|
2249 |
|
2250 ent = gethistent(first, first < last? GETHIST_DOWNWARD : GETHIST_UPWARD); |
|
2251 if (!ent || (first < last? ent->histnum > last : ent->histnum < last)) { |
|
2252 if (first == last) { |
|
2253 char buf[DIGBUFSIZE]; |
|
2254 convbase(buf, first, 10); |
|
2255 zwarnnam("fc", "no such event: %s", buf, 0); |
|
2256 } else |
|
2257 zwarnnam("fc", "no events in that range", NULL, 0); |
|
2258 return 1; |
|
2259 } |
|
2260 |
|
2261 #ifdef __SYMBIAN32__ |
|
2262 { |
|
2263 Histent up=ent->up; |
|
2264 if( (strcmp(ent->text, "r")==0) && up && |
|
2265 (strcmp(up->text, "r")==0)) |
|
2266 { |
|
2267 zwarnnam("fc", "no history", NULL, 0); |
|
2268 return 1; |
|
2269 } |
|
2270 } |
|
2271 #endif |
|
2272 |
|
2273 for (;;) { |
|
2274 s = dupstring(ent->text); |
|
2275 /* this if does the pattern matching, if required */ |
|
2276 if (!pprog || pattry(pprog, s)) { |
|
2277 /* perform substitution */ |
|
2278 fclistdone |= fcsubs(&s, subs); |
|
2279 |
|
2280 /* do numbering */ |
|
2281 if (!OPT_ISSET(ops,'n')) { |
|
2282 char buf[DIGBUFSIZE]; |
|
2283 convbase(buf, ent->histnum, 10); |
|
2284 fprintf(f, "%5s%c ", buf, |
|
2285 ent->flags & HIST_FOREIGN? '*' : ' '); |
|
2286 } |
|
2287 /* output actual time (and possibly date) of execution of the |
|
2288 command, if required */ |
|
2289 if (OPT_ISSET(ops,'d') || OPT_ISSET(ops,'f') || |
|
2290 OPT_ISSET(ops,'E') || OPT_ISSET(ops,'i')) { |
|
2291 struct tm *ltm; |
|
2292 ltm = localtime(&ent->stim); |
|
2293 if (OPT_ISSET(ops,'i')) { |
|
2294 fprintf(f, "%d-%02d-%02d ", |
|
2295 ltm->tm_year + 1900, |
|
2296 ltm->tm_mon + 1, ltm->tm_mday); |
|
2297 } else if (OPT_ISSET(ops,'E')) { |
|
2298 fprintf(f, "%d.%d.%d ", |
|
2299 ltm->tm_mday, ltm->tm_mon + 1, |
|
2300 ltm->tm_year + 1900); |
|
2301 } else if (OPT_ISSET(ops,'f')) { |
|
2302 fprintf(f, "%d/%d/%d ", |
|
2303 ltm->tm_mon + 1, ltm->tm_mday, |
|
2304 ltm->tm_year + 1900); |
|
2305 } |
|
2306 fprintf(f, "%02d:%02d ", ltm->tm_hour, ltm->tm_min); |
|
2307 } |
|
2308 /* display the time taken by the command, if required */ |
|
2309 if (OPT_ISSET(ops,'D')) { |
|
2310 long diff; |
|
2311 diff = (ent->ftim) ? ent->ftim - ent->stim : 0; |
|
2312 fprintf(f, "%ld:%02ld ", diff / 60, diff % 60); |
|
2313 } |
|
2314 |
|
2315 /* output the command */ |
|
2316 if (f == stdout) { |
|
2317 nicezputs(s, f); |
|
2318 putc('\n', f); |
|
2319 } else |
|
2320 fprintf(f, "%s\n", s); |
|
2321 |
|
2322 fflush(f); |
|
2323 } |
|
2324 /* move on to the next history line, or quit the loop */ |
|
2325 if (first < last) { |
|
2326 if (!(ent = down_histent(ent)) || ent->histnum > last) |
|
2327 break; |
|
2328 } |
|
2329 else { |
|
2330 if (!(ent = up_histent(ent)) || ent->histnum < last) |
|
2331 break; |
|
2332 } |
|
2333 } |
|
2334 |
|
2335 /* final processing */ |
|
2336 if (f != stdout) |
|
2337 fclose(f); |
|
2338 if (!fclistdone) { |
|
2339 zwarnnam("fc", "no substitutions performed", NULL, 0); |
|
2340 return 1; |
|
2341 } |
|
2342 return 0; |
|
2343 } |
|
2344 |
|
2345 /* edit a history file */ |
|
2346 |
|
2347 /**/ |
|
2348 static int |
|
2349 fcedit(char *ename, char *fn) |
|
2350 { |
|
2351 char *s; |
|
2352 |
|
2353 if (!strcmp(ename, "-")) |
|
2354 return 1; |
|
2355 |
|
2356 s = tricat(ename, " ", fn); |
|
2357 execstring(s, 1, 0); |
|
2358 zsfree(s); |
|
2359 |
|
2360 return lastval; |
|
2361 } |
|
2362 |
|
2363 /**** parameter builtins ****/ |
|
2364 |
|
2365 /* Separate an argument into name=value parts, returning them in an * |
|
2366 * asgment structure. Because the asgment structure used is global, * |
|
2367 * only one of these can be active at a time. The string s gets placed * |
|
2368 * in this global structure, so it needs to be in permanent memory. */ |
|
2369 |
|
2370 /**/ |
|
2371 static Asgment |
|
2372 getasg(char *s) |
|
2373 { |
|
2374 static struct asgment asg; |
|
2375 |
|
2376 /* sanity check for valid argument */ |
|
2377 if (!s) |
|
2378 return NULL; |
|
2379 |
|
2380 /* check if name is empty */ |
|
2381 if (*s == '=') { |
|
2382 zerr("bad assignment", NULL, 0); |
|
2383 return NULL; |
|
2384 } |
|
2385 asg.name = s; |
|
2386 |
|
2387 /* search for `=' */ |
|
2388 for (; *s && *s != '='; s++); |
|
2389 |
|
2390 /* found `=', so return with a value */ |
|
2391 if (*s) { |
|
2392 *s = '\0'; |
|
2393 asg.value = s + 1; |
|
2394 } else { |
|
2395 /* didn't find `=', so we only have a name */ |
|
2396 asg.value = NULL; |
|
2397 } |
|
2398 return &asg; |
|
2399 } |
|
2400 |
|
2401 /* for new special parameters */ |
|
2402 enum { |
|
2403 NS_NONE, |
|
2404 NS_NORMAL, |
|
2405 NS_SECONDS |
|
2406 }; |
|
2407 |
|
2408 static const struct gsu_scalar tiedarr_gsu = |
|
2409 { tiedarrgetfn, tiedarrsetfn, tiedarrunsetfn }; |
|
2410 |
|
2411 /* Install a base if we are turning on a numeric option with an argument */ |
|
2412 |
|
2413 static int |
|
2414 typeset_setbase(const char *name, Param pm, Options ops, int on, int always) |
|
2415 { |
|
2416 char *arg = NULL; |
|
2417 |
|
2418 if ((on & PM_INTEGER) && OPT_HASARG(ops,'i')) |
|
2419 arg = OPT_ARG(ops,'i'); |
|
2420 else if ((on & PM_EFLOAT) && OPT_HASARG(ops,'E')) |
|
2421 arg = OPT_ARG(ops,'E'); |
|
2422 else if ((on & PM_FFLOAT) && OPT_HASARG(ops,'F')) |
|
2423 arg = OPT_ARG(ops,'F'); |
|
2424 |
|
2425 if (arg) { |
|
2426 char *eptr; |
|
2427 pm->base = (int)zstrtol(arg, &eptr, 10); |
|
2428 if (*eptr) { |
|
2429 if (on & PM_INTEGER) |
|
2430 zwarnnam(name, "bad base value: %s", arg, 0); |
|
2431 else |
|
2432 zwarnnam(name, "bad precision value: %s", arg, 0); |
|
2433 return 1; |
|
2434 } |
|
2435 } else if (always) |
|
2436 pm->base = 0; |
|
2437 |
|
2438 return 0; |
|
2439 } |
|
2440 |
|
2441 /* Install a width if we are turning on a padding option with an argument */ |
|
2442 |
|
2443 static int |
|
2444 typeset_setwidth(const char * name, Param pm, Options ops, int on, int always) |
|
2445 { |
|
2446 char *arg = NULL; |
|
2447 |
|
2448 if ((on & PM_LEFT) && OPT_HASARG(ops,'L')) |
|
2449 arg = OPT_ARG(ops,'L'); |
|
2450 else if ((on & PM_RIGHT_B) && OPT_HASARG(ops,'R')) |
|
2451 arg = OPT_ARG(ops,'R'); |
|
2452 else if ((on & PM_RIGHT_Z) && OPT_HASARG(ops,'Z')) |
|
2453 arg = OPT_ARG(ops,'Z'); |
|
2454 |
|
2455 if (arg) { |
|
2456 char *eptr; |
|
2457 pm->width = (int)zstrtol(arg, &eptr, 10); |
|
2458 if (*eptr) { |
|
2459 zwarnnam(name, "bad width value: %s", arg, 0); |
|
2460 return 1; |
|
2461 } |
|
2462 } else if (always) |
|
2463 pm->width = 0; |
|
2464 |
|
2465 return 0; |
|
2466 } |
|
2467 |
|
2468 /* function to set a single parameter */ |
|
2469 |
|
2470 /**/ |
|
2471 static Param |
|
2472 typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), |
|
2473 int on, int off, int roff, char *value, Param altpm, |
|
2474 Options ops, int joinchar) |
|
2475 { |
|
2476 int usepm, tc, keeplocal = 0, newspecial = NS_NONE, readonly; |
|
2477 char *subscript; |
|
2478 |
|
2479 /* |
|
2480 * Do we use the existing pm? Note that this isn't the end of the |
|
2481 * story, because if we try and create a new pm at the same |
|
2482 * locallevel as an unset one we use the pm struct anyway: that's |
|
2483 * handled in createparam(). Here we just avoid using it for the |
|
2484 * present tests if it's unset. |
|
2485 */ |
|
2486 usepm = pm && !(pm->flags & PM_UNSET); |
|
2487 |
|
2488 /* |
|
2489 * We need to compare types with an existing pm if special, |
|
2490 * even if that's unset |
|
2491 */ |
|
2492 if (pm && (pm->flags & PM_SPECIAL)) |
|
2493 usepm = 1; |
|
2494 |
|
2495 /* |
|
2496 * Don't use an existing param if |
|
2497 * - the local level has changed, and |
|
2498 * - we are really locallizing the parameter |
|
2499 */ |
|
2500 if (usepm && locallevel != pm->level && (on & PM_LOCAL)) { |
|
2501 /* |
|
2502 * If the original parameter was special and we're creating |
|
2503 * a new one, we need to keep it special. |
|
2504 * |
|
2505 * The -h (hide) flag prevents an existing special being made |
|
2506 * local. It can be applied either to the special or in the |
|
2507 * typeset/local statement for the local variable. |
|
2508 */ |
|
2509 if ((pm->flags & PM_SPECIAL) |
|
2510 && !(on & PM_HIDE) && !(pm->flags & PM_HIDE & ~off)) |
|
2511 newspecial = NS_NORMAL; |
|
2512 usepm = 0; |
|
2513 } |
|
2514 |
|
2515 /* attempting a type conversion, or making a tied colonarray? */ |
|
2516 tc = 0; |
|
2517 if (usepm || newspecial != NS_NONE) { |
|
2518 int chflags = ((off & pm->flags) | (on & ~pm->flags)) & |
|
2519 (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED| |
|
2520 PM_ARRAY|PM_TIED|PM_AUTOLOAD); |
|
2521 /* keep the parameter if just switching between floating types */ |
|
2522 if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT))) |
|
2523 usepm = 0; |
|
2524 } |
|
2525 |
|
2526 /* |
|
2527 * Extra checks if converting the type of a parameter, or if |
|
2528 * trying to remove readonlyness. It's dangerous doing either |
|
2529 * with a special or a parameter which isn't loaded yet (which |
|
2530 * may be special when it is loaded; we can't tell yet). |
|
2531 */ |
|
2532 if ((readonly = |
|
2533 ((usepm || newspecial != NS_NONE) && |
|
2534 (off & pm->flags & PM_READONLY))) || |
|
2535 tc) { |
|
2536 if (pm->flags & PM_SPECIAL) { |
|
2537 int err = 1; |
|
2538 if (!readonly && !strcmp(pname, "SECONDS")) |
|
2539 { |
|
2540 /* |
|
2541 * We allow SECONDS to change type between integer |
|
2542 * and floating point. If we are creating a new |
|
2543 * local copy we check the type here and allow |
|
2544 * a new special to be created with that type. |
|
2545 * We then need to make sure the correct type |
|
2546 * for the special is restored at the end of the scope. |
|
2547 * If we are changing the type of an existing |
|
2548 * parameter, we do the whole thing here. |
|
2549 */ |
|
2550 if (newspecial != NS_NONE) |
|
2551 { |
|
2552 /* |
|
2553 * The first test allows `typeset' to copy the |
|
2554 * existing type. This is the usual behaviour |
|
2555 * for making special parameters local. |
|
2556 */ |
|
2557 if (PM_TYPE(on) == 0 || PM_TYPE(on) == PM_INTEGER || |
|
2558 PM_TYPE(on) == PM_FFLOAT || PM_TYPE(on) == PM_EFLOAT) |
|
2559 { |
|
2560 newspecial = NS_SECONDS; |
|
2561 err = 0; /* and continue */ |
|
2562 tc = 0; /* but don't do a normal conversion */ |
|
2563 } |
|
2564 } else if (!setsecondstype(pm, on, off)) { |
|
2565 if (value && !setsparam(pname, ztrdup(value))) |
|
2566 return NULL; |
|
2567 return pm; |
|
2568 } |
|
2569 } |
|
2570 if (err) |
|
2571 { |
|
2572 zerrnam(cname, "%s: can't change type of a special parameter", |
|
2573 pname, 0); |
|
2574 return NULL; |
|
2575 } |
|
2576 } else if (pm->flags & PM_AUTOLOAD) { |
|
2577 zerrnam(cname, "%s: can't change type of autoloaded parameter", |
|
2578 pname, 0); |
|
2579 return NULL; |
|
2580 } |
|
2581 } |
|
2582 else if (newspecial != NS_NONE && strcmp(pname, "SECONDS") == 0) |
|
2583 newspecial = NS_SECONDS; |
|
2584 |
|
2585 /* |
|
2586 * A parameter will be local if |
|
2587 * 1. we are re-using an existing local parameter |
|
2588 * or |
|
2589 * 2. we are not using an existing parameter, but |
|
2590 * i. there is already a parameter, which will be hidden |
|
2591 * or |
|
2592 * ii. we are creating a new local parameter |
|
2593 */ |
|
2594 if (usepm) { |
|
2595 on &= ~PM_LOCAL; |
|
2596 if (!on && !roff && !value) { |
|
2597 if (OPT_ISSET(ops,'p')) |
|
2598 paramtab->printnode((HashNode)pm, PRINT_TYPESET); |
|
2599 else if (unset(TYPESETSILENT) || OPT_ISSET(ops,'m')) |
|
2600 paramtab->printnode((HashNode)pm, PRINT_INCLUDEVALUE); |
|
2601 return pm; |
|
2602 } |
|
2603 if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { |
|
2604 zerrnam(cname, "%s: restricted", pname, 0); |
|
2605 return pm; |
|
2606 } |
|
2607 if ((on & PM_UNIQUE) && !(pm->flags & PM_READONLY & ~off)) { |
|
2608 Param apm; |
|
2609 char **x; |
|
2610 if (PM_TYPE(pm->flags) == PM_ARRAY) { |
|
2611 x = (*pm->gsu.a->getfn)(pm); |
|
2612 uniqarray(x); |
|
2613 if (pm->ename && x) |
|
2614 arrfixenv(pm->ename, x); |
|
2615 } else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename && |
|
2616 (apm = |
|
2617 (Param) paramtab->getnode(paramtab, pm->ename))) { |
|
2618 x = (*apm->gsu.a->getfn)(apm); |
|
2619 uniqarray(x); |
|
2620 if (x) |
|
2621 arrfixenv(pm->nam, x); |
|
2622 } |
|
2623 } |
|
2624 pm->flags = (pm->flags | (on & ~PM_READONLY)) & ~(off | PM_UNSET); |
|
2625 if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { |
|
2626 if (typeset_setwidth(cname, pm, ops, on, 0)) |
|
2627 return NULL; |
|
2628 } |
|
2629 if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) { |
|
2630 if (typeset_setbase(cname, pm, ops, on, 0)) |
|
2631 return NULL; |
|
2632 } |
|
2633 if (!(pm->flags & (PM_ARRAY|PM_HASHED))) { |
|
2634 if (pm->flags & PM_EXPORTED) { |
|
2635 if (!(pm->flags & PM_UNSET) && !pm->env && !value) |
|
2636 addenv(pm, getsparam(pname)); |
|
2637 } else if (pm->env && !(pm->flags & PM_HASHELEM)) |
|
2638 delenv(pm); |
|
2639 if (value && !(pm = setsparam(pname, ztrdup(value)))) |
|
2640 return NULL; |
|
2641 } else if (value) { |
|
2642 zwarnnam(cname, "can't assign new value for array %s", pname, 0); |
|
2643 return NULL; |
|
2644 } |
|
2645 pm->flags |= (on & PM_READONLY); |
|
2646 if (OPT_ISSET(ops,'p')) |
|
2647 paramtab->printnode((HashNode)pm, PRINT_TYPESET); |
|
2648 return pm; |
|
2649 } |
|
2650 |
|
2651 /* |
|
2652 * We're here either because we're creating a new parameter, |
|
2653 * or we're adding a parameter at a different local level, |
|
2654 * or we're converting the type of a parameter. In the |
|
2655 * last case only, we need to delete the old parameter. |
|
2656 */ |
|
2657 if (tc) { |
|
2658 /* Maintain existing readonly/exported status... */ |
|
2659 on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->flags; |
|
2660 /* ...but turn off existing readonly so we can delete it */ |
|
2661 pm->flags &= ~PM_READONLY; |
|
2662 /* |
|
2663 * If we're just changing the type, we should keep the |
|
2664 * variable at the current level of localness. |
|
2665 */ |
|
2666 keeplocal = pm->level; |
|
2667 /* |
|
2668 * Try to carry over a value, but not when changing from, |
|
2669 * to, or between non-scalar types. |
|
2670 */ |
|
2671 if (!value && !((pm->flags|on) & (PM_ARRAY|PM_HASHED))) |
|
2672 value = dupstring(getsparam(pname)); |
|
2673 /* pname may point to pm->nam which is about to disappear */ |
|
2674 pname = dupstring(pname); |
|
2675 unsetparam_pm(pm, 0, 1); |
|
2676 } |
|
2677 |
|
2678 if (newspecial != NS_NONE) { |
|
2679 Param tpm, pm2; |
|
2680 if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { |
|
2681 zerrnam(cname, "%s: restricted", pname, 0); |
|
2682 return pm; |
|
2683 } |
|
2684 /* |
|
2685 * For specials, we keep the same struct but zero everything. |
|
2686 * Maybe it would be easier to create a new struct but copy |
|
2687 * the get/set methods. |
|
2688 */ |
|
2689 tpm = (Param) zshcalloc(sizeof *tpm); |
|
2690 |
|
2691 tpm->nam = pm->nam; |
|
2692 if (pm->ename && |
|
2693 (pm2 = (Param) paramtab->getnode(paramtab, pm->ename)) && |
|
2694 pm2->level == locallevel) { |
|
2695 /* This is getting silly, but anyway: if one of a path/PATH |
|
2696 * pair has already been made local at the current level, we |
|
2697 * have to make sure that the other one does not have its value |
|
2698 * saved: since that comes from an internal variable it will |
|
2699 * already reflect the local value, so restoring it on exit |
|
2700 * would be wrong. |
|
2701 * |
|
2702 * This problem is also why we make sure we have a copy |
|
2703 * of the environment entry in tpm->env, rather than relying |
|
2704 * on the restored value to provide it. |
|
2705 */ |
|
2706 tpm->flags = pm->flags | PM_NORESTORE; |
|
2707 } else { |
|
2708 copyparam(tpm, pm, 1); |
|
2709 } |
|
2710 tpm->old = pm->old; |
|
2711 tpm->level = pm->level; |
|
2712 tpm->base = pm->base; |
|
2713 tpm->width = pm->width; |
|
2714 if (pm->env) |
|
2715 delenv(pm); |
|
2716 tpm->env = NULL; |
|
2717 |
|
2718 pm->old = tpm; |
|
2719 /* |
|
2720 * The remaining on/off flags should be harmless to use, |
|
2721 * because we've checked for unpleasant surprises above. |
|
2722 */ |
|
2723 pm->flags = (PM_TYPE(pm->flags) | on | PM_SPECIAL) & ~off; |
|
2724 if (newspecial == NS_SECONDS) { |
|
2725 /* We save off the raw internal value of the SECONDS var */ |
|
2726 tpm->u.dval = getrawseconds(); |
|
2727 setsecondstype(pm, on, off); |
|
2728 } |
|
2729 |
|
2730 /* |
|
2731 * Final tweak: if we've turned on one of the flags with |
|
2732 * numbers, we should use the appropriate integer. |
|
2733 */ |
|
2734 if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z)) { |
|
2735 if (typeset_setwidth(cname, pm, ops, on, 1)) |
|
2736 return NULL; |
|
2737 } |
|
2738 if (on & (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) { |
|
2739 if (typeset_setbase(cname, pm, ops, on, 1)) |
|
2740 return NULL; |
|
2741 } |
|
2742 } else if ((subscript = strchr(pname, '['))) { |
|
2743 if (on & PM_READONLY) { |
|
2744 zerrnam(cname, |
|
2745 "%s: can't create readonly array elements", pname, 0); |
|
2746 return NULL; |
|
2747 } else if (on & PM_LOCAL) { |
|
2748 *subscript = 0; |
|
2749 pm = (Param) (paramtab == realparamtab ? |
|
2750 gethashnode2(paramtab, pname) : |
|
2751 paramtab->getnode(paramtab, pname)); |
|
2752 *subscript = '['; |
|
2753 if (!pm || pm->level != locallevel) { |
|
2754 zerrnam(cname, |
|
2755 "%s: can't create local array elements", pname, 0); |
|
2756 return NULL; |
|
2757 } |
|
2758 } |
|
2759 if (PM_TYPE(on) == PM_SCALAR) { |
|
2760 /* |
|
2761 * This will either complain about bad identifiers, or will set |
|
2762 * a hash element or array slice. This once worked by accident, |
|
2763 * creating a stray parameter along the way via createparam(), |
|
2764 * now called below in the isident() branch. |
|
2765 */ |
|
2766 if (!(pm = setsparam(pname, ztrdup(value ? value : "")))) |
|
2767 return NULL; |
|
2768 value = NULL; |
|
2769 keeplocal = 0; |
|
2770 on = pm->flags; |
|
2771 } else { |
|
2772 zerrnam(cname, |
|
2773 "%s: array elements must be scalar", pname, 0); |
|
2774 return NULL; |
|
2775 } |
|
2776 } else if (isident(pname) && !idigit(*pname)) { |
|
2777 /* |
|
2778 * Create a new node for a parameter with the flags in `on' minus the |
|
2779 * readonly flag |
|
2780 */ |
|
2781 pm = createparam(pname, on & ~PM_READONLY); |
|
2782 DPUTS(!pm, "BUG: parameter not created"); |
|
2783 if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { |
|
2784 if (typeset_setwidth(cname, pm, ops, on, 0)) |
|
2785 return NULL; |
|
2786 } |
|
2787 if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) { |
|
2788 if (typeset_setbase(cname, pm, ops, on, 0)) |
|
2789 return NULL; |
|
2790 } |
|
2791 } else { |
|
2792 if (isident(pname)) |
|
2793 zerrnam(cname, "not valid in this context: %s", pname, 0); |
|
2794 else |
|
2795 zerrnam(cname, "not an identifier: %s", pname, 0); |
|
2796 return NULL; |
|
2797 } |
|
2798 |
|
2799 if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) { |
|
2800 /* |
|
2801 * It seems safer to set this here than in createparam(), |
|
2802 * to make sure we only ever use the colonarr functions |
|
2803 * when u.data is correctly set. |
|
2804 */ |
|
2805 struct tieddata *tdp = (struct tieddata *) |
|
2806 zalloc(sizeof(struct tieddata)); |
|
2807 if (!tdp) |
|
2808 return NULL; |
|
2809 tdp->joinchar = joinchar; |
|
2810 tdp->arrptr = &altpm->u.arr; |
|
2811 |
|
2812 pm->gsu.s = &tiedarr_gsu; |
|
2813 pm->u.data = tdp; |
|
2814 } |
|
2815 |
|
2816 if (keeplocal) |
|
2817 pm->level = keeplocal; |
|
2818 else if (on & PM_LOCAL) |
|
2819 pm->level = locallevel; |
|
2820 if (value && !(pm->flags & (PM_ARRAY|PM_HASHED))) { |
|
2821 Param ipm = pm; |
|
2822 if (!(pm = setsparam(pname, ztrdup(value)))) |
|
2823 return NULL; |
|
2824 if (pm != ipm) { |
|
2825 DPUTS(ipm->flags != pm->flags, |
|
2826 "BUG: parameter recreated with wrong flags"); |
|
2827 unsetparam_pm(ipm, 0, 1); |
|
2828 } |
|
2829 } else if (newspecial != NS_NONE && !(pm->old->flags & PM_NORESTORE)) { |
|
2830 /* |
|
2831 * We need to use the special setting function to re-initialise |
|
2832 * the special parameter to empty. |
|
2833 */ |
|
2834 switch (PM_TYPE(pm->flags)) { |
|
2835 case PM_SCALAR: |
|
2836 pm->gsu.s->setfn(pm, ztrdup("")); |
|
2837 break; |
|
2838 case PM_INTEGER: |
|
2839 pm->gsu.i->setfn(pm, 0); |
|
2840 break; |
|
2841 case PM_EFLOAT: |
|
2842 case PM_FFLOAT: |
|
2843 pm->gsu.f->setfn(pm, 0.0); |
|
2844 break; |
|
2845 case PM_ARRAY: |
|
2846 pm->gsu.a->setfn(pm, mkarray(NULL)); |
|
2847 break; |
|
2848 case PM_HASHED: |
|
2849 pm->gsu.h->setfn(pm, newparamtable(17, pm->nam)); |
|
2850 break; |
|
2851 } |
|
2852 } |
|
2853 pm->flags |= (on & PM_READONLY); |
|
2854 if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) { |
|
2855 zerrnam(cname, "%s: can't assign initial value for array", pname, 0); |
|
2856 /* the only safe thing to do here seems to be unset the param */ |
|
2857 unsetparam_pm(pm, 0, 1); |
|
2858 return NULL; |
|
2859 } |
|
2860 |
|
2861 if (OPT_ISSET(ops,'p')) |
|
2862 paramtab->printnode((HashNode)pm, PRINT_TYPESET); |
|
2863 |
|
2864 return pm; |
|
2865 } |
|
2866 |
|
2867 /* declare, export, integer, local, readonly, typeset */ |
|
2868 |
|
2869 /**/ |
|
2870 int |
|
2871 bin_typeset(char *name, char **argv, Options ops, int func) |
|
2872 { |
|
2873 Param pm; |
|
2874 Asgment asg; |
|
2875 Patprog pprog; |
|
2876 char *optstr = TYPESET_OPTSTR; |
|
2877 int on = 0, off = 0, roff, bit = PM_ARRAY; |
|
2878 int i; |
|
2879 int returnval = 0, printflags = 0; |
|
2880 |
|
2881 /* hash -f is really the builtin `functions' */ |
|
2882 if (OPT_ISSET(ops,'f')) |
|
2883 return bin_functions(name, argv, ops, func); |
|
2884 |
|
2885 /* Translate the options into PM_* flags. * |
|
2886 * Unfortunately, this depends on the order * |
|
2887 * these flags are defined in zsh.h */ |
|
2888 for (; *optstr; optstr++, bit <<= 1) |
|
2889 { |
|
2890 int optval = STOUC(*optstr); |
|
2891 if (OPT_MINUS(ops,optval)) |
|
2892 on |= bit; |
|
2893 else if (OPT_PLUS(ops,optval)) |
|
2894 off |= bit; |
|
2895 } |
|
2896 roff = off; |
|
2897 |
|
2898 /* Sanity checks on the options. Remove conflicting options. */ |
|
2899 if (on & PM_FFLOAT) { |
|
2900 off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_INTEGER | PM_EFLOAT; |
|
2901 /* Allow `float -F' to work even though float sets -E by default */ |
|
2902 on &= ~PM_EFLOAT; |
|
2903 } |
|
2904 if (on & PM_EFLOAT) |
|
2905 off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_INTEGER | PM_FFLOAT; |
|
2906 if (on & PM_INTEGER) |
|
2907 off |= PM_UPPER | PM_ARRAY | PM_HASHED | PM_EFLOAT | PM_FFLOAT; |
|
2908 /* |
|
2909 * Allowing -Z with -L is a feature: left justify, suppressing |
|
2910 * leading zeroes. |
|
2911 */ |
|
2912 if (on & (PM_LEFT|PM_RIGHT_Z)) |
|
2913 off |= PM_RIGHT_B; |
|
2914 if (on & PM_RIGHT_B) |
|
2915 off |= PM_LEFT | PM_RIGHT_Z; |
|
2916 if (on & PM_UPPER) |
|
2917 off |= PM_LOWER; |
|
2918 if (on & PM_LOWER) |
|
2919 off |= PM_UPPER; |
|
2920 if (on & PM_HASHED) |
|
2921 off |= PM_ARRAY; |
|
2922 if (on & PM_TIED) |
|
2923 off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED; |
|
2924 |
|
2925 on &= ~off; |
|
2926 |
|
2927 queue_signals(); |
|
2928 |
|
2929 /* Given no arguments, list whatever the options specify. */ |
|
2930 if (OPT_ISSET(ops,'p')) |
|
2931 printflags |= PRINT_TYPESET; |
|
2932 if (!*argv) { |
|
2933 if (!OPT_ISSET(ops,'p')) { |
|
2934 if (!(on|roff)) |
|
2935 printflags |= PRINT_TYPE; |
|
2936 if (roff || OPT_ISSET(ops,'+')) |
|
2937 printflags |= PRINT_NAMEONLY; |
|
2938 } |
|
2939 scanhashtable(paramtab, 1, on|roff, 0, paramtab->printnode, printflags); |
|
2940 unqueue_signals(); |
|
2941 return 0; |
|
2942 } |
|
2943 |
|
2944 if (!(OPT_ISSET(ops,'g') || OPT_ISSET(ops,'x') || OPT_ISSET(ops,'m')) || |
|
2945 OPT_PLUS(ops,'g') || *name == 'l' || |
|
2946 (!isset(GLOBALEXPORT) && !OPT_ISSET(ops,'g'))) |
|
2947 on |= PM_LOCAL; |
|
2948 |
|
2949 if (on & PM_TIED) { |
|
2950 Param apm; |
|
2951 struct asgment asg0; |
|
2952 char *oldval = NULL; |
|
2953 int joinchar; |
|
2954 |
|
2955 if (OPT_ISSET(ops,'m')) { |
|
2956 zwarnnam(name, "incompatible options for -T", NULL, 0); |
|
2957 unqueue_signals(); |
|
2958 return 1; |
|
2959 } |
|
2960 on &= ~off; |
|
2961 if (!argv[1] || (argv[2] && argv[3])) { |
|
2962 zwarnnam(name, "-T requires names of scalar and array", NULL, 0); |
|
2963 unqueue_signals(); |
|
2964 return 1; |
|
2965 } |
|
2966 |
|
2967 /* |
|
2968 * Third argument, if given, is character used to join |
|
2969 * the elements of the array in the scalar. |
|
2970 */ |
|
2971 if (!argv[2]) |
|
2972 joinchar = ':'; |
|
2973 else if (!*argv[2]) |
|
2974 joinchar = 0; |
|
2975 else if (*argv[2] == Meta) |
|
2976 joinchar = argv[2][1] ^ 32; |
|
2977 else |
|
2978 joinchar = *argv[2]; |
|
2979 |
|
2980 if (!(asg = getasg(argv[0]))) { |
|
2981 unqueue_signals(); |
|
2982 return 1; |
|
2983 } |
|
2984 asg0 = *asg; |
|
2985 if (!(asg = getasg(argv[1]))) { |
|
2986 unqueue_signals(); |
|
2987 return 1; |
|
2988 } |
|
2989 if (!strcmp(asg0.name, asg->name)) { |
|
2990 unqueue_signals(); |
|
2991 zerrnam(name, "can't tie a variable to itself", NULL, 0); |
|
2992 return 1; |
|
2993 } |
|
2994 if (strchr(asg0.name, '[') || strchr(asg->name, '[')) { |
|
2995 unqueue_signals(); |
|
2996 zerrnam(name, "can't tie array elements", NULL, 0); |
|
2997 return 1; |
|
2998 } |
|
2999 /* |
|
3000 * Keep the old value of the scalar. We need to do this |
|
3001 * here as if it is already tied to the same array it |
|
3002 * will be unset when we retie the array. This is all |
|
3003 * so that typeset -T is idempotent. |
|
3004 * |
|
3005 * We also need to remember here whether the damn thing is |
|
3006 * exported and pass that along. Isn't the world complicated? |
|
3007 */ |
|
3008 if ((pm = (Param) paramtab->getnode(paramtab, asg0.name)) |
|
3009 && !(pm->flags & PM_UNSET) |
|
3010 && (locallevel == pm->level || !(on & PM_LOCAL))) { |
|
3011 if (!asg0.value && !(PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) |
|
3012 oldval = ztrdup(getsparam(asg0.name)); |
|
3013 on |= (pm->flags & PM_EXPORTED); |
|
3014 } |
|
3015 /* |
|
3016 * Create the tied array; this is normal except that |
|
3017 * it has the PM_TIED flag set. Do it first because |
|
3018 * we need the address. |
|
3019 */ |
|
3020 if (!(apm=typeset_single(name, asg->name, |
|
3021 (Param)paramtab->getnode(paramtab, |
|
3022 asg->name), |
|
3023 func, (on | PM_ARRAY) & ~PM_EXPORTED, |
|
3024 off, roff, asg->value, NULL, ops, 0))) { |
|
3025 unqueue_signals(); |
|
3026 return 1; |
|
3027 } |
|
3028 /* |
|
3029 * Create the tied colonarray. We make it as a normal scalar |
|
3030 * and fix up the oddities later. |
|
3031 */ |
|
3032 if (!(pm=typeset_single(name, asg0.name, |
|
3033 (Param)paramtab->getnode(paramtab, |
|
3034 asg0.name), |
|
3035 func, on, off, roff, asg0.value, apm, |
|
3036 ops, joinchar))) { |
|
3037 if (oldval) |
|
3038 zsfree(oldval); |
|
3039 unsetparam_pm(apm, 1, 1); |
|
3040 unqueue_signals(); |
|
3041 return 1; |
|
3042 } |
|
3043 |
|
3044 /* |
|
3045 * pm->ename is only deleted when the struct is, so |
|
3046 * we need to free it here if it already exists. |
|
3047 */ |
|
3048 if (pm->ename) |
|
3049 zsfree(pm->ename); |
|
3050 pm->ename = ztrdup(asg->name); |
|
3051 if (apm->ename) |
|
3052 zsfree(apm->ename); |
|
3053 apm->ename = ztrdup(asg0.name); |
|
3054 if (oldval) |
|
3055 setsparam(asg0.name, oldval); |
|
3056 unqueue_signals(); |
|
3057 |
|
3058 return 0; |
|
3059 } |
|
3060 if (off & PM_TIED) { |
|
3061 zerrnam(name, "use unset to remove tied variables", NULL, 0); |
|
3062 return 1; |
|
3063 } |
|
3064 |
|
3065 /* With the -m option, treat arguments as glob patterns */ |
|
3066 if (OPT_ISSET(ops,'m')) { |
|
3067 if (!OPT_ISSET(ops,'p')) { |
|
3068 if (!(on|roff)) |
|
3069 printflags |= PRINT_TYPE; |
|
3070 if (!on) |
|
3071 printflags |= PRINT_NAMEONLY; |
|
3072 } |
|
3073 |
|
3074 while ((asg = getasg(*argv++))) { |
|
3075 LinkList pmlist = newlinklist(); |
|
3076 LinkNode pmnode; |
|
3077 |
|
3078 tokenize(asg->name); /* expand argument */ |
|
3079 if (!(pprog = patcompile(asg->name, 0, NULL))) { |
|
3080 untokenize(asg->name); |
|
3081 zwarnnam(name, "bad pattern : %s", argv[-1], 0); |
|
3082 returnval = 1; |
|
3083 continue; |
|
3084 } |
|
3085 if (OPT_PLUS(ops,'m') && !asg->value) { |
|
3086 scanmatchtable(paramtab, pprog, on|roff, 0, |
|
3087 paramtab->printnode, printflags); |
|
3088 continue; |
|
3089 } |
|
3090 /* |
|
3091 * Search through the parameter table and change all parameters |
|
3092 * matching the glob pattern to have these flags and/or value. |
|
3093 * Bad news: if the parameter gets altered, e.g. by |
|
3094 * a type conversion, then paramtab can be shifted around, |
|
3095 * so we need to store the parameters to alter on a separate |
|
3096 * list for later use. |
|
3097 */ |
|
3098 for (i = 0; i < paramtab->hsize; i++) { |
|
3099 for (pm = (Param) paramtab->nodes[i]; pm; |
|
3100 pm = (Param) pm->next) { |
|
3101 if (((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) || |
|
3102 (pm->flags & PM_UNSET)) |
|
3103 continue; |
|
3104 if (pattry(pprog, pm->nam)) |
|
3105 addlinknode(pmlist, pm); |
|
3106 } |
|
3107 } |
|
3108 for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) { |
|
3109 pm = (Param) getdata(pmnode); |
|
3110 if (!typeset_single(name, pm->nam, pm, func, on, off, roff, |
|
3111 asg->value, NULL, ops, 0)) |
|
3112 returnval = 1; |
|
3113 } |
|
3114 } |
|
3115 unqueue_signals(); |
|
3116 return returnval; |
|
3117 } |
|
3118 |
|
3119 /* Take arguments literally. Don't glob */ |
|
3120 while ((asg = getasg(*argv++))) { |
|
3121 if (!typeset_single(name, asg->name, |
|
3122 (Param) (paramtab == realparamtab ? |
|
3123 gethashnode2(paramtab, asg->name) : |
|
3124 paramtab->getnode(paramtab, asg->name)), |
|
3125 func, on, off, roff, asg->value, NULL, |
|
3126 ops, 0)) |
|
3127 returnval = 1; |
|
3128 } |
|
3129 unqueue_signals(); |
|
3130 return returnval; |
|
3131 } |
|
3132 |
|
3133 /* Helper for bin_functions() when run as "autoload -X" */ |
|
3134 |
|
3135 /**/ |
|
3136 int |
|
3137 eval_autoload(Shfunc shf, char *name, Options ops, int func) |
|
3138 { |
|
3139 if (!(shf->flags & PM_UNDEFINED)) |
|
3140 return 1; |
|
3141 |
|
3142 if (shf->funcdef) { |
|
3143 freeeprog(shf->funcdef); |
|
3144 shf->funcdef = &dummy_eprog; |
|
3145 } |
|
3146 if (OPT_MINUS(ops,'X')) { |
|
3147 char *fargv[3]; |
|
3148 fargv[0] = name; |
|
3149 fargv[1] = "\"$@\""; |
|
3150 fargv[2] = 0; |
|
3151 shf->funcdef = mkautofn(shf); |
|
3152 return bin_eval(name, fargv, ops, func); |
|
3153 } |
|
3154 |
|
3155 return !loadautofn(shf, (OPT_ISSET(ops,'k') ? 2 : |
|
3156 (OPT_ISSET(ops,'z') ? 0 : 1)), 1); |
|
3157 } |
|
3158 |
|
3159 /* Display or change the attributes of shell functions. * |
|
3160 * If called as autoload, it will define a new autoloaded * |
|
3161 * (undefined) shell function. */ |
|
3162 |
|
3163 /**/ |
|
3164 int |
|
3165 bin_functions(char *name, char **argv, Options ops, int func) |
|
3166 { |
|
3167 Patprog pprog; |
|
3168 Shfunc shf; |
|
3169 int i, returnval = 0; |
|
3170 int on = 0, off = 0, pflags = 0; |
|
3171 |
|
3172 /* Do we have any flags defined? */ |
|
3173 if (OPT_PLUS(ops,'u')) |
|
3174 off |= PM_UNDEFINED; |
|
3175 else if (OPT_MINUS(ops,'u') || OPT_ISSET(ops,'X')) |
|
3176 on |= PM_UNDEFINED; |
|
3177 if (OPT_MINUS(ops,'U')) |
|
3178 on |= PM_UNALIASED|PM_UNDEFINED; |
|
3179 else if (OPT_PLUS(ops,'U')) |
|
3180 off |= PM_UNALIASED; |
|
3181 if (OPT_MINUS(ops,'t')) |
|
3182 on |= PM_TAGGED; |
|
3183 else if (OPT_PLUS(ops,'t')) |
|
3184 off |= PM_TAGGED; |
|
3185 if (OPT_MINUS(ops,'z')) { |
|
3186 on |= PM_ZSHSTORED; |
|
3187 off |= PM_KSHSTORED; |
|
3188 } else if (OPT_PLUS(ops,'z')) |
|
3189 off |= PM_ZSHSTORED; |
|
3190 if (OPT_MINUS(ops,'k')) { |
|
3191 on |= PM_KSHSTORED; |
|
3192 off |= PM_ZSHSTORED; |
|
3193 } else if (OPT_PLUS(ops,'k')) |
|
3194 off |= PM_KSHSTORED; |
|
3195 |
|
3196 if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) || |
|
3197 (OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || *argv || !scriptname))) { |
|
3198 zwarnnam(name, "invalid option(s)", NULL, 0); |
|
3199 return 1; |
|
3200 } |
|
3201 |
|
3202 if (OPT_PLUS(ops,'f') || OPT_ISSET(ops,'+')) |
|
3203 pflags |= PRINT_NAMEONLY; |
|
3204 |
|
3205 /* If no arguments given, we will print functions. If flags * |
|
3206 * are given, we will print only functions containing these * |
|
3207 * flags, else we'll print them all. */ |
|
3208 if (!*argv) { |
|
3209 int ret = 0; |
|
3210 |
|
3211 queue_signals(); |
|
3212 if (OPT_MINUS(ops,'X')) { |
|
3213 if ((shf = (Shfunc) shfunctab->getnode(shfunctab, scriptname))) { |
|
3214 DPUTS(!shf->funcdef, |
|
3215 "BUG: Calling autoload from empty function"); |
|
3216 } else { |
|
3217 shf = (Shfunc) zshcalloc(sizeof *shf); |
|
3218 shfunctab->addnode(shfunctab, ztrdup(scriptname), shf); |
|
3219 } |
|
3220 shf->flags = on; |
|
3221 ret = eval_autoload(shf, scriptname, ops, func); |
|
3222 } else { |
|
3223 if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u')) |
|
3224 on &= ~PM_UNDEFINED; |
|
3225 scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, |
|
3226 pflags); |
|
3227 } |
|
3228 unqueue_signals(); |
|
3229 return ret; |
|
3230 } |
|
3231 |
|
3232 /* With the -m option, treat arguments as glob patterns */ |
|
3233 if (OPT_ISSET(ops,'m')) { |
|
3234 on &= ~PM_UNDEFINED; |
|
3235 for (; *argv; argv++) { |
|
3236 /* expand argument */ |
|
3237 tokenize(*argv); |
|
3238 if ((pprog = patcompile(*argv, PAT_STATIC, 0))) { |
|
3239 /* with no options, just print all functions matching the glob pattern */ |
|
3240 queue_signals(); |
|
3241 if (!(on|off)) { |
|
3242 scanmatchtable(shfunctab, pprog, 0, DISABLED, |
|
3243 shfunctab->printnode, pflags); |
|
3244 } else { |
|
3245 /* apply the options to all functions matching the glob pattern */ |
|
3246 for (i = 0; i < shfunctab->hsize; i++) { |
|
3247 for (shf = (Shfunc) shfunctab->nodes[i]; shf; |
|
3248 shf = (Shfunc) shf->next) |
|
3249 if (pattry(pprog, shf->nam) && |
|
3250 !(shf->flags & DISABLED)) { |
|
3251 shf->flags = (shf->flags | |
|
3252 (on & ~PM_UNDEFINED)) & ~off; |
|
3253 if (OPT_ISSET(ops,'X') && |
|
3254 eval_autoload(shf, shf->nam, ops, func)) { |
|
3255 returnval = 1; |
|
3256 } |
|
3257 } |
|
3258 } |
|
3259 } |
|
3260 unqueue_signals(); |
|
3261 } else { |
|
3262 untokenize(*argv); |
|
3263 zwarnnam(name, "bad pattern : %s", *argv, 0); |
|
3264 returnval = 1; |
|
3265 } |
|
3266 } |
|
3267 return returnval; |
|
3268 } |
|
3269 |
|
3270 /* Take the arguments literally -- do not glob */ |
|
3271 queue_signals(); |
|
3272 for (; *argv; argv++) { |
|
3273 #ifndef __SYMBIAN32__ |
|
3274 if (OPT_ISSET(ops,'w')) |
|
3275 returnval = dump_autoload(name, *argv, on, ops, func); |
|
3276 else |
|
3277 #endif |
|
3278 if ((shf = (Shfunc) shfunctab->getnode(shfunctab, *argv))) { |
|
3279 /* if any flag was given */ |
|
3280 if (on|off) { |
|
3281 /* turn on/off the given flags */ |
|
3282 shf->flags = (shf->flags | (on & ~PM_UNDEFINED)) & ~off; |
|
3283 if (OPT_ISSET(ops,'X') && |
|
3284 eval_autoload(shf, shf->nam, ops, func)) |
|
3285 returnval = 1; |
|
3286 } else |
|
3287 /* no flags, so just print */ |
|
3288 shfunctab->printnode((HashNode) shf, pflags); |
|
3289 } else if (on & PM_UNDEFINED) { |
|
3290 int signum = -1, ok = 1; |
|
3291 |
|
3292 if (!strncmp(*argv, "TRAP", 4) && |
|
3293 (signum = getsignum(*argv + 4)) != -1) { |
|
3294 /* |
|
3295 * Because of the possibility of alternative names, |
|
3296 * we must remove the trap explicitly. |
|
3297 */ |
|
3298 removetrapnode(signum); |
|
3299 } |
|
3300 |
|
3301 /* Add a new undefined (autoloaded) function to the * |
|
3302 * hash table with the corresponding flags set. */ |
|
3303 shf = (Shfunc) zshcalloc(sizeof *shf); |
|
3304 shf->flags = on; |
|
3305 shf->funcdef = mkautofn(shf); |
|
3306 shfunctab->addnode(shfunctab, ztrdup(*argv), shf); |
|
3307 |
|
3308 if (signum != -1) { |
|
3309 if (settrap(signum, shf->funcdef)) { |
|
3310 shfunctab->removenode(shfunctab, *argv); |
|
3311 shfunctab->freenode((HashNode)shf); |
|
3312 returnval = 1; |
|
3313 ok = 0; |
|
3314 } |
|
3315 else |
|
3316 sigtrapped[signum] |= ZSIG_FUNC; |
|
3317 } |
|
3318 |
|
3319 if (ok && OPT_ISSET(ops,'X') && |
|
3320 eval_autoload(shf, shf->nam, ops, func)) |
|
3321 returnval = 1; |
|
3322 } else |
|
3323 returnval = 1; |
|
3324 } |
|
3325 unqueue_signals(); |
|
3326 return returnval; |
|
3327 } |
|
3328 |
|
3329 /**/ |
|
3330 Eprog |
|
3331 mkautofn(Shfunc shf) |
|
3332 { |
|
3333 Eprog p; |
|
3334 |
|
3335 p = (Eprog) zalloc(sizeof(*p)); |
|
3336 p->len = 5 * sizeof(wordcode); |
|
3337 p->prog = (Wordcode) zalloc(p->len); |
|
3338 p->strs = NULL; |
|
3339 p->shf = shf; |
|
3340 p->npats = 0; |
|
3341 p->nref = 1; /* allocated from permanent storage */ |
|
3342 p->pats = (Patprog *) p->prog; |
|
3343 p->flags = EF_REAL; |
|
3344 p->dump = NULL; |
|
3345 |
|
3346 p->prog[0] = WCB_LIST((Z_SYNC | Z_END), 0); |
|
3347 p->prog[1] = WCB_SUBLIST(WC_SUBLIST_END, 0, 3); |
|
3348 p->prog[2] = WCB_PIPE(WC_PIPE_END, 0); |
|
3349 p->prog[3] = WCB_AUTOFN(); |
|
3350 p->prog[4] = WCB_END(); |
|
3351 |
|
3352 return p; |
|
3353 } |
|
3354 |
|
3355 /* unset: unset parameters */ |
|
3356 |
|
3357 /**/ |
|
3358 int |
|
3359 bin_unset(char *name, char **argv, Options ops, int func) |
|
3360 { |
|
3361 Param pm, next; |
|
3362 Patprog pprog; |
|
3363 char *s; |
|
3364 int match = 0, returnval = 0; |
|
3365 int i; |
|
3366 |
|
3367 /* unset -f is the same as unfunction */ |
|
3368 if (OPT_ISSET(ops,'f')) |
|
3369 return bin_unhash(name, argv, ops, func); |
|
3370 |
|
3371 /* with -m option, treat arguments as glob patterns */ |
|
3372 if (OPT_ISSET(ops,'m')) { |
|
3373 while ((s = *argv++)) { |
|
3374 /* expand */ |
|
3375 tokenize(s); |
|
3376 if ((pprog = patcompile(s, PAT_STATIC, NULL))) { |
|
3377 /* Go through the parameter table, and unset any matches */ |
|
3378 queue_signals(); |
|
3379 for (i = 0; i < paramtab->hsize; i++) { |
|
3380 for (pm = (Param) paramtab->nodes[i]; pm; pm = next) { |
|
3381 /* record pointer to next, since we may free this one */ |
|
3382 next = (Param) pm->next; |
|
3383 if ((!(pm->flags & PM_RESTRICTED) || |
|
3384 unset(RESTRICTED)) && |
|
3385 pattry(pprog, pm->nam)) { |
|
3386 unsetparam_pm(pm, 0, 1); |
|
3387 match++; |
|
3388 } |
|
3389 } |
|
3390 } |
|
3391 unqueue_signals(); |
|
3392 } else { |
|
3393 untokenize(s); |
|
3394 zwarnnam(name, "bad pattern : %s", s, 0); |
|
3395 returnval = 1; |
|
3396 } |
|
3397 } |
|
3398 /* If we didn't match anything, we return 1. */ |
|
3399 if (!match) |
|
3400 returnval = 1; |
|
3401 return returnval; |
|
3402 } |
|
3403 |
|
3404 /* do not glob -- unset the given parameter */ |
|
3405 queue_signals(); |
|
3406 while ((s = *argv++)) { |
|
3407 char *ss = strchr(s, '['); |
|
3408 char *sse = ss; |
|
3409 if (ss) { |
|
3410 if (skipparens('[', ']', &sse) || *sse) { |
|
3411 zerrnam(name, "%s: invalid parameter name", s, 0); |
|
3412 returnval = 1; |
|
3413 continue; |
|
3414 } |
|
3415 *ss = 0; |
|
3416 } |
|
3417 pm = (Param) (paramtab == realparamtab ? |
|
3418 gethashnode2(paramtab, s) : |
|
3419 paramtab->getnode(paramtab, s)); |
|
3420 if (!pm) |
|
3421 returnval = 1; |
|
3422 else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { |
|
3423 zerrnam(name, "%s: restricted", pm->nam, 0); |
|
3424 returnval = 1; |
|
3425 } else if (ss) { |
|
3426 if (PM_TYPE(pm->flags) == PM_HASHED) { |
|
3427 HashTable tht = paramtab; |
|
3428 if ((paramtab = pm->gsu.h->getfn(pm))) { |
|
3429 *--sse = 0; |
|
3430 unsetparam(ss+1); |
|
3431 *sse = ']'; |
|
3432 } |
|
3433 paramtab = tht; |
|
3434 } else { |
|
3435 zerrnam(name, "%s: invalid element for unset", s, 0); |
|
3436 returnval = 1; |
|
3437 } |
|
3438 } else { |
|
3439 if (unsetparam_pm(pm, 0, 1)) |
|
3440 returnval = 1; |
|
3441 } |
|
3442 if (ss) |
|
3443 *ss = '['; |
|
3444 } |
|
3445 unqueue_signals(); |
|
3446 return returnval; |
|
3447 } |
|
3448 |
|
3449 /* type, whence, which, command */ |
|
3450 |
|
3451 /**/ |
|
3452 int |
|
3453 bin_whence(char *nam, char **argv, Options ops, int func) |
|
3454 { |
|
3455 HashNode hn; |
|
3456 Patprog pprog; |
|
3457 int returnval = 0; |
|
3458 int printflags = 0; |
|
3459 int aliasflags; |
|
3460 int csh, all, v, wd; |
|
3461 int informed; |
|
3462 char *cnam; |
|
3463 |
|
3464 /* Check some option information */ |
|
3465 csh = OPT_ISSET(ops,'c'); |
|
3466 v = OPT_ISSET(ops,'v'); |
|
3467 all = OPT_ISSET(ops,'a'); |
|
3468 wd = OPT_ISSET(ops,'w'); |
|
3469 |
|
3470 if (OPT_ISSET(ops,'w')) |
|
3471 printflags |= PRINT_WHENCE_WORD; |
|
3472 else if (OPT_ISSET(ops,'c')) |
|
3473 printflags |= PRINT_WHENCE_CSH; |
|
3474 else if (OPT_ISSET(ops,'v')) |
|
3475 printflags |= PRINT_WHENCE_VERBOSE; |
|
3476 else |
|
3477 printflags |= PRINT_WHENCE_SIMPLE; |
|
3478 if (OPT_ISSET(ops,'f')) |
|
3479 printflags |= PRINT_WHENCE_FUNCDEF; |
|
3480 |
|
3481 if (func == BIN_COMMAND) |
|
3482 if (OPT_ISSET(ops,'V')) { |
|
3483 printflags = aliasflags = PRINT_WHENCE_VERBOSE; |
|
3484 v = 1; |
|
3485 } else { |
|
3486 aliasflags = PRINT_LIST; |
|
3487 printflags = PRINT_WHENCE_SIMPLE; |
|
3488 v = 0; |
|
3489 } |
|
3490 else |
|
3491 aliasflags = printflags; |
|
3492 |
|
3493 /* With -m option -- treat arguments as a glob patterns */ |
|
3494 if (OPT_ISSET(ops,'m')) { |
|
3495 for (; *argv; argv++) { |
|
3496 /* parse the pattern */ |
|
3497 tokenize(*argv); |
|
3498 if (!(pprog = patcompile(*argv, PAT_STATIC, NULL))) { |
|
3499 untokenize(*argv); |
|
3500 zwarnnam(nam, "bad pattern : %s", *argv, 0); |
|
3501 returnval = 1; |
|
3502 continue; |
|
3503 } |
|
3504 queue_signals(); |
|
3505 if (!OPT_ISSET(ops,'p')) { |
|
3506 /* -p option is for path search only. * |
|
3507 * We're not using it, so search for ... */ |
|
3508 |
|
3509 /* aliases ... */ |
|
3510 scanmatchtable(aliastab, pprog, 0, DISABLED, |
|
3511 aliastab->printnode, printflags); |
|
3512 |
|
3513 /* and reserved words ... */ |
|
3514 scanmatchtable(reswdtab, pprog, 0, DISABLED, |
|
3515 reswdtab->printnode, printflags); |
|
3516 |
|
3517 /* and shell functions... */ |
|
3518 scanmatchtable(shfunctab, pprog, 0, DISABLED, |
|
3519 shfunctab->printnode, printflags); |
|
3520 |
|
3521 /* and builtins. */ |
|
3522 scanmatchtable(builtintab, pprog, 0, DISABLED, |
|
3523 builtintab->printnode, printflags); |
|
3524 } |
|
3525 /* Done search for `internal' commands, if the -p option * |
|
3526 * was not used. Now search the path. */ |
|
3527 cmdnamtab->filltable(cmdnamtab); |
|
3528 scanmatchtable(cmdnamtab, pprog, 0, 0, |
|
3529 cmdnamtab->printnode, printflags); |
|
3530 |
|
3531 unqueue_signals(); |
|
3532 } |
|
3533 return returnval; |
|
3534 } |
|
3535 |
|
3536 /* Take arguments literally -- do not glob */ |
|
3537 queue_signals(); |
|
3538 for (; *argv; argv++) { |
|
3539 informed = 0; |
|
3540 |
|
3541 if (!OPT_ISSET(ops,'p')) { |
|
3542 char *suf; |
|
3543 |
|
3544 /* Look for alias */ |
|
3545 if ((hn = aliastab->getnode(aliastab, *argv))) { |
|
3546 aliastab->printnode(hn, aliasflags); |
|
3547 if (!all) |
|
3548 continue; |
|
3549 informed = 1; |
|
3550 } |
|
3551 /* Look for suffix alias */ |
|
3552 if ((suf = strrchr(*argv, '.')) && suf[1] && |
|
3553 suf > *argv && suf[-1] != Meta && |
|
3554 (hn = sufaliastab->getnode(sufaliastab, suf+1))) { |
|
3555 sufaliastab->printnode(hn, printflags); |
|
3556 if (!all) |
|
3557 continue; |
|
3558 informed = 1; |
|
3559 } |
|
3560 /* Look for reserved word */ |
|
3561 if ((hn = reswdtab->getnode(reswdtab, *argv))) { |
|
3562 reswdtab->printnode(hn, printflags); |
|
3563 if (!all) |
|
3564 continue; |
|
3565 informed = 1; |
|
3566 } |
|
3567 /* Look for shell function */ |
|
3568 if ((hn = shfunctab->getnode(shfunctab, *argv))) { |
|
3569 shfunctab->printnode(hn, printflags); |
|
3570 if (!all) |
|
3571 continue; |
|
3572 informed = 1; |
|
3573 } |
|
3574 /* Look for builtin command */ |
|
3575 if ((hn = builtintab->getnode(builtintab, *argv))) { |
|
3576 builtintab->printnode(hn, printflags); |
|
3577 if (!all) |
|
3578 continue; |
|
3579 informed = 1; |
|
3580 } |
|
3581 /* Look for commands that have been added to the * |
|
3582 * cmdnamtab with the builtin `hash foo=bar'. */ |
|
3583 if ((hn = cmdnamtab->getnode(cmdnamtab, *argv)) && (hn->flags & HASHED)) { |
|
3584 cmdnamtab->printnode(hn, printflags); |
|
3585 if (!all) |
|
3586 continue; |
|
3587 informed = 1; |
|
3588 } |
|
3589 } |
|
3590 |
|
3591 /* Option -a is to search the entire path, * |
|
3592 * rather than just looking for one match. */ |
|
3593 if (all) { |
|
3594 char **pp, *buf; |
|
3595 |
|
3596 pushheap(); |
|
3597 for (pp = path; *pp; pp++) { |
|
3598 if (**pp) { |
|
3599 buf = zhtricat(*pp, "/", *argv); |
|
3600 } else buf = ztrdup(*argv); |
|
3601 |
|
3602 if (iscom(buf)) { |
|
3603 if (wd) { |
|
3604 printf("%s: command\n", *argv); |
|
3605 } else { |
|
3606 if (v && !csh) |
|
3607 zputs(*argv, stdout), fputs(" is ", stdout); |
|
3608 zputs(buf, stdout); |
|
3609 if (OPT_ISSET(ops,'s')) |
|
3610 print_if_link(buf); |
|
3611 fputc('\n', stdout); |
|
3612 } |
|
3613 informed = 1; |
|
3614 } |
|
3615 } |
|
3616 if (!informed && (wd || v || csh)) { |
|
3617 zputs(*argv, stdout); |
|
3618 puts(wd ? ": none" : " not found"); |
|
3619 returnval = 1; |
|
3620 } |
|
3621 popheap(); |
|
3622 } else if ((cnam = findcmd(*argv, 1))) { |
|
3623 /* Found external command. */ |
|
3624 if (wd) { |
|
3625 printf("%s: command\n", *argv); |
|
3626 }else { |
|
3627 if (v && !csh) |
|
3628 zputs(*argv, stdout), fputs(" is ", stdout); |
|
3629 zputs(cnam, stdout); |
|
3630 if (OPT_ISSET(ops,'s')) |
|
3631 print_if_link(cnam); |
|
3632 fputc('\n', stdout); |
|
3633 } |
|
3634 }else { |
|
3635 /* Not found at all. */ |
|
3636 if (v || csh || wd) |
|
3637 zputs(*argv, stdout), puts(wd ? ": not builtin command" : " not found"); |
|
3638 returnval = 1; |
|
3639 } |
|
3640 } |
|
3641 unqueue_signals(); |
|
3642 return returnval; |
|
3643 } |
|
3644 |
|
3645 #ifndef __SYMBIAN32__ |
|
3646 /**** command & named directory hash table builtins ****/ |
|
3647 |
|
3648 /***************************************************************** |
|
3649 * hash -- explicitly hash a command. * |
|
3650 * 1) Given no arguments, list the hash table. * |
|
3651 * 2) The -m option prints out commands in the hash table that * |
|
3652 * match a given glob pattern. * |
|
3653 * 3) The -f option causes the entire path to be added to the * |
|
3654 * hash table (cannot be combined with any arguments). * |
|
3655 * 4) The -r option causes the entire hash table to be discarded * |
|
3656 * (cannot be combined with any arguments). * |
|
3657 * 5) Given argument of the form foo=bar, add element to command * |
|
3658 * hash table, so that when `foo' is entered, then `bar' is * |
|
3659 * executed. * |
|
3660 * 6) Given arguments not of the previous form, add it to the * |
|
3661 * command hash table as if it were being executed. * |
|
3662 * 7) The -d option causes analogous things to be done using * |
|
3663 * the named directory hash table. * |
|
3664 *****************************************************************/ |
|
3665 |
|
3666 /**/ |
|
3667 int |
|
3668 bin_hash(char *name, char **argv, Options ops, UNUSED(int func)) |
|
3669 { |
|
3670 HashTable ht; |
|
3671 Patprog pprog; |
|
3672 Asgment asg; |
|
3673 int returnval = 0; |
|
3674 int printflags = 0; |
|
3675 |
|
3676 if (OPT_ISSET(ops,'d')) |
|
3677 ht = nameddirtab; |
|
3678 else |
|
3679 ht = cmdnamtab; |
|
3680 |
|
3681 if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'f')) { |
|
3682 /* -f and -r can't be used with any arguments */ |
|
3683 if (*argv) { |
|
3684 zwarnnam("hash", "too many arguments", NULL, 0); |
|
3685 return 1; |
|
3686 } |
|
3687 |
|
3688 /* empty the hash table */ |
|
3689 if (OPT_ISSET(ops,'r')) |
|
3690 ht->emptytable(ht); |
|
3691 |
|
3692 /* fill the hash table in a standard way */ |
|
3693 if (OPT_ISSET(ops,'f')) |
|
3694 ht->filltable(ht); |
|
3695 |
|
3696 return 0; |
|
3697 } |
|
3698 |
|
3699 if (OPT_ISSET(ops,'L')) printflags |= PRINT_LIST; |
|
3700 |
|
3701 /* Given no arguments, display current hash table. */ |
|
3702 if (!*argv) { |
|
3703 queue_signals(); |
|
3704 scanhashtable(ht, 1, 0, 0, ht->printnode, printflags); |
|
3705 unqueue_signals(); |
|
3706 return 0; |
|
3707 } |
|
3708 |
|
3709 queue_signals(); |
|
3710 while (*argv) { |
|
3711 void *hn; |
|
3712 if (OPT_ISSET(ops,'m')) { |
|
3713 /* with the -m option, treat the argument as a glob pattern */ |
|
3714 tokenize(*argv); /* expand */ |
|
3715 if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) { |
|
3716 /* display matching hash table elements */ |
|
3717 scanmatchtable(ht, pprog, 0, 0, ht->printnode, printflags); |
|
3718 } else { |
|
3719 untokenize(*argv); |
|
3720 zwarnnam(name, "bad pattern : %s", *argv, 0); |
|
3721 returnval = 1; |
|
3722 } |
|
3723 } else if ((asg = getasg(*argv)) && asg->value) { |
|
3724 if(isset(RESTRICTED)) { |
|
3725 zwarnnam(name, "restricted: %s", asg->value, 0); |
|
3726 returnval = 1; |
|
3727 } else { |
|
3728 /* The argument is of the form foo=bar, * |
|
3729 * so define an entry for the table. */ |
|
3730 if(OPT_ISSET(ops,'d')) { |
|
3731 Nameddir nd = hn = zshcalloc(sizeof *nd); |
|
3732 nd->flags = 0; |
|
3733 nd->dir = ztrdup(asg->value); |
|
3734 } else { |
|
3735 Cmdnam cn = hn = zshcalloc(sizeof *cn); |
|
3736 cn->flags = HASHED; |
|
3737 cn->u.cmd = ztrdup(asg->value); |
|
3738 } |
|
3739 ht->addnode(ht, ztrdup(asg->name), hn); |
|
3740 if(OPT_ISSET(ops,'v')) |
|
3741 ht->printnode(hn, 0); |
|
3742 } |
|
3743 } else if (!(hn = ht->getnode2(ht, asg->name))) { |
|
3744 /* With no `=value' part to the argument, * |
|
3745 * work out what it ought to be. */ |
|
3746 if(OPT_ISSET(ops,'d')) { |
|
3747 if(!getnameddir(asg->name)) { |
|
3748 zwarnnam(name, "no such directory name: %s", asg->name, 0); |
|
3749 returnval = 1; |
|
3750 } |
|
3751 } else { |
|
3752 if (!hashcmd(asg->name, path)) { |
|
3753 zwarnnam(name, "no such command: %s", asg->name, 0); |
|
3754 returnval = 1; |
|
3755 } |
|
3756 } |
|
3757 if(OPT_ISSET(ops,'v') && (hn = ht->getnode2(ht, asg->name))) |
|
3758 ht->printnode(hn, 0); |
|
3759 } else if(OPT_ISSET(ops,'v')) |
|
3760 ht->printnode(hn, 0); |
|
3761 argv++; |
|
3762 } |
|
3763 unqueue_signals(); |
|
3764 return returnval; |
|
3765 } |
|
3766 #endif //__SYMBIAN32__ |
|
3767 |
|
3768 /* unhash: remove specified elements from a hash table */ |
|
3769 |
|
3770 /**/ |
|
3771 int |
|
3772 bin_unhash(char *name, char **argv, Options ops, UNUSED(int func)) |
|
3773 { |
|
3774 HashTable ht; |
|
3775 HashNode hn, nhn; |
|
3776 Patprog pprog; |
|
3777 int match = 0, returnval = 0; |
|
3778 int i; |
|
3779 |
|
3780 /* Check which hash table we are working with. */ |
|
3781 if (OPT_ISSET(ops,'d')) |
|
3782 ht = nameddirtab; /* named directories */ |
|
3783 else if (OPT_ISSET(ops,'f')) |
|
3784 ht = shfunctab; /* shell functions */ |
|
3785 else if (OPT_ISSET(ops,'s')) |
|
3786 ht = sufaliastab; /* suffix aliases, must precede aliases */ |
|
3787 else if (OPT_ISSET(ops,'a')) |
|
3788 ht = aliastab; /* aliases */ |
|
3789 else |
|
3790 ht = cmdnamtab; /* external commands */ |
|
3791 |
|
3792 /* With -m option, treat arguments as glob patterns. * |
|
3793 * "unhash -m '*'" is legal, but not recommended. */ |
|
3794 if (OPT_ISSET(ops,'m')) { |
|
3795 for (; *argv; argv++) { |
|
3796 /* expand argument */ |
|
3797 tokenize(*argv); |
|
3798 if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) { |
|
3799 /* remove all nodes matching glob pattern */ |
|
3800 queue_signals(); |
|
3801 for (i = 0; i < ht->hsize; i++) { |
|
3802 for (hn = ht->nodes[i]; hn; hn = nhn) { |
|
3803 /* record pointer to next, since we may free this one */ |
|
3804 nhn = hn->next; |
|
3805 if (pattry(pprog, hn->nam)) { |
|
3806 ht->freenode(ht->removenode(ht, hn->nam)); |
|
3807 match++; |
|
3808 } |
|
3809 } |
|
3810 } |
|
3811 unqueue_signals(); |
|
3812 } else { |
|
3813 untokenize(*argv); |
|
3814 zwarnnam(name, "bad pattern : %s", *argv, 0); |
|
3815 returnval = 1; |
|
3816 } |
|
3817 } |
|
3818 /* If we didn't match anything, we return 1. */ |
|
3819 if (!match) |
|
3820 returnval = 1; |
|
3821 return returnval; |
|
3822 } |
|
3823 |
|
3824 /* Take arguments literally -- do not glob */ |
|
3825 queue_signals(); |
|
3826 for (; *argv; argv++) { |
|
3827 if ((hn = ht->removenode(ht, *argv))) { |
|
3828 ht->freenode(hn); |
|
3829 } else { |
|
3830 zwarnnam(name, "no such hash table element: %s", *argv, 0); |
|
3831 returnval = 1; |
|
3832 } |
|
3833 } |
|
3834 unqueue_signals(); |
|
3835 return returnval; |
|
3836 } |
|
3837 |
|
3838 /**** alias builtins ****/ |
|
3839 |
|
3840 /* alias: display or create aliases. */ |
|
3841 |
|
3842 /**/ |
|
3843 int |
|
3844 bin_alias(char *name, char **argv, Options ops, UNUSED(int func)) |
|
3845 { |
|
3846 Alias a; |
|
3847 Patprog pprog; |
|
3848 Asgment asg; |
|
3849 int returnval = 0; |
|
3850 int flags1 = 0, flags2 = DISABLED; |
|
3851 int printflags = 0; |
|
3852 int type_opts; |
|
3853 HashTable ht = aliastab; |
|
3854 |
|
3855 /* Did we specify the type of alias? */ |
|
3856 type_opts = OPT_ISSET(ops, 'r') + OPT_ISSET(ops, 'g') + |
|
3857 OPT_ISSET(ops, 's'); |
|
3858 if (type_opts) { |
|
3859 if (type_opts > 1) { |
|
3860 zwarnnam(name, "illegal combination of options", NULL, 0); |
|
3861 return 1; |
|
3862 } |
|
3863 if (OPT_ISSET(ops,'g')) |
|
3864 flags1 |= ALIAS_GLOBAL; |
|
3865 else |
|
3866 flags2 |= ALIAS_GLOBAL; |
|
3867 if (OPT_ISSET(ops, 's')) { |
|
3868 /* |
|
3869 * Although we keep suffix aliases in a different table, |
|
3870 * it is useful to be able to distinguish Alias structures |
|
3871 * without reference to the table, so we have a separate |
|
3872 * flag, too. |
|
3873 */ |
|
3874 flags1 |= ALIAS_SUFFIX; |
|
3875 ht = sufaliastab; |
|
3876 } else |
|
3877 flags2 |= ALIAS_SUFFIX; |
|
3878 } |
|
3879 |
|
3880 if (OPT_ISSET(ops,'L')) |
|
3881 printflags |= PRINT_LIST; |
|
3882 else if (OPT_PLUS(ops,'g') || OPT_PLUS(ops,'r') || OPT_PLUS(ops,'s') || |
|
3883 OPT_PLUS(ops,'m') || OPT_ISSET(ops,'+')) |
|
3884 printflags |= PRINT_NAMEONLY; |
|
3885 |
|
3886 /* In the absence of arguments, list all aliases. If a command * |
|
3887 * line flag is specified, list only those of that type. */ |
|
3888 if (!*argv) { |
|
3889 queue_signals(); |
|
3890 scanhashtable(ht, 1, flags1, flags2, ht->printnode, printflags); |
|
3891 unqueue_signals(); |
|
3892 return 0; |
|
3893 } |
|
3894 |
|
3895 /* With the -m option, treat the arguments as * |
|
3896 * glob patterns of aliases to display. */ |
|
3897 if (OPT_ISSET(ops,'m')) { |
|
3898 for (; *argv; argv++) { |
|
3899 tokenize(*argv); /* expand argument */ |
|
3900 if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) { |
|
3901 /* display the matching aliases */ |
|
3902 queue_signals(); |
|
3903 scanmatchtable(ht, pprog, flags1, flags2, |
|
3904 ht->printnode, printflags); |
|
3905 unqueue_signals(); |
|
3906 } else { |
|
3907 untokenize(*argv); |
|
3908 zwarnnam(name, "bad pattern : %s", *argv, 0); |
|
3909 returnval = 1; |
|
3910 } |
|
3911 } |
|
3912 return returnval; |
|
3913 } |
|
3914 |
|
3915 /* Take arguments literally. Don't glob */ |
|
3916 queue_signals(); |
|
3917 while ((asg = getasg(*argv++))) { |
|
3918 if (asg->value && !OPT_ISSET(ops,'L')) { |
|
3919 /* The argument is of the form foo=bar and we are not * |
|
3920 * forcing a listing with -L, so define an alias */ |
|
3921 ht->addnode(ht, ztrdup(asg->name), |
|
3922 createaliasnode(ztrdup(asg->value), flags1)); |
|
3923 } else if ((a = (Alias) ht->getnode(ht, asg->name))) { |
|
3924 /* display alias if appropriate */ |
|
3925 if (!type_opts || ht == sufaliastab || |
|
3926 (OPT_ISSET(ops,'r') && |
|
3927 !(a->flags & (ALIAS_GLOBAL|ALIAS_SUFFIX))) || |
|
3928 (OPT_ISSET(ops,'g') && (a->flags & ALIAS_GLOBAL))) |
|
3929 ht->printnode((HashNode) a, printflags); |
|
3930 } else |
|
3931 returnval = 1; |
|
3932 } |
|
3933 unqueue_signals(); |
|
3934 return returnval; |
|
3935 } |
|
3936 |
|
3937 |
|
3938 /**** miscellaneous builtins ****/ |
|
3939 |
|
3940 /* true, : (colon) */ |
|
3941 |
|
3942 /**/ |
|
3943 int |
|
3944 bin_true(UNUSED(char *name), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func)) |
|
3945 { |
|
3946 return 0; |
|
3947 } |
|
3948 |
|
3949 /* false builtin */ |
|
3950 |
|
3951 /**/ |
|
3952 int |
|
3953 bin_false(UNUSED(char *name), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func)) |
|
3954 { |
|
3955 return 1; |
|
3956 } |
|
3957 |
|
3958 /* the zle buffer stack */ |
|
3959 |
|
3960 /**/ |
|
3961 mod_export LinkList bufstack; |
|
3962 |
|
3963 /* echo, print, printf, pushln */ |
|
3964 |
|
3965 #define print_val(VAL) \ |
|
3966 if (prec >= 0) \ |
|
3967 count += fprintf(fout, spec, width, prec, VAL); \ |
|
3968 else \ |
|
3969 count += fprintf(fout, spec, width, VAL); |
|
3970 |
|
3971 /**/ |
|
3972 int |
|
3973 bin_print(char *name, char **args, Options ops, int func) |
|
3974 { |
|
3975 int flen, width, prec, type, argc, n, narg; |
|
3976 int nnl = 0, ret = 0, maxarg = 0; |
|
3977 int flags[5], *len; |
|
3978 char *start, *endptr, *c, *d, *flag, *buf, spec[13], *fmt = NULL; |
|
3979 char **first, *curarg, *flagch = "0+- #", save = '\0', nullstr = '\0'; |
|
3980 size_t rcount, count = 0; |
|
3981 #ifdef HAVE_OPEN_MEMSTREAM |
|
3982 size_t mcount; |
|
3983 #endif |
|
3984 FILE *fout = stdout; |
|
3985 Histent ent; |
|
3986 |
|
3987 mnumber mnumval; |
|
3988 double doubleval; |
|
3989 int intval; |
|
3990 zlong zlongval; |
|
3991 zulong zulongval; |
|
3992 char *stringval; |
|
3993 |
|
3994 if (func == BIN_PRINTF) { |
|
3995 if (!strcmp(*args, "--") && !*++args) { |
|
3996 zwarnnam(name, "not enough arguments", NULL, 0); |
|
3997 return 1; |
|
3998 } |
|
3999 fmt = *args++; |
|
4000 } else if (func == BIN_ECHO && isset(BSDECHO)) |
|
4001 ops->ind['E'] = 1; |
|
4002 else if (OPT_HASARG(ops,'f')) |
|
4003 fmt = OPT_ARG(ops,'f'); |
|
4004 if (fmt) |
|
4005 #ifndef __SYMBIAN32__ |
|
4006 fmt = getkeystring(fmt, &flen, OPT_ISSET(ops,'b') ? 2 : 0, &nnl); |
|
4007 #else |
|
4008 fmt = getkeystring(fmt, &flen, 0, &nnl); |
|
4009 #endif |
|
4010 first = args; |
|
4011 |
|
4012 /* -m option -- treat the first argument as a pattern and remove |
|
4013 * arguments not matching */ |
|
4014 if (OPT_ISSET(ops,'m')) { |
|
4015 Patprog pprog; |
|
4016 char **t, **p; |
|
4017 |
|
4018 if (!*args) { |
|
4019 zwarnnam(name, "no pattern specified", NULL, 0); |
|
4020 return 1; |
|
4021 } |
|
4022 tokenize(*args); |
|
4023 if (!(pprog = patcompile(*args, PAT_STATIC, NULL))) { |
|
4024 untokenize(*args); |
|
4025 zwarnnam(name, "bad pattern : %s", *args, 0); |
|
4026 return 1; |
|
4027 } |
|
4028 for (t = p = ++args; *p; p++) |
|
4029 if (pattry(pprog, *p)) |
|
4030 *t++ = *p; |
|
4031 *t = NULL; |
|
4032 first = args; |
|
4033 if (fmt && !*args) return 0; |
|
4034 } |
|
4035 /* compute lengths, and interpret according to -P, -D, -e, etc. */ |
|
4036 argc = arrlen(args); |
|
4037 len = (int *) hcalloc(argc * sizeof(int)); |
|
4038 for(n = 0; n < argc; n++) { |
|
4039 /* first \ sequences */ |
|
4040 if (fmt || |
|
4041 (!OPT_ISSET(ops,'e') && |
|
4042 (OPT_ISSET(ops,'R') || OPT_ISSET(ops,'r') || OPT_ISSET(ops,'E')))) |
|
4043 unmetafy(args[n], &len[n]); |
|
4044 else |
|
4045 #ifndef __SYMBIAN32__ |
|
4046 args[n] = getkeystring(args[n], &len[n], OPT_ISSET(ops,'b') ? 2 : |
|
4047 (func != BIN_ECHO && !OPT_ISSET(ops,'e')), |
|
4048 &nnl); |
|
4049 #else |
|
4050 args[n] = getkeystring(args[n], &len[n], (func != BIN_ECHO && !OPT_ISSET(ops,'e')), |
|
4051 &nnl); |
|
4052 #endif |
|
4053 /* -P option -- interpret as a prompt sequence */ |
|
4054 if(OPT_ISSET(ops,'P')) { |
|
4055 /* |
|
4056 * promptexpand uses permanent storage: to avoid |
|
4057 * messy memory management, stick it on the heap |
|
4058 * instead. |
|
4059 */ |
|
4060 char *str = unmetafy(promptexpand(metafy(args[n], len[n], |
|
4061 META_NOALLOC), 0, NULL, NULL), &len[n]); |
|
4062 args[n] = dupstring(str); |
|
4063 free(str); |
|
4064 } |
|
4065 #ifndef __SYMBIAN32__ |
|
4066 /* -D option -- interpret as a directory, and use ~ */ |
|
4067 if(OPT_ISSET(ops,'D')) { |
|
4068 Nameddir d; |
|
4069 |
|
4070 queue_signals(); |
|
4071 d = finddir(args[n]); |
|
4072 if(d) { |
|
4073 char *arg = zhalloc(strlen(args[n]) + 1); |
|
4074 sprintf(arg, "~%s%s", d->nam, |
|
4075 args[n] + strlen(d->dir)); |
|
4076 args[n] = arg; |
|
4077 len[n] = strlen(args[n]); |
|
4078 } |
|
4079 unqueue_signals(); |
|
4080 } |
|
4081 #endif |
|
4082 } |
|
4083 |
|
4084 /* -u and -p -- output to other than standard output */ |
|
4085 if (OPT_HASARG(ops,'u')/* || OPT_ISSET(ops,'p')*/) { |
|
4086 int fd; |
|
4087 |
|
4088 if (OPT_ISSET(ops, 'p')) |
|
4089 fd = coprocout; |
|
4090 else { |
|
4091 char *argptr = OPT_ARG(ops,'u'), *eptr; |
|
4092 /* Handle undocumented feature that -up worked */ |
|
4093 if (!strcmp(argptr, "p")) { |
|
4094 fd = coprocout; |
|
4095 } else { |
|
4096 fd = (int)zstrtol(argptr, &eptr, 10); |
|
4097 if (*eptr) { |
|
4098 zwarnnam(name, "number expected after -%c: %s", argptr, |
|
4099 'u'); |
|
4100 return 1; |
|
4101 } |
|
4102 } |
|
4103 } |
|
4104 |
|
4105 if ((fd = dup(fd)) < 0) { |
|
4106 zwarnnam(name, "bad file number: %d", NULL, fd); |
|
4107 return 1; |
|
4108 } |
|
4109 if ((fout = fdopen(fd, "w")) == 0) { |
|
4110 close(fd); |
|
4111 zwarnnam(name, "bad mode on fd %d", NULL, fd); |
|
4112 return 1; |
|
4113 } |
|
4114 } |
|
4115 |
|
4116 /* -o and -O -- sort the arguments */ |
|
4117 if (OPT_ISSET(ops,'o')) { |
|
4118 if (fmt && !*args) return 0; |
|
4119 if (OPT_ISSET(ops,'i')) |
|
4120 qsort(args, arrlen(args), sizeof(char *), cstrpcmp); |
|
4121 else |
|
4122 qsort(args, arrlen(args), sizeof(char *), strpcmp); |
|
4123 } else if (OPT_ISSET(ops,'O')) { |
|
4124 if (fmt && !*args) return 0; |
|
4125 if (OPT_ISSET(ops,'i')) |
|
4126 qsort(args, arrlen(args), sizeof(char *), invcstrpcmp); |
|
4127 else |
|
4128 qsort(args, arrlen(args), sizeof(char *), invstrpcmp); |
|
4129 } |
|
4130 /* after sorting arguments, recalculate lengths */ |
|
4131 if(OPT_ISSET(ops,'o') || OPT_ISSET(ops,'O')) |
|
4132 for(n = 0; n < argc; n++) |
|
4133 len[n] = strlen(args[n]); |
|
4134 |
|
4135 /* -c -- output in columns */ |
|
4136 if (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C')) { |
|
4137 int l, nc, nr, sc, n, t, i; |
|
4138 char **ap; |
|
4139 |
|
4140 if (OPT_ISSET(ops,'C')) { |
|
4141 char *eptr, *argptr = OPT_ARG(ops,'C'); |
|
4142 nc = (int)zstrtol(argptr, &eptr, 10); |
|
4143 if (*eptr) { |
|
4144 zwarnnam(name, "number expected after -%c: %s", argptr, 'C'); |
|
4145 return 1; |
|
4146 } |
|
4147 if (nc <= 0) { |
|
4148 zwarnnam(name, "invalid number of columns: %s", argptr, 0); |
|
4149 return 1; |
|
4150 } |
|
4151 /* |
|
4152 * n: number of elements |
|
4153 * nc: number of columns |
|
4154 * nr: number of rows |
|
4155 */ |
|
4156 n = arrlen(args); |
|
4157 nr = (n + nc - 1) / nc; |
|
4158 |
|
4159 /* |
|
4160 * i: loop counter |
|
4161 * ap: array iterator |
|
4162 * l: maximum length seen |
|
4163 * |
|
4164 * Ignore lengths in last column since they don't affect |
|
4165 * the separation. |
|
4166 */ |
|
4167 for (i = l = 0, ap = args; *ap; ap++, i++) { |
|
4168 if (OPT_ISSET(ops, 'a')) { |
|
4169 if ((i % nc) == nc - 1) |
|
4170 continue; |
|
4171 } else { |
|
4172 if (i >= nr * (nc - 1)) |
|
4173 break; |
|
4174 } |
|
4175 if (l < (t = strlen(*ap))) |
|
4176 l = t; |
|
4177 } |
|
4178 sc = l + 2; |
|
4179 } |
|
4180 else |
|
4181 { |
|
4182 /* |
|
4183 * n: loop counter |
|
4184 * ap: array iterator |
|
4185 * l: maximum length seen |
|
4186 */ |
|
4187 for (n = l = 0, ap = args; *ap; ap++, n++) |
|
4188 if (l < (t = strlen(*ap))) |
|
4189 l = t; |
|
4190 |
|
4191 /* |
|
4192 * sc: column width |
|
4193 * nc: number of columns (at least one) |
|
4194 */ |
|
4195 sc = l + 2; |
|
4196 nc = (columns + 1) / sc; |
|
4197 if (!nc) |
|
4198 nc = 1; |
|
4199 nr = (n + nc - 1) / nc; |
|
4200 } |
|
4201 |
|
4202 if (OPT_ISSET(ops,'a')) /* print across, i.e. columns first */ |
|
4203 ap = args; |
|
4204 for (i = 0; i < nr; i++) { |
|
4205 if (OPT_ISSET(ops,'a')) |
|
4206 { |
|
4207 int ic; |
|
4208 for (ic = 0; ic < nc && *ap; ic++, ap++) |
|
4209 { |
|
4210 l = strlen(*ap); |
|
4211 fprintf(fout, "%s", *ap); |
|
4212 if (*ap) |
|
4213 for (; l < sc; l++) |
|
4214 fputc(' ', fout); |
|
4215 } |
|
4216 } |
|
4217 else |
|
4218 { |
|
4219 ap = args + i; |
|
4220 do { |
|
4221 l = strlen(*ap); |
|
4222 fprintf(fout, "%s", *ap); |
|
4223 for (t = nr; t && *ap; t--, ap++); |
|
4224 if(*ap) |
|
4225 for (; l < sc; l++) |
|
4226 fputc(' ', fout); |
|
4227 } while (*ap); |
|
4228 } |
|
4229 fputc(OPT_ISSET(ops,'N') ? '\0' : '\n', fout); |
|
4230 } |
|
4231 /* Testing EBADF special-cases >&- redirections */ |
|
4232 if ((fout != stdout) ? (fclose(fout) != 0) : |
|
4233 (fflush(fout) != 0 && errno != EBADF)) { |
|
4234 zwarnnam(name, "write error: %e", NULL, errno); |
|
4235 ret = 1; |
|
4236 } |
|
4237 return ret; |
|
4238 } |
|
4239 |
|
4240 /* normal output */ |
|
4241 if (!fmt) { |
|
4242 /* -z option -- push the arguments onto the editing buffer stack */ |
|
4243 if (OPT_ISSET(ops,'z')) { |
|
4244 queue_signals(); |
|
4245 zpushnode(bufstack, sepjoin(args, NULL, 0)); |
|
4246 unqueue_signals(); |
|
4247 return 0; |
|
4248 } |
|
4249 /* -s option -- add the arguments to the history list */ |
|
4250 if (OPT_ISSET(ops,'s')) { |
|
4251 int nwords = 0, nlen, iwords; |
|
4252 char **pargs = args; |
|
4253 |
|
4254 queue_signals(); |
|
4255 ent = prepnexthistent(); |
|
4256 while (*pargs++) |
|
4257 nwords++; |
|
4258 if ((ent->nwords = nwords)) { |
|
4259 ent->words = (short *)zalloc(nwords*2*sizeof(short)); |
|
4260 nlen = iwords = 0; |
|
4261 for (pargs = args; *pargs; pargs++) { |
|
4262 ent->words[iwords++] = nlen; |
|
4263 nlen += strlen(*pargs); |
|
4264 ent->words[iwords++] = nlen; |
|
4265 nlen++; |
|
4266 } |
|
4267 } else |
|
4268 ent->words = (short *)NULL; |
|
4269 ent->text = zjoin(args, ' ', 0); |
|
4270 ent->stim = ent->ftim = time(NULL); |
|
4271 ent->flags = 0; |
|
4272 addhistnode(histtab, ent->text, ent); |
|
4273 unqueue_signals(); |
|
4274 return 0; |
|
4275 } |
|
4276 |
|
4277 for (; *args; args++, len++) { |
|
4278 fwrite(*args, *len, 1, fout); |
|
4279 if (args[1]) |
|
4280 fputc(OPT_ISSET(ops,'l') ? '\n' : |
|
4281 OPT_ISSET(ops,'N') ? '\0' : ' ', fout); |
|
4282 } |
|
4283 if (!(OPT_ISSET(ops,'n') || nnl)) |
|
4284 fputc(OPT_ISSET(ops,'N') ? '\0' : '\n', fout); |
|
4285 |
|
4286 /* Testing EBADF special-cases >&- redirections */ |
|
4287 if ((fout != stdout) ? (fclose(fout) != 0) : |
|
4288 (fflush(fout) != 0 && errno != EBADF)) { |
|
4289 zwarnnam(name, "write error: %e", NULL, errno); |
|
4290 ret = 1; |
|
4291 } |
|
4292 return ret; |
|
4293 } |
|
4294 |
|
4295 if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) { |
|
4296 #ifdef HAVE_OPEN_MEMSTREAM |
|
4297 if ((fout = open_memstream(&buf, &mcount)) == NULL) |
|
4298 zwarnnam(name, "open_memstream failed", NULL, 0); |
|
4299 #else |
|
4300 int tempfd; |
|
4301 char *tmpf; |
|
4302 if ((tempfd = gettempfile(NULL, 1, &tmpf)) < 0 |
|
4303 || (fout = fdopen(tempfd, "w+")) == NULL) |
|
4304 zwarnnam(name, "can't open temp file: %e", NULL, errno); |
|
4305 unlink(tmpf); |
|
4306 #endif |
|
4307 } |
|
4308 |
|
4309 /* printf style output */ |
|
4310 *spec='%'; |
|
4311 do { |
|
4312 rcount = count; |
|
4313 if (maxarg) { |
|
4314 first += maxarg; |
|
4315 argc -= maxarg; |
|
4316 maxarg = 0; |
|
4317 } |
|
4318 for (c = fmt;c-fmt < flen;c++) { |
|
4319 if (*c != '%') { |
|
4320 putc(*c, fout); |
|
4321 ++count; |
|
4322 continue; |
|
4323 } |
|
4324 |
|
4325 start = c++; |
|
4326 if (*c == '%') { |
|
4327 putchar('%'); |
|
4328 ++count; |
|
4329 continue; |
|
4330 } |
|
4331 |
|
4332 type = prec = -1; |
|
4333 width = 0; |
|
4334 curarg = NULL; |
|
4335 d = spec + 1; |
|
4336 |
|
4337 if (*c >= '1' && *c <= '9') { |
|
4338 narg = strtoul(c, &endptr, 0); |
|
4339 if (*endptr == '$') { |
|
4340 c = endptr + 1; |
|
4341 DPUTS(narg <= 0, "specified zero or negative arg"); |
|
4342 if (narg > argc) { |
|
4343 zwarnnam(name, "%d: argument specifier out of range", |
|
4344 0, narg); |
|
4345 return 1; |
|
4346 } else { |
|
4347 if (narg > maxarg) maxarg = narg; |
|
4348 curarg = *(first + narg - 1); |
|
4349 } |
|
4350 } |
|
4351 } |
|
4352 |
|
4353 |
|
4354 /* copy only one of each flag as spec has finite size */ |
|
4355 memset(flags, 0, sizeof(flags)); |
|
4356 while ((flag = strchr(flagch, *c))) { |
|
4357 if (!flags[flag - flagch]) { |
|
4358 flags[flag - flagch] = 1; |
|
4359 *d++ = *c; |
|
4360 } |
|
4361 c++; |
|
4362 } |
|
4363 |
|
4364 if (idigit(*c)) { |
|
4365 width = strtoul(c, &endptr, 0); |
|
4366 c = endptr; |
|
4367 } else if (*c == '*') { |
|
4368 if (idigit(*++c)) { |
|
4369 narg = strtoul(c, &endptr, 0); |
|
4370 if (*endptr == '$') { |
|
4371 c = endptr + 1; |
|
4372 if (narg > argc || narg <= 0) { |
|
4373 zwarnnam(name, |
|
4374 "%d: argument specifier out of range", |
|
4375 0, narg); |
|
4376 return 1; |
|
4377 } else { |
|
4378 if (narg > maxarg) maxarg = narg; |
|
4379 args = first + narg - 1; |
|
4380 } |
|
4381 } |
|
4382 } |
|
4383 if (*args) { |
|
4384 width = (int)mathevali(*args++); |
|
4385 if (errflag) { |
|
4386 errflag = 0; |
|
4387 ret = 1; |
|
4388 } |
|
4389 } |
|
4390 } |
|
4391 *d++ = '*'; |
|
4392 |
|
4393 if (*c == '.') { |
|
4394 if (*++c == '*') { |
|
4395 if (idigit(*++c)) { |
|
4396 narg = strtoul(c, &endptr, 0); |
|
4397 if (*endptr == '$') { |
|
4398 c = endptr + 1; |
|
4399 if (narg > argc || narg <= 0) { |
|
4400 zwarnnam(name, |
|
4401 "%d: argument specifier out of range", |
|
4402 0, narg); |
|
4403 return 1; |
|
4404 } else { |
|
4405 if (narg > maxarg) maxarg = narg; |
|
4406 args = first + narg - 1; |
|
4407 } |
|
4408 } |
|
4409 } |
|
4410 |
|
4411 if (*args) { |
|
4412 prec = (int)mathevali(*args++); |
|
4413 if (errflag) { |
|
4414 errflag = 0; |
|
4415 ret = 1; |
|
4416 } |
|
4417 } |
|
4418 } else if (idigit(*c)) { |
|
4419 prec = strtoul(c, &endptr, 0); |
|
4420 c = endptr; |
|
4421 } |
|
4422 if (prec >= 0) *d++ = '.', *d++ = '*'; |
|
4423 } |
|
4424 |
|
4425 /* ignore any size modifier */ |
|
4426 if (*c == 'l' || *c == 'L' || *c == 'h') c++; |
|
4427 |
|
4428 if (!curarg && *args) curarg = *args++; |
|
4429 d[1] = '\0'; |
|
4430 switch (*d = *c) { |
|
4431 case 'c': |
|
4432 if (curarg) { |
|
4433 intval = *curarg; |
|
4434 } else |
|
4435 intval = 0; |
|
4436 print_val(intval); |
|
4437 break; |
|
4438 case 's': |
|
4439 stringval = curarg ? curarg : &nullstr; |
|
4440 print_val(stringval); |
|
4441 break; |
|
4442 case 'b': |
|
4443 if (curarg) { |
|
4444 int l; |
|
4445 #ifndef __SYMBIAN32__ |
|
4446 char *b = getkeystring(curarg, &l, |
|
4447 OPT_ISSET(ops,'b') ? 2 : 0, &nnl); |
|
4448 #else |
|
4449 char *b = getkeystring(curarg, &l, |
|
4450 0, &nnl); |
|
4451 #endif |
|
4452 /* handle width/precision here and use fwrite so that |
|
4453 * nul characters can be output */ |
|
4454 if (prec >= 0 && prec < l) l = prec; |
|
4455 if (width > 0 && flags[2]) width = -width; |
|
4456 if (width > 0 && l < width) |
|
4457 printf("%*c", width - l, ' '); |
|
4458 fwrite(b, l, 1, fout); |
|
4459 if (width < 0 && l < -width) |
|
4460 printf("%*c", -width - l, ' '); |
|
4461 count += l; |
|
4462 } |
|
4463 break; |
|
4464 case 'q': |
|
4465 stringval = curarg ? bslashquote(curarg, NULL, 0) : &nullstr; |
|
4466 *d = 's'; |
|
4467 print_val(stringval); |
|
4468 break; |
|
4469 case 'd': |
|
4470 case 'i': |
|
4471 type=1; |
|
4472 break; |
|
4473 case 'e': |
|
4474 case 'E': |
|
4475 case 'f': |
|
4476 case 'g': |
|
4477 case 'G': |
|
4478 type=2; |
|
4479 break; |
|
4480 case 'o': |
|
4481 case 'u': |
|
4482 case 'x': |
|
4483 case 'X': |
|
4484 type=3; |
|
4485 break; |
|
4486 case 'n': |
|
4487 if (curarg) setiparam(curarg, count - rcount); |
|
4488 break; |
|
4489 default: |
|
4490 if (*c) { |
|
4491 save = c[1]; |
|
4492 c[1] = '\0'; |
|
4493 } |
|
4494 zwarnnam(name, "%s: invalid directive", start, 0); |
|
4495 if (*c) c[1] = save; |
|
4496 /* Testing EBADF special-cases >&- redirections */ |
|
4497 if ((fout != stdout) ? (fclose(fout) != 0) : |
|
4498 (fflush(fout) != 0 && errno != EBADF)) { |
|
4499 zwarnnam(name, "write error: %e", NULL, errno); |
|
4500 } |
|
4501 return 1; |
|
4502 } |
|
4503 |
|
4504 if (type > 0) { |
|
4505 if (curarg && (*curarg == '\'' || *curarg == '"' )) { |
|
4506 if (type == 2) { |
|
4507 doubleval = (unsigned char)curarg[1]; |
|
4508 print_val(doubleval); |
|
4509 } else { |
|
4510 intval = (unsigned char)curarg[1]; |
|
4511 print_val(intval); |
|
4512 } |
|
4513 } else { |
|
4514 switch (type) { |
|
4515 case 1: |
|
4516 #ifdef ZSH_64_BIT_TYPE |
|
4517 *d++ = 'l'; |
|
4518 #endif |
|
4519 *d++ = 'l', *d++ = *c, *d = '\0'; |
|
4520 zlongval = (curarg) ? mathevali(curarg) : 0; |
|
4521 if (errflag) { |
|
4522 zlongval = 0; |
|
4523 errflag = 0; |
|
4524 ret = 1; |
|
4525 } |
|
4526 print_val(zlongval) |
|
4527 break; |
|
4528 case 2: |
|
4529 if (curarg) { |
|
4530 mnumval = matheval(curarg); |
|
4531 doubleval = (mnumval.type & MN_FLOAT) ? |
|
4532 mnumval.u.d : (double)mnumval.u.l; |
|
4533 } else doubleval = 0; |
|
4534 if (errflag) { |
|
4535 doubleval = 0; |
|
4536 errflag = 0; |
|
4537 ret = 1; |
|
4538 } |
|
4539 print_val(doubleval) |
|
4540 break; |
|
4541 case 3: |
|
4542 #ifdef ZSH_64_BIT_UTYPE |
|
4543 *d++ = 'l'; |
|
4544 #endif |
|
4545 *d++ = 'l', *d++ = *c, *d = '\0'; |
|
4546 zulongval = (curarg) ? mathevali(curarg) : 0; |
|
4547 if (errflag) { |
|
4548 zulongval = 0; |
|
4549 errflag = 0; |
|
4550 ret = 1; |
|
4551 } |
|
4552 print_val(zulongval) |
|
4553 } |
|
4554 } |
|
4555 } |
|
4556 if (maxarg && (args - first > maxarg)) |
|
4557 maxarg = args - first; |
|
4558 } |
|
4559 #ifdef __SYMBIAN32__ |
|
4560 fputc('\n', fout); |
|
4561 #endif |
|
4562 if (maxarg) args = first + maxarg; |
|
4563 /* if there are remaining args, reuse format string */ |
|
4564 } while (*args && args != first && !OPT_ISSET(ops,'r')); |
|
4565 |
|
4566 if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) { |
|
4567 #ifdef HAVE_OPEN_MEMSTREAM |
|
4568 putc(0, fout); |
|
4569 fflush(fout); |
|
4570 count = mcount; |
|
4571 #else |
|
4572 rewind(fout); |
|
4573 buf = (char *)zalloc(count + 1); |
|
4574 fread(buf, count, 1, fout); |
|
4575 buf[count] = '\0'; |
|
4576 #endif |
|
4577 queue_signals(); |
|
4578 if (OPT_ISSET(ops,'z')) { |
|
4579 zpushnode(bufstack, buf); |
|
4580 } else { |
|
4581 ent = prepnexthistent(); |
|
4582 ent->text = buf; |
|
4583 ent->stim = ent->ftim = time(NULL); |
|
4584 ent->flags = 0; |
|
4585 ent->words = (short *)NULL; |
|
4586 addhistnode(histtab, ent->text, ent); |
|
4587 } |
|
4588 unqueue_signals(); |
|
4589 } |
|
4590 |
|
4591 /* Testing EBADF special-cases >&- redirections */ |
|
4592 if ((fout != stdout) ? (fclose(fout) != 0) : |
|
4593 (fflush(fout) != 0 && errno != EBADF)) { |
|
4594 zwarnnam(name, "write error: %e", NULL, errno); |
|
4595 ret = 1; |
|
4596 } |
|
4597 return ret; |
|
4598 } |
|
4599 |
|
4600 /* shift builtin */ |
|
4601 |
|
4602 /**/ |
|
4603 int |
|
4604 bin_shift(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) |
|
4605 { |
|
4606 int num = 1, l, ret = 0; |
|
4607 char **s; |
|
4608 |
|
4609 /* optional argument can be either numeric or an array */ |
|
4610 queue_signals(); |
|
4611 if (*argv && !getaparam(*argv)) |
|
4612 num = mathevali(*argv++); |
|
4613 |
|
4614 if (num < 0) { |
|
4615 unqueue_signals(); |
|
4616 zwarnnam(name, "argument to shift must be non-negative", NULL, 0); |
|
4617 return 1; |
|
4618 } |
|
4619 |
|
4620 if (*argv) { |
|
4621 for (; *argv; argv++) |
|
4622 if ((s = getaparam(*argv))) { |
|
4623 if (num > arrlen(s)) { |
|
4624 zwarnnam(name, "shift count must be <= $#", NULL, 0); |
|
4625 ret++; |
|
4626 continue; |
|
4627 } |
|
4628 s = zarrdup(s + num); |
|
4629 setaparam(*argv, s); |
|
4630 } |
|
4631 } else { |
|
4632 if (num > (l = arrlen(pparams))) { |
|
4633 zwarnnam(name, "shift count must be <= $#", NULL, 0); |
|
4634 ret = 1; |
|
4635 } else { |
|
4636 s = zalloc((l - num + 1) * sizeof(char *)); |
|
4637 memcpy(s, pparams + num, (l - num + 1) * sizeof(char *)); |
|
4638 while (num--) |
|
4639 zsfree(pparams[num]); |
|
4640 zfree(pparams, (l + 1) * sizeof(char *)); |
|
4641 pparams = s; |
|
4642 } |
|
4643 } |
|
4644 unqueue_signals(); |
|
4645 return ret; |
|
4646 } |
|
4647 |
|
4648 /**/ |
|
4649 int optcind; |
|
4650 |
|
4651 /* getopts: automagical option handling for shell scripts */ |
|
4652 |
|
4653 /**/ |
|
4654 int |
|
4655 bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int func)) |
|
4656 { |
|
4657 int lenstr, lenoptstr, quiet, lenoptbuf; |
|
4658 char *optstr = unmetafy(*argv++, &lenoptstr), *var = *argv++; |
|
4659 char **args = (*argv) ? argv : pparams; |
|
4660 char *str, optbuf[2] = " ", *p, opch; |
|
4661 |
|
4662 /* zoptind keeps count of the current argument number. The * |
|
4663 * user can set it to zero to start a new option parse. */ |
|
4664 if (zoptind < 1) { |
|
4665 /* first call */ |
|
4666 zoptind = 1; |
|
4667 optcind = 0; |
|
4668 } |
|
4669 if(zoptind > arrlen(args)) |
|
4670 /* no more options */ |
|
4671 return 1; |
|
4672 |
|
4673 /* leading ':' in optstr means don't print an error message */ |
|
4674 quiet = *optstr == ':'; |
|
4675 optstr += quiet; |
|
4676 lenoptstr -= quiet; |
|
4677 |
|
4678 /* find place in relevant argument */ |
|
4679 str = unmetafy(dupstring(args[zoptind - 1]), &lenstr); |
|
4680 if (!lenstr) /* Definitely not an option. */ |
|
4681 return 1; |
|
4682 if(optcind >= lenstr) { |
|
4683 optcind = 0; |
|
4684 if(!args[zoptind++]) |
|
4685 return 1; |
|
4686 str = unmetafy(dupstring(args[zoptind - 1]), &lenstr); |
|
4687 } |
|
4688 if(!optcind) { |
|
4689 if(lenstr < 2 || (*str != '-' && *str != '+')) |
|
4690 return 1; |
|
4691 if(lenstr == 2 && str[0] == '-' && str[1] == '-') { |
|
4692 zoptind++; |
|
4693 return 1; |
|
4694 } |
|
4695 optcind++; |
|
4696 } |
|
4697 opch = str[optcind++]; |
|
4698 if(str[0] == '+') { |
|
4699 optbuf[0] = '+'; |
|
4700 lenoptbuf = 2; |
|
4701 } else |
|
4702 lenoptbuf = 1; |
|
4703 optbuf[lenoptbuf - 1] = opch; |
|
4704 |
|
4705 /* check for legality */ |
|
4706 if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) { |
|
4707 p = "?"; |
|
4708 err: |
|
4709 zsfree(zoptarg); |
|
4710 setsparam(var, ztrdup(p)); |
|
4711 if(quiet) { |
|
4712 zoptarg = metafy(optbuf, lenoptbuf, META_DUP); |
|
4713 } else { |
|
4714 zwarn(*p == '?' ? "bad option: -%c" : |
|
4715 "argument expected after -%c option", NULL, opch); |
|
4716 zoptarg=ztrdup(""); |
|
4717 } |
|
4718 return 0; |
|
4719 } |
|
4720 |
|
4721 /* check for required argument */ |
|
4722 if(p[1] == ':') { |
|
4723 if(optcind == lenstr) { |
|
4724 if(!args[zoptind]) { |
|
4725 p = ":"; |
|
4726 goto err; |
|
4727 } |
|
4728 p = ztrdup(args[zoptind++]); |
|
4729 } else |
|
4730 p = metafy(str+optcind, lenstr-optcind, META_DUP); |
|
4731 /* |
|
4732 * Careful: I've just changed the following two lines from |
|
4733 * optcind = ztrlen(args[zoptind - 1]); |
|
4734 * and it's a rigorous theorem that every change in getopts breaks |
|
4735 * something. See zsh-workers/9095 for the bug fixed here. |
|
4736 * PWS 2000/05/02 |
|
4737 */ |
|
4738 optcind = 0; |
|
4739 zoptind++; |
|
4740 zsfree(zoptarg); |
|
4741 zoptarg = p; |
|
4742 } else { |
|
4743 zsfree(zoptarg); |
|
4744 zoptarg = ztrdup(""); |
|
4745 } |
|
4746 |
|
4747 setsparam(var, metafy(optbuf, lenoptbuf, META_DUP)); |
|
4748 return 0; |
|
4749 } |
|
4750 |
|
4751 /* Flag that we should exit the shell as soon as all functions return. */ |
|
4752 /**/ |
|
4753 mod_export int |
|
4754 exit_pending; |
|
4755 |
|
4756 /* break, bye, continue, exit, logout, return -- most of these take * |
|
4757 * one numeric argument, and the other (logout) is related to return. * |
|
4758 * (return is treated as a logout when in a login shell.) */ |
|
4759 |
|
4760 /**/ |
|
4761 int |
|
4762 bin_break(char *name, char **argv, UNUSED(Options ops), int func) |
|
4763 { |
|
4764 int num = lastval, nump = 0; |
|
4765 |
|
4766 /* handle one optional numeric argument */ |
|
4767 if (*argv) { |
|
4768 num = mathevali(*argv++); |
|
4769 nump = 1; |
|
4770 } |
|
4771 |
|
4772 switch (func) { |
|
4773 case BIN_CONTINUE: |
|
4774 if (!loops) { /* continue is only permitted in loops */ |
|
4775 /* TODO: Check zerrnam() behaviour with fprintf*/ |
|
4776 fprintf(stdout,"not in while, until, select, or repeat loop"); |
|
4777 return 1; |
|
4778 } |
|
4779 contflag = 1; /* ARE WE SUPPOSED TO FALL THROUGH HERE? */ |
|
4780 case BIN_BREAK: |
|
4781 if (!loops) { /* break is only permitted in loops */ |
|
4782 zerrnam(name, "not in while, until, select, or repeat loop", NULL, 0); |
|
4783 return 1; |
|
4784 } |
|
4785 breaks = nump ? minimum(num,loops) : 1; |
|
4786 break; |
|
4787 case BIN_RETURN: |
|
4788 if (isset(INTERACTIVE) || locallevel || sourcelevel) { |
|
4789 retflag = 1; |
|
4790 breaks = loops; |
|
4791 lastval = num; |
|
4792 if (trapreturn == -2) |
|
4793 trapreturn = lastval; |
|
4794 return lastval; |
|
4795 } |
|
4796 zexit(num, 0); /* else treat return as logout/exit */ |
|
4797 break; |
|
4798 case BIN_LOGOUT: |
|
4799 #ifndef __SYMBIAN32__ |
|
4800 if (unset(LOGINSHELL)) { |
|
4801 zerrnam(name, "not login shell", NULL, 0); |
|
4802 return 1; |
|
4803 } |
|
4804 #else |
|
4805 { |
|
4806 zerrnam(name, "not supported", NULL, 0); |
|
4807 return 1; |
|
4808 } |
|
4809 #endif |
|
4810 /*FALLTHROUGH*/ |
|
4811 case BIN_EXIT: |
|
4812 if (locallevel) { |
|
4813 /* |
|
4814 * We don't exit directly from functions to allow tidying |
|
4815 * up, in particular EXIT traps. We still need to perform |
|
4816 * the usual interactive tests to see if we can exit at |
|
4817 * all, however. |
|
4818 */ |
|
4819 if (stopmsg || (zexit(0,2), !stopmsg)) { |
|
4820 retflag = 1; |
|
4821 breaks = loops; |
|
4822 exit_pending = (num << 1) | 1; |
|
4823 } |
|
4824 } else |
|
4825 zexit(num, 0); |
|
4826 break; |
|
4827 } |
|
4828 return 0; |
|
4829 } |
|
4830 |
|
4831 |
|
4832 /* we have printed a 'you have stopped (running) jobs.' message */ |
|
4833 |
|
4834 /**/ |
|
4835 mod_export int stopmsg; |
|
4836 |
|
4837 /* check to see if user has jobs running/stopped */ |
|
4838 |
|
4839 /**/ |
|
4840 static void |
|
4841 checkjobs(void) |
|
4842 { |
|
4843 int i; |
|
4844 |
|
4845 for (i = 1; i <= maxjob; i++) |
|
4846 if (i != thisjob && (jobtab[i].stat & STAT_LOCKED) && |
|
4847 !(jobtab[i].stat & STAT_NOPRINT)) |
|
4848 break; |
|
4849 if (i <= maxjob) { |
|
4850 if (jobtab[i].stat & STAT_STOPPED) { |
|
4851 |
|
4852 #ifdef USE_SUSPENDED |
|
4853 zerr("you have suspended jobs.", NULL, 0); |
|
4854 #else |
|
4855 zerr("you have stopped jobs.", NULL, 0); |
|
4856 #endif |
|
4857 |
|
4858 } else |
|
4859 zerr("you have running jobs.", NULL, 0); |
|
4860 stopmsg = 1; |
|
4861 } |
|
4862 } |
|
4863 |
|
4864 /* exit the shell. val is the return value of the shell. * |
|
4865 * from_where is |
|
4866 * 1 if zexit is called because of a signal |
|
4867 * 2 if we can't actually exit yet (e.g. functions need |
|
4868 * terminating) but should perform the usual interactive tests. |
|
4869 */ |
|
4870 |
|
4871 /**/ |
|
4872 mod_export void |
|
4873 zexit(int val, int from_where) |
|
4874 { |
|
4875 static int in_exit; |
|
4876 |
|
4877 if (isset(MONITOR) && !stopmsg && from_where != 1) { |
|
4878 scanjobs(); /* check if jobs need printing */ |
|
4879 if (isset(CHECKJOBS)) |
|
4880 checkjobs(); /* check if any jobs are running/stopped */ |
|
4881 if (stopmsg) { |
|
4882 stopmsg = 2; |
|
4883 return; |
|
4884 } |
|
4885 } |
|
4886 if (from_where == 2 || (in_exit++ && from_where)) |
|
4887 return; |
|
4888 |
|
4889 if (isset(MONITOR)) { |
|
4890 /* send SIGHUP to any jobs left running */ |
|
4891 killrunjobs(from_where == 1); |
|
4892 } |
|
4893 if (isset(RCS) && interact) { |
|
4894 if (!nohistsave) { |
|
4895 int writeflags = HFILE_USE_OPTIONS; |
|
4896 if (from_where == 1) |
|
4897 writeflags |= HFILE_NO_REWRITE; |
|
4898 saveandpophiststack(1, writeflags); |
|
4899 savehistfile(NULL, 1, writeflags); |
|
4900 } |
|
4901 if (islogin && !subsh) { |
|
4902 sourcehome(".zlogout"); |
|
4903 #ifdef GLOBAL_ZLOGOUT |
|
4904 if (isset(RCS) && isset(GLOBALRCS)) |
|
4905 source(GLOBAL_ZLOGOUT); |
|
4906 #endif |
|
4907 } |
|
4908 } |
|
4909 if (sigtrapped[SIGEXIT]) |
|
4910 dotrap(SIGEXIT); |
|
4911 runhookdef(EXITHOOK, NULL); |
|
4912 if (opts[MONITOR] && interact && (SHTTY != -1)) { |
|
4913 release_pgrp(); |
|
4914 } |
|
4915 if (mypid != getpid()) |
|
4916 _exit(val); |
|
4917 else |
|
4918 exit(val); |
|
4919 } |
|
4920 |
|
4921 /* . (dot), source */ |
|
4922 |
|
4923 /**/ |
|
4924 int |
|
4925 bin_dot(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) |
|
4926 { |
|
4927 char **old, *old0 = NULL; |
|
4928 int ret, diddot = 0, dotdot = 0; |
|
4929 char *s, **t, *enam, *arg0, *buf; |
|
4930 struct stat st; |
|
4931 |
|
4932 if (!*argv) |
|
4933 return 0; |
|
4934 old = pparams; |
|
4935 /* get arguments for the script */ |
|
4936 if (argv[1]) |
|
4937 pparams = zarrdup(argv + 1); |
|
4938 |
|
4939 enam = arg0 = ztrdup(*argv); |
|
4940 if (isset(FUNCTIONARGZERO)) { |
|
4941 old0 = argzero; |
|
4942 argzero = arg0; |
|
4943 } |
|
4944 s = unmeta(enam); |
|
4945 errno = ENOENT; |
|
4946 ret = 1; |
|
4947 /* for source only, check in current directory first */ |
|
4948 if (*name != '.' && access(s, F_OK) == 0 |
|
4949 && stat(s, &st) >= 0 && !S_ISDIR(st.st_mode)) { |
|
4950 diddot = 1; |
|
4951 ret = source(enam); |
|
4952 } |
|
4953 if (ret) { |
|
4954 /* use a path with / in it */ |
|
4955 for (s = arg0; *s; s++) |
|
4956 if (*s == '/' || *s == '\\') { |
|
4957 if (*arg0 == '.') { |
|
4958 if (arg0 + 1 == s) |
|
4959 ++diddot; |
|
4960 else if (arg0[1] == '.' && arg0 + 2 == s) |
|
4961 ++dotdot; |
|
4962 } |
|
4963 ret = source(arg0); |
|
4964 break; |
|
4965 } |
|
4966 if (!*s || (ret && isset(PATHDIRS) && diddot < 2 && dotdot == 0)) { |
|
4967 pushheap(); |
|
4968 /* search path for script */ |
|
4969 for (t = path; *t; t++) { |
|
4970 if (!(*t)[0] || ((*t)[0] == '.' && !(*t)[1])) { |
|
4971 if (diddot) |
|
4972 continue; |
|
4973 diddot = 1; |
|
4974 buf = dupstring(arg0); |
|
4975 } else |
|
4976 buf = zhtricat(*t, "/", arg0); |
|
4977 |
|
4978 s = unmeta(buf); |
|
4979 if (access(s, F_OK) == 0 && stat(s, &st) >= 0 |
|
4980 && !S_ISDIR(st.st_mode)) { |
|
4981 ret = source(enam = buf); |
|
4982 break; |
|
4983 } |
|
4984 } |
|
4985 popheap(); |
|
4986 } |
|
4987 } |
|
4988 /* clean up and return */ |
|
4989 if (argv[1]) { |
|
4990 freearray(pparams); |
|
4991 pparams = old; |
|
4992 } |
|
4993 if (ret) |
|
4994 zwarnnam(name, "%e: %s", enam, errno); |
|
4995 zsfree(arg0); |
|
4996 if (old0) |
|
4997 argzero = old0; |
|
4998 return ret ? ret : lastval; |
|
4999 } |
|
5000 |
|
5001 /**/ |
|
5002 int |
|
5003 bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) |
|
5004 { |
|
5005 emulate(*argv, OPT_ISSET(ops,'R')); |
|
5006 if (OPT_ISSET(ops,'L')) |
|
5007 opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1; |
|
5008 return 0; |
|
5009 } |
|
5010 |
|
5011 /* eval: simple evaluation */ |
|
5012 |
|
5013 /**/ |
|
5014 int ineval; |
|
5015 |
|
5016 /**/ |
|
5017 int |
|
5018 bin_eval(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func)) |
|
5019 { |
|
5020 Eprog prog; |
|
5021 char *oscriptname = scriptname; |
|
5022 int oineval = ineval; |
|
5023 /* |
|
5024 * If EVALLINENO is not set, we use the line number of the |
|
5025 * environment and must flag this up to exec.c. Otherwise, |
|
5026 * we use a special script name to indicate the special line number. |
|
5027 */ |
|
5028 ineval = !isset(EVALLINENO); |
|
5029 if (!ineval) |
|
5030 scriptname = "(eval)"; |
|
5031 |
|
5032 prog = parse_string(zjoin(argv, ' ', 1)); |
|
5033 if (prog) { |
|
5034 lastval = 0; |
|
5035 |
|
5036 execode(prog, 1, 0); |
|
5037 |
|
5038 if (errflag) |
|
5039 lastval = errflag; |
|
5040 } else { |
|
5041 lastval = 1; |
|
5042 } |
|
5043 |
|
5044 |
|
5045 errflag = 0; |
|
5046 scriptname = oscriptname; |
|
5047 ineval = oineval; |
|
5048 |
|
5049 return lastval; |
|
5050 } |
|
5051 |
|
5052 static char *zbuf; |
|
5053 static int readfd; |
|
5054 |
|
5055 /* Read a character from readfd, or from the buffer zbuf. Return EOF on end of |
|
5056 file/buffer. */ |
|
5057 |
|
5058 /* read: get a line of input, or (for compctl functions) return some * |
|
5059 * useful data about the state of the editing line. The -E and -e * |
|
5060 * options mean that the result should be sent to stdout. -e means, * |
|
5061 * in addition, that the result should not actually be assigned to * |
|
5062 * the specified parameters. */ |
|
5063 |
|
5064 /**/ |
|
5065 int |
|
5066 bin_read(char *name, char **args, Options ops, UNUSED(int func)) |
|
5067 { |
|
5068 char *reply, *readpmpt; |
|
5069 int bsiz, c = 0, gotnl = 0, al = 0, first, nchars = 1, bslash, keys = 0; |
|
5070 int haso = 0; /* true if /dev/tty has been opened specially */ |
|
5071 int isem = !strcmp(term, "emacs"), izle = zleactive && getkeyptr; |
|
5072 char *buf, *bptr, *firstarg, *zbuforig; |
|
5073 LinkList readll = newlinklist(); |
|
5074 FILE *oshout = NULL; |
|
5075 int readchar = -1, val, resettty = 0; |
|
5076 struct ttyinfo saveti; |
|
5077 char d; |
|
5078 char delim = '\n'; |
|
5079 char *eptr, *optarg; |
|
5080 |
|
5081 if (OPT_HASARG(ops,c='k')) { |
|
5082 optarg = OPT_ARG(ops,c); |
|
5083 nchars = (int)zstrtol(optarg, &eptr, 10); |
|
5084 if (*eptr) { |
|
5085 zwarnnam(name, "number expected after -%c: %s", optarg, c); |
|
5086 return 1; |
|
5087 } |
|
5088 } |
|
5089 /* This `*args++ : *args' looks a bit weird, but it works around a bug |
|
5090 * in gcc-2.8.1 under DU 4.0. */ |
|
5091 firstarg = (*args && **args == '?' ? *args++ : *args); |
|
5092 reply = *args ? *args++ : OPT_ISSET(ops,'A') ? "reply" : "REPLY"; |
|
5093 |
|
5094 if (OPT_ISSET(ops,'A') && *args) { |
|
5095 zwarnnam(name, "only one array argument allowed", NULL, 0); |
|
5096 return 1; |
|
5097 } |
|
5098 |
|
5099 /* handle compctl case */ |
|
5100 if(OPT_ISSET(ops,'l') || OPT_ISSET(ops,'c')) |
|
5101 return compctlread(name, args, ops, reply); |
|
5102 |
|
5103 if ((OPT_ISSET(ops,'k') && !OPT_ISSET(ops,'u') && |
|
5104 !OPT_ISSET(ops,'p')) || OPT_ISSET(ops,'q')) { |
|
5105 if (!zleactive) { |
|
5106 if (SHTTY == -1) { |
|
5107 /* need to open /dev/tty specially */ |
|
5108 if ((SHTTY = open("/dev/tty", O_RDWR|O_NOCTTY)) != -1) { |
|
5109 haso = 1; |
|
5110 oshout = shout; |
|
5111 init_shout(); |
|
5112 } |
|
5113 } else if (!shout) { |
|
5114 /* We need an output FILE* on the tty */ |
|
5115 init_shout(); |
|
5116 } |
|
5117 /* We should have a SHTTY opened by now. */ |
|
5118 if (SHTTY == -1) { |
|
5119 /* Unfortunately, we didn't. */ |
|
5120 fprintf(stderr, "not interactive and can't open terminal\n"); |
|
5121 fflush(stderr); |
|
5122 return 1; |
|
5123 } |
|
5124 if (unset(INTERACTIVE)) |
|
5125 gettyinfo(&shttyinfo); |
|
5126 /* attach to the tty */ |
|
5127 attachtty(mypgrp); |
|
5128 if (!isem && OPT_ISSET(ops,'k')) |
|
5129 setcbreak(); |
|
5130 readfd = SHTTY; |
|
5131 } |
|
5132 keys = 1; |
|
5133 } else if (OPT_HASARG(ops,'u') && !OPT_ISSET(ops,'p')) { |
|
5134 /* -u means take input from the specified file descriptor. */ |
|
5135 char *eptr, *argptr = OPT_ARG(ops,'u'); |
|
5136 /* The old code handled -up, but that was never documented. Still...*/ |
|
5137 if (!strcmp(argptr, "p")) { |
|
5138 readfd = coprocin; |
|
5139 } else { |
|
5140 readfd = (int)zstrtol(argptr, &eptr, 10); |
|
5141 if (*eptr) { |
|
5142 zwarnnam(name, "number expected after -%c: %s", argptr, 'u'); |
|
5143 return 1; |
|
5144 } |
|
5145 } |
|
5146 #if 0 |
|
5147 /* This code is left as a warning to future generations --- pws. */ |
|
5148 for (readfd = 9; readfd && !OPT_ISSET(ops,readfd + '0'); --readfd); |
|
5149 #endif |
|
5150 izle = 0; |
|
5151 } else if (OPT_ISSET(ops,'p')) { |
|
5152 readfd = coprocin; |
|
5153 izle = 0; |
|
5154 } else |
|
5155 readfd = izle = 0; |
|
5156 |
|
5157 if (OPT_ISSET(ops,'t')) { |
|
5158 zlong timeout = 0; |
|
5159 if (OPT_HASARG(ops,'t')) { |
|
5160 mnumber mn = zero_mnumber; |
|
5161 mn = matheval(OPT_ARG(ops,'t')); |
|
5162 if (errflag) |
|
5163 return 1; |
|
5164 if (mn.type == MN_FLOAT) { |
|
5165 mn.u.d *= 1e6; |
|
5166 timeout = (zlong)mn.u.d; |
|
5167 } else { |
|
5168 timeout = (zlong)mn.u.l * (zlong)1000000; |
|
5169 } |
|
5170 } |
|
5171 if (readfd == -1 || |
|
5172 !read_poll(readfd, &readchar, keys && !zleactive, timeout)) { |
|
5173 if (OPT_ISSET(ops,'k') && !zleactive && !isem) |
|
5174 settyinfo(&shttyinfo); |
|
5175 if (haso) { |
|
5176 fclose(shout); |
|
5177 shout = oshout; |
|
5178 SHTTY = -1; |
|
5179 } |
|
5180 return 1; |
|
5181 } |
|
5182 } |
|
5183 if (OPT_ISSET(ops,'d')) { |
|
5184 char *delimstr = OPT_ARG(ops,'d'); |
|
5185 delim = (delimstr[0] == Meta) ? delimstr[1] ^ 32 : delimstr[0]; |
|
5186 if (SHTTY != -1) { |
|
5187 struct ttyinfo ti; |
|
5188 gettyinfo(&ti); |
|
5189 saveti = ti; |
|
5190 resettty = 1; |
|
5191 #ifdef HAS_TIO |
|
5192 ti.tio.c_lflag &= ~ICANON; |
|
5193 ti.tio.c_cc[VMIN] = 1; |
|
5194 ti.tio.c_cc[VTIME] = 0; |
|
5195 #else |
|
5196 ti.sgttyb.sg_flags |= CBREAK; |
|
5197 #endif |
|
5198 settyinfo(&ti); |
|
5199 } |
|
5200 } |
|
5201 if (OPT_ISSET(ops,'s') && SHTTY != -1) { |
|
5202 #ifndef __SYMBIAN32__ |
|
5203 struct ttyinfo ti; |
|
5204 gettyinfo(&ti); |
|
5205 if (! resettty) { |
|
5206 saveti = ti; |
|
5207 resettty = 1; |
|
5208 } |
|
5209 #ifdef HAS_TIO |
|
5210 ti.tio.c_lflag &= ~ECHO; |
|
5211 #else |
|
5212 ti.sgttyb.sg_flags &= ~ECHO; |
|
5213 #endif |
|
5214 settyinfo(&ti); |
|
5215 #else |
|
5216 zwarn("bad option: -%c", NULL, 's'); |
|
5217 return 1; |
|
5218 #endif |
|
5219 } |
|
5220 |
|
5221 /* handle prompt */ |
|
5222 if (firstarg) { |
|
5223 for (readpmpt = firstarg; |
|
5224 *readpmpt && *readpmpt != '?'; readpmpt++); |
|
5225 if (*readpmpt++) { |
|
5226 if (keys || isatty(0)) { |
|
5227 zputs(readpmpt, (shout ? shout : stderr)); |
|
5228 fflush(shout ? shout : stderr); |
|
5229 } |
|
5230 readpmpt[-1] = '\0'; |
|
5231 } |
|
5232 } |
|
5233 |
|
5234 /* option -k means read only a given number of characters (default 1) */ |
|
5235 if (OPT_ISSET(ops,'k')) { |
|
5236 /* allocate buffer space for result */ |
|
5237 bptr = buf = (char *)zalloc(nchars+1); |
|
5238 |
|
5239 do { |
|
5240 if (izle) { |
|
5241 if ((val = getkeyptr(0)) < 0) |
|
5242 break; |
|
5243 *bptr++ = (char) val; |
|
5244 nchars--; |
|
5245 } else { |
|
5246 /* If read returns 0, is end of file */ |
|
5247 if (readchar >= 0) { |
|
5248 *bptr = readchar; |
|
5249 val = 1; |
|
5250 readchar = -1; |
|
5251 } else if ((val = read(readfd, bptr, nchars)) <= 0) |
|
5252 break; |
|
5253 |
|
5254 /* decrement number of characters read from number required */ |
|
5255 nchars -= val; |
|
5256 |
|
5257 /* increment pointer past read characters */ |
|
5258 bptr += val; |
|
5259 } |
|
5260 } while (nchars > 0); |
|
5261 |
|
5262 if (!izle && !OPT_ISSET(ops,'u') && !OPT_ISSET(ops,'p')) { |
|
5263 /* dispose of result appropriately, etc. */ |
|
5264 if (isem) |
|
5265 while (val > 0 && read(SHTTY, &d, 1) == 1 && d != '\n'); |
|
5266 else { |
|
5267 settyinfo(&shttyinfo); |
|
5268 resettty = 0; |
|
5269 } |
|
5270 if (haso) { |
|
5271 fclose(shout); /* close(SHTTY) */ |
|
5272 shout = oshout; |
|
5273 SHTTY = -1; |
|
5274 } |
|
5275 } |
|
5276 |
|
5277 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) |
|
5278 fwrite(buf, bptr - buf, 1, stdout); |
|
5279 if (!OPT_ISSET(ops,'e')) |
|
5280 setsparam(reply, metafy(buf, bptr - buf, META_REALLOC)); |
|
5281 else |
|
5282 zfree(buf, bptr - buf + 1); |
|
5283 if (resettty && SHTTY != -1) |
|
5284 settyinfo(&saveti); |
|
5285 return val <= 0; |
|
5286 } |
|
5287 |
|
5288 /* option -q means get one character, and interpret it as a Y or N */ |
|
5289 if (OPT_ISSET(ops,'q')) { |
|
5290 char readbuf[2]; |
|
5291 |
|
5292 /* set up the buffer */ |
|
5293 readbuf[1] = '\0'; |
|
5294 |
|
5295 /* get, and store, reply */ |
|
5296 if (izle) { |
|
5297 int key = getkeyptr(0); |
|
5298 |
|
5299 readbuf[0] = (key == 'y' ? 'y' : 'n'); |
|
5300 } else { |
|
5301 readbuf[0] = ((char)getquery(NULL, 0)) == 'y' ? 'y' : 'n'; |
|
5302 |
|
5303 /* dispose of result appropriately, etc. */ |
|
5304 if (haso) { |
|
5305 fclose(shout); /* close(SHTTY) */ |
|
5306 shout = oshout; |
|
5307 SHTTY = -1; |
|
5308 } |
|
5309 } |
|
5310 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) |
|
5311 printf("%s\n", readbuf); |
|
5312 if (!OPT_ISSET(ops,'e')) |
|
5313 setsparam(reply, ztrdup(readbuf)); |
|
5314 |
|
5315 if (resettty && SHTTY != -1) |
|
5316 settyinfo(&saveti); |
|
5317 return readbuf[0] == 'n'; |
|
5318 } |
|
5319 |
|
5320 /* All possible special types of input have been exhausted. Take one line, |
|
5321 and assign words to the parameters until they run out. Leftover words go |
|
5322 onto the last parameter. If an array is specified, all the words become |
|
5323 separate elements of the array. */ |
|
5324 |
|
5325 zbuforig = zbuf = (!OPT_ISSET(ops,'z')) ? NULL : |
|
5326 (nonempty(bufstack)) ? (char *) getlinknode(bufstack) : ztrdup(""); |
|
5327 first = 1; |
|
5328 bslash = 0; |
|
5329 while (*args || (OPT_ISSET(ops,'A') && !gotnl)) { |
|
5330 sigset_t s = child_unblock(); |
|
5331 buf = bptr = (char *)zalloc(bsiz = 64); |
|
5332 /* get input, a character at a time */ |
|
5333 while (!gotnl) { |
|
5334 c = zread(izle, &readchar); |
|
5335 /* \ at the end of a line indicates a continuation * |
|
5336 * line, except in raw mode (-r option) */ |
|
5337 if (bslash && c == delim) { |
|
5338 bslash = 0; |
|
5339 continue; |
|
5340 } |
|
5341 if (c == EOF || c == delim) |
|
5342 break; |
|
5343 /* |
|
5344 * `first' is non-zero if any separator we encounter is a |
|
5345 * non-whitespace separator, which means that anything |
|
5346 * (even an empty string) between, before or after separators |
|
5347 * is significant. If it is zero, we have a whitespace |
|
5348 * separator, which shouldn't cause extra empty strings to |
|
5349 * be emitted. Hence the test for (*buf || first) when |
|
5350 * we assign the result of reading a word. |
|
5351 */ |
|
5352 if (!bslash && isep(c)) { |
|
5353 if (bptr != buf || (!iwsep(c) && first)) { |
|
5354 first |= !iwsep(c); |
|
5355 break; |
|
5356 } |
|
5357 first |= !iwsep(c); |
|
5358 continue; |
|
5359 } |
|
5360 bslash = c == '\\' && !bslash && !OPT_ISSET(ops,'r'); |
|
5361 if (bslash) |
|
5362 continue; |
|
5363 first = 0; |
|
5364 if (imeta(c)) { |
|
5365 *bptr++ = Meta; |
|
5366 *bptr++ = c ^ 32; |
|
5367 } else |
|
5368 *bptr++ = c; |
|
5369 /* increase the buffer size, if necessary */ |
|
5370 if (bptr >= buf + bsiz - 1) { |
|
5371 int blen = bptr - buf; |
|
5372 |
|
5373 buf = realloc(buf, bsiz *= 2); |
|
5374 bptr = buf + blen; |
|
5375 } |
|
5376 } |
|
5377 signal_setmask(s); |
|
5378 if (c == delim || c == EOF) |
|
5379 gotnl = 1; |
|
5380 *bptr = '\0'; |
|
5381 /* dispose of word appropriately */ |
|
5382 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) { |
|
5383 zputs(buf, stdout); |
|
5384 putchar('\n'); |
|
5385 } |
|
5386 if (!OPT_ISSET(ops,'e') && (*buf || first)) { |
|
5387 if (OPT_ISSET(ops,'A')) { |
|
5388 addlinknode(readll, buf); |
|
5389 al++; |
|
5390 } else |
|
5391 setsparam(reply, buf); |
|
5392 } else |
|
5393 free(buf); |
|
5394 if (!OPT_ISSET(ops,'A')) |
|
5395 reply = *args++; |
|
5396 } |
|
5397 /* handle EOF */ |
|
5398 if (c == EOF) { |
|
5399 if (readfd == coprocin) { |
|
5400 close(coprocin); |
|
5401 close(coprocout); |
|
5402 coprocin = coprocout = -1; |
|
5403 } |
|
5404 } |
|
5405 /* final assignment (and display) of array parameter */ |
|
5406 if (OPT_ISSET(ops,'A')) { |
|
5407 char **pp, **p = NULL; |
|
5408 LinkNode n; |
|
5409 |
|
5410 p = (OPT_ISSET(ops,'e') ? (char **)NULL |
|
5411 : (char **)zalloc((al + 1) * sizeof(char *))); |
|
5412 |
|
5413 for (pp = p, n = firstnode(readll); n; incnode(n)) { |
|
5414 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) { |
|
5415 zputs((char *) getdata(n), stdout); |
|
5416 putchar('\n'); |
|
5417 } |
|
5418 if (p) |
|
5419 *pp++ = (char *)getdata(n); |
|
5420 else |
|
5421 zsfree(getdata(n)); |
|
5422 } |
|
5423 if (p) { |
|
5424 *pp++ = NULL; |
|
5425 setaparam(reply, p); |
|
5426 } |
|
5427 if (resettty && SHTTY != -1) |
|
5428 settyinfo(&saveti); |
|
5429 return c == EOF; |
|
5430 } |
|
5431 buf = bptr = (char *)zalloc(bsiz = 64); |
|
5432 /* any remaining part of the line goes into one parameter */ |
|
5433 bslash = 0; |
|
5434 if (!gotnl) { |
|
5435 sigset_t s = child_unblock(); |
|
5436 for (;;) { |
|
5437 c = zread(izle, &readchar); |
|
5438 /* \ at the end of a line introduces a continuation line, except in |
|
5439 raw mode (-r option) */ |
|
5440 if (bslash && c == delim) { |
|
5441 bslash = 0; |
|
5442 continue; |
|
5443 } |
|
5444 if (c == EOF || (c == delim && !zbuf)) |
|
5445 break; |
|
5446 if (!bslash && isep(c) && bptr == buf) { |
|
5447 if (iwsep(c)) |
|
5448 continue; |
|
5449 else if (!first) { |
|
5450 first = 1; |
|
5451 continue; |
|
5452 } |
|
5453 } |
|
5454 bslash = c == '\\' && !bslash && !OPT_ISSET(ops,'r'); |
|
5455 if (bslash) |
|
5456 continue; |
|
5457 if (imeta(c)) { |
|
5458 *bptr++ = Meta; |
|
5459 *bptr++ = c ^ 32; |
|
5460 } else |
|
5461 *bptr++ = c; |
|
5462 /* increase the buffer size, if necessary */ |
|
5463 if (bptr >= buf + bsiz - 1) { |
|
5464 int blen = bptr - buf; |
|
5465 |
|
5466 buf = realloc(buf, bsiz *= 2); |
|
5467 bptr = buf + blen; |
|
5468 } |
|
5469 } |
|
5470 signal_setmask(s); |
|
5471 } |
|
5472 while (bptr > buf) { |
|
5473 if (bptr > buf + 1 && bptr[-2] == Meta) { |
|
5474 if (iwsep(bptr[-1] ^ 32)) |
|
5475 bptr -= 2; |
|
5476 else |
|
5477 break; |
|
5478 } else if (iwsep(bptr[-1])) |
|
5479 bptr--; |
|
5480 else |
|
5481 break; |
|
5482 } |
|
5483 *bptr = '\0'; |
|
5484 if (resettty && SHTTY != -1) |
|
5485 settyinfo(&saveti); |
|
5486 /* final assignment of reply, etc. */ |
|
5487 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) { |
|
5488 zputs(buf, stdout); |
|
5489 putchar('\n'); |
|
5490 } |
|
5491 if (!OPT_ISSET(ops,'e')) |
|
5492 setsparam(reply, buf); |
|
5493 else |
|
5494 zsfree(buf); |
|
5495 if (zbuforig) { |
|
5496 char first = *zbuforig; |
|
5497 |
|
5498 zsfree(zbuforig); |
|
5499 if (!first) |
|
5500 return 1; |
|
5501 } else if (c == EOF) { |
|
5502 if (readfd == coprocin) { |
|
5503 close(coprocin); |
|
5504 close(coprocout); |
|
5505 coprocin = coprocout = -1; |
|
5506 } |
|
5507 return 1; |
|
5508 } |
|
5509 return 0; |
|
5510 } |
|
5511 |
|
5512 /**/ |
|
5513 static int |
|
5514 zread(int izle, int *readchar) |
|
5515 { |
|
5516 char cc, retry = 0; |
|
5517 int ret; |
|
5518 |
|
5519 if (izle) { |
|
5520 int c = getkeyptr(0); |
|
5521 |
|
5522 return (c < 0 ? EOF : c); |
|
5523 } |
|
5524 /* use zbuf if possible */ |
|
5525 if (zbuf) { |
|
5526 /* If zbuf points to anything, it points to the next character in the |
|
5527 buffer. This may be a null byte to indicate EOF. If reading from the |
|
5528 buffer, move on the buffer pointer. */ |
|
5529 if (*zbuf == Meta) |
|
5530 return zbuf++, STOUC(*zbuf++ ^ 32); |
|
5531 else |
|
5532 return (*zbuf) ? STOUC(*zbuf++) : EOF; |
|
5533 } |
|
5534 if (*readchar >= 0) { |
|
5535 cc = *readchar; |
|
5536 *readchar = -1; |
|
5537 return STOUC(cc); |
|
5538 } |
|
5539 for (;;) { |
|
5540 /* read a character from readfd */ |
|
5541 ret = read(readfd, &cc, 1); |
|
5542 switch (ret) { |
|
5543 case 1: |
|
5544 /* return the character read */ |
|
5545 return STOUC(cc); |
|
5546 case -1: |
|
5547 #if defined(EAGAIN) || defined(EWOULDBLOCK) |
|
5548 if (!retry && readfd == 0 && ( |
|
5549 # ifdef EAGAIN |
|
5550 errno == EAGAIN |
|
5551 # ifdef EWOULDBLOCK |
|
5552 || |
|
5553 # endif /* EWOULDBLOCK */ |
|
5554 # endif /* EAGAIN */ |
|
5555 # ifdef EWOULDBLOCK |
|
5556 errno == EWOULDBLOCK |
|
5557 # endif /* EWOULDBLOCK */ |
|
5558 ) && setblock_stdin()) { |
|
5559 retry = 1; |
|
5560 continue; |
|
5561 } else |
|
5562 #endif /* EAGAIN || EWOULDBLOCK */ |
|
5563 if (errno == EINTR && !(errflag || retflag || breaks || contflag)) |
|
5564 continue; |
|
5565 break; |
|
5566 } |
|
5567 return EOF; |
|
5568 } |
|
5569 } |
|
5570 |
|
5571 /* holds arguments for testlex() */ |
|
5572 /**/ |
|
5573 char **testargs; |
|
5574 |
|
5575 /* test, [: the old-style general purpose logical expression builtin */ |
|
5576 |
|
5577 /**/ |
|
5578 void |
|
5579 testlex(void) |
|
5580 { |
|
5581 if (tok == LEXERR) |
|
5582 return; |
|
5583 |
|
5584 tokstr = *testargs; |
|
5585 if (!*testargs) { |
|
5586 /* if tok is already zero, reading past the end: error */ |
|
5587 tok = tok ? NULLTOK : LEXERR; |
|
5588 return; |
|
5589 } else if (!strcmp(*testargs, "-o")) |
|
5590 tok = DBAR; |
|
5591 else if (!strcmp(*testargs, "-a")) |
|
5592 tok = DAMPER; |
|
5593 else if (!strcmp(*testargs, "!")) |
|
5594 tok = BANG; |
|
5595 else if (!strcmp(*testargs, "(")) |
|
5596 tok = INPAR; |
|
5597 else if (!strcmp(*testargs, ")")) |
|
5598 tok = OUTPAR; |
|
5599 else |
|
5600 tok = STRING; |
|
5601 testargs++; |
|
5602 } |
|
5603 |
|
5604 /**/ |
|
5605 int |
|
5606 bin_test(char *name, char **argv, UNUSED(Options ops), int func) |
|
5607 { |
|
5608 char **s; |
|
5609 Eprog prog; |
|
5610 struct estate state; |
|
5611 |
|
5612 /* if "test" was invoked as "[", it needs a matching "]" * |
|
5613 * which is subsequently ignored */ |
|
5614 if (func == BIN_BRACKET) { |
|
5615 for (s = argv; *s; s++); |
|
5616 if (s == argv || strcmp(s[-1], "]")) { |
|
5617 zwarnnam(name, "']' expected", NULL, 0); |
|
5618 return 1; |
|
5619 } |
|
5620 s[-1] = NULL; |
|
5621 } |
|
5622 /* an empty argument list evaluates to false (1) */ |
|
5623 if (!*argv) |
|
5624 return 1; |
|
5625 |
|
5626 testargs = argv; |
|
5627 tok = NULLTOK; |
|
5628 condlex = testlex; |
|
5629 testlex(); |
|
5630 prog = parse_cond(); |
|
5631 condlex = yylex; |
|
5632 |
|
5633 if (errflag) { |
|
5634 errflag = 0; |
|
5635 return 1; |
|
5636 } |
|
5637 |
|
5638 if (!prog || tok == LEXERR) { |
|
5639 zwarnnam(name, tokstr ? "parse error" : "argument expected", NULL, 0); |
|
5640 return 1; |
|
5641 } |
|
5642 |
|
5643 /* syntax is OK, so evaluate */ |
|
5644 |
|
5645 state.prog = prog; |
|
5646 state.pc = prog->prog; |
|
5647 state.strs = prog->strs; |
|
5648 |
|
5649 |
|
5650 return evalcond(&state, name); |
|
5651 } |
|
5652 |
|
5653 /* display a time, provided in units of 1/60s, as minutes and seconds */ |
|
5654 #define pttime(X) printf("%ldm%ld.%02lds",((long) (X))/3600,\ |
|
5655 ((long) (X))/60%60,((long) (X))*100/60%100) |
|
5656 |
|
5657 #ifndef __SYMBIAN32__ |
|
5658 /* times: display, in a two-line format, the times provided by times(3) */ |
|
5659 |
|
5660 /**/ |
|
5661 int |
|
5662 bin_times(UNUSED(char *name), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func)) |
|
5663 { |
|
5664 struct tms buf; |
|
5665 |
|
5666 /* get time accounting information */ |
|
5667 if (times(&buf) == -1) |
|
5668 return 1; |
|
5669 pttime(buf.tms_utime); /* user time */ |
|
5670 putchar(' '); |
|
5671 pttime(buf.tms_stime); /* system time */ |
|
5672 putchar('\n'); |
|
5673 pttime(buf.tms_cutime); /* user time, children */ |
|
5674 putchar(' '); |
|
5675 pttime(buf.tms_cstime); /* system time, children */ |
|
5676 putchar('\n'); |
|
5677 return 0; |
|
5678 } |
|
5679 |
|
5680 |
|
5681 /* trap: set/unset signal traps */ |
|
5682 |
|
5683 /**/ |
|
5684 int |
|
5685 bin_trap(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) |
|
5686 { |
|
5687 Eprog prog; |
|
5688 char *arg, *s; |
|
5689 int sig; |
|
5690 |
|
5691 if (*argv && !strcmp(*argv, "--")) |
|
5692 argv++; |
|
5693 |
|
5694 /* If given no arguments, list all currently-set traps */ |
|
5695 if (!*argv) { |
|
5696 queue_signals(); |
|
5697 for (sig = 0; sig < VSIGCOUNT; sig++) { |
|
5698 if (sigtrapped[sig] & ZSIG_FUNC) { |
|
5699 HashNode hn; |
|
5700 |
|
5701 if ((hn = gettrapnode(sig, 0))) |
|
5702 shfunctab->printnode(hn, 0); |
|
5703 DPUTS(!hn, "BUG: I did not find any trap functions!"); |
|
5704 } else if (sigtrapped[sig]) { |
|
5705 if (!sigfuncs[sig]) |
|
5706 printf("trap -- '' %s\n", sigs[sig]); |
|
5707 else { |
|
5708 s = getpermtext(sigfuncs[sig], NULL); |
|
5709 printf("trap -- "); |
|
5710 quotedzputs(s, stdout); |
|
5711 printf(" %s\n", sigs[sig]); |
|
5712 zsfree(s); |
|
5713 } |
|
5714 } |
|
5715 } |
|
5716 unqueue_signals(); |
|
5717 return 0; |
|
5718 } |
|
5719 |
|
5720 /* If we have a signal number, unset the specified * |
|
5721 * signals. With only -, remove all traps. */ |
|
5722 if ((getsignum(*argv) != -1) || (!strcmp(*argv, "-") && argv++)) { |
|
5723 if (!*argv) |
|
5724 for (sig = 0; sig < VSIGCOUNT; sig++) |
|
5725 unsettrap(sig); |
|
5726 else |
|
5727 while (*argv) |
|
5728 unsettrap(getsignum(*argv++)); |
|
5729 return 0; |
|
5730 } |
|
5731 |
|
5732 /* Sort out the command to execute on trap */ |
|
5733 arg = *argv++; |
|
5734 if (!*arg) |
|
5735 prog = &dummy_eprog; |
|
5736 else if (!(prog = parse_string(arg))) { |
|
5737 zwarnnam(name, "couldn't parse trap command", NULL, 0); |
|
5738 return 1; |
|
5739 } |
|
5740 |
|
5741 /* set traps */ |
|
5742 for (; *argv; argv++) { |
|
5743 Eprog t; |
|
5744 |
|
5745 sig = getsignum(*argv); |
|
5746 if (sig == -1) { |
|
5747 zwarnnam(name, "undefined signal: %s", *argv, 0); |
|
5748 break; |
|
5749 } |
|
5750 t = dupeprog(prog, 0); |
|
5751 if (settrap(sig, t)) |
|
5752 freeeprog(t); |
|
5753 } |
|
5754 return *argv != NULL; |
|
5755 } |
|
5756 |
|
5757 /**/ |
|
5758 int |
|
5759 bin_ttyctl(UNUSED(char *name), UNUSED(char **argv), Options ops, UNUSED(int func)) |
|
5760 { |
|
5761 if (OPT_ISSET(ops,'f')) |
|
5762 ttyfrozen = 1; |
|
5763 else if (OPT_ISSET(ops,'u')) |
|
5764 ttyfrozen = 0; |
|
5765 else |
|
5766 printf("tty is %sfrozen\n", ttyfrozen ? "" : "not "); |
|
5767 return 0; |
|
5768 } |
|
5769 #endif //__SYMBIAN32__ |
|
5770 /* let -- mathematical evaluation */ |
|
5771 |
|
5772 /**/ |
|
5773 int |
|
5774 bin_let(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int func)) |
|
5775 { |
|
5776 mnumber val = zero_mnumber; |
|
5777 |
|
5778 while (*argv) |
|
5779 val = matheval(*argv++); |
|
5780 /* Errors in math evaluation in let are non-fatal. */ |
|
5781 errflag = 0; |
|
5782 /* should test for fabs(val.u.d) < epsilon? */ |
|
5783 return (val.type == MN_INTEGER) ? val.u.l == 0 : val.u.d == 0.0; |
|
5784 } |
|
5785 #ifndef __SYMBIAN32__ |
|
5786 /* umask command. umask may be specified as octal digits, or in the * |
|
5787 * symbolic form that chmod(1) uses. Well, a subset of it. Remember * |
|
5788 * that only the bottom nine bits of umask are used, so there's no * |
|
5789 * point allowing the set{u,g}id and sticky bits to be specified. */ |
|
5790 |
|
5791 /**/ |
|
5792 int |
|
5793 bin_umask(char *nam, char **args, Options ops, UNUSED(int func)) |
|
5794 { |
|
5795 mode_t um; |
|
5796 char *s = *args; |
|
5797 |
|
5798 /* Get the current umask. */ |
|
5799 um = umask(0); |
|
5800 umask(um); |
|
5801 /* No arguments means to display the current setting. */ |
|
5802 if (!s) { |
|
5803 if (OPT_ISSET(ops,'S')) { |
|
5804 char *who = "ugo"; |
|
5805 |
|
5806 while (*who) { |
|
5807 char *what = "rwx"; |
|
5808 printf("%c=", *who++); |
|
5809 while (*what) { |
|
5810 if (!(um & 0400)) |
|
5811 putchar(*what); |
|
5812 um <<= 1; |
|
5813 what++; |
|
5814 } |
|
5815 putchar(*who ? ',' : '\n'); |
|
5816 } |
|
5817 } else { |
|
5818 if (um & 0700) |
|
5819 putchar('0'); |
|
5820 printf("%03o\n", (unsigned)um); |
|
5821 } |
|
5822 return 0; |
|
5823 } |
|
5824 |
|
5825 if (idigit(*s)) { |
|
5826 /* Simple digital umask. */ |
|
5827 um = zstrtol(s, &s, 8); |
|
5828 if (*s) { |
|
5829 zwarnnam(nam, "bad umask", NULL, 0); |
|
5830 return 1; |
|
5831 } |
|
5832 } else { |
|
5833 /* Symbolic notation -- slightly complicated. */ |
|
5834 int whomask, umaskop, mask; |
|
5835 |
|
5836 /* More than one symbolic argument may be used at once, each separated |
|
5837 by commas. */ |
|
5838 for (;;) { |
|
5839 /* First part of the argument -- who does this apply to? |
|
5840 u=owner, g=group, o=other. */ |
|
5841 whomask = 0; |
|
5842 while (*s == 'u' || *s == 'g' || *s == 'o' || *s == 'a') |
|
5843 if (*s == 'u') |
|
5844 s++, whomask |= 0700; |
|
5845 else if (*s == 'g') |
|
5846 s++, whomask |= 0070; |
|
5847 else if (*s == 'o') |
|
5848 s++, whomask |= 0007; |
|
5849 else if (*s == 'a') |
|
5850 s++, whomask |= 0777; |
|
5851 /* Default whomask is everyone. */ |
|
5852 if (!whomask) |
|
5853 whomask = 0777; |
|
5854 /* Operation may be +, - or =. */ |
|
5855 umaskop = (int)*s; |
|
5856 if (!(umaskop == '+' || umaskop == '-' || umaskop == '=')) { |
|
5857 if (umaskop) |
|
5858 zwarnnam(nam, "bad symbolic mode operator: %c", NULL, umaskop); |
|
5859 else |
|
5860 zwarnnam(nam, "bad umask", NULL, 0); |
|
5861 return 1; |
|
5862 } |
|
5863 /* Permissions mask -- r=read, w=write, x=execute. */ |
|
5864 mask = 0; |
|
5865 while (*++s && *s != ',') |
|
5866 if (*s == 'r') |
|
5867 mask |= 0444 & whomask; |
|
5868 else if (*s == 'w') |
|
5869 mask |= 0222 & whomask; |
|
5870 else if (*s == 'x') |
|
5871 mask |= 0111 & whomask; |
|
5872 else { |
|
5873 zwarnnam(nam, "bad symbolic mode permission: %c", |
|
5874 NULL, *s); |
|
5875 return 1; |
|
5876 } |
|
5877 /* Apply parsed argument to um. */ |
|
5878 if (umaskop == '+') |
|
5879 um &= ~mask; |
|
5880 else if (umaskop == '-') |
|
5881 um |= mask; |
|
5882 else /* umaskop == '=' */ |
|
5883 um = (um | (whomask)) & ~mask; |
|
5884 if (*s == ',') |
|
5885 s++; |
|
5886 else |
|
5887 break; |
|
5888 } |
|
5889 if (*s) { |
|
5890 zwarnnam(nam, "bad character in symbolic mode: %c", NULL, *s); |
|
5891 return 1; |
|
5892 } |
|
5893 } |
|
5894 |
|
5895 /* Finally, set the new umask. */ |
|
5896 umask(um); |
|
5897 return 0; |
|
5898 } |
|
5899 |
|
5900 #endif//__SYMBIAN32__ |
|
5901 |
|
5902 #ifdef __SYMBIAN32__ |
|
5903 |
|
5904 extern ls_internal(int, char**); |
|
5905 extern cp_internal(int, char**); |
|
5906 extern cat_internal(int, char**); |
|
5907 extern touch_internal(int, char**); |
|
5908 |
|
5909 //generate the arguments to be passed to the _internal of |
|
5910 //all the ported external commands |
|
5911 char** make_arg(char* cmd, char* opts, char** argv, int argc) |
|
5912 { |
|
5913 if(!cmd) |
|
5914 return NULL; |
|
5915 else |
|
5916 { |
|
5917 int opts_exist=0; |
|
5918 char** made_arg=NULL; |
|
5919 if(opts && *opts) |
|
5920 opts_exist=1; |
|
5921 |
|
5922 made_arg=(char**) calloc(argc+opts_exist+2, sizeof(char*)); |
|
5923 if(made_arg!=NULL) |
|
5924 { |
|
5925 int index=0; |
|
5926 made_arg[index]=calloc(strlen(cmd)+1, sizeof(char)); |
|
5927 if(made_arg[index]) |
|
5928 { |
|
5929 int index_args=0; |
|
5930 strcpy(made_arg[index], cmd); |
|
5931 |
|
5932 if(opts_exist) |
|
5933 { |
|
5934 made_arg[++index]=calloc(strlen(opts)+1, sizeof(char)); |
|
5935 if(made_arg[index]) |
|
5936 { |
|
5937 strcpy(made_arg[index], opts); |
|
5938 } |
|
5939 else |
|
5940 { |
|
5941 free(made_arg[index-1]); |
|
5942 free(made_arg); |
|
5943 return NULL; |
|
5944 } |
|
5945 } |
|
5946 |
|
5947 while(index_args<argc) |
|
5948 { |
|
5949 made_arg[++index]=calloc(strlen(argv[index-opts_exist])+1, sizeof(char)); |
|
5950 if(made_arg[index]) |
|
5951 { |
|
5952 strcpy(made_arg[index],argv[index-opts_exist-1]); |
|
5953 } |
|
5954 else |
|
5955 { |
|
5956 while(index_args>0) |
|
5957 { |
|
5958 free(made_arg[index_args-1]); |
|
5959 index_args--; |
|
5960 } |
|
5961 if(opts_exist) |
|
5962 { |
|
5963 free(made_arg[1]); //opts will be at 1; |
|
5964 } |
|
5965 free(made_arg); |
|
5966 return NULL; |
|
5967 } |
|
5968 index_args++; |
|
5969 } |
|
5970 } |
|
5971 else |
|
5972 { |
|
5973 free(made_arg); |
|
5974 return NULL; |
|
5975 } |
|
5976 made_arg[++index]=NULL; //terminate the array |
|
5977 } |
|
5978 return made_arg; |
|
5979 } |
|
5980 } |
|
5981 |
|
5982 //clear the argument list... |
|
5983 void clear_arg(char** argv, int arg_cnt) |
|
5984 { |
|
5985 int cur_idx=arg_cnt-1; |
|
5986 if(arg_cnt<=0 || argv==NULL) |
|
5987 return; |
|
5988 |
|
5989 while(cur_idx>=0) |
|
5990 { |
|
5991 free(argv[cur_idx]); |
|
5992 cur_idx--; |
|
5993 } |
|
5994 |
|
5995 free(argv); |
|
5996 return; |
|
5997 } |
|
5998 |
|
5999 int |
|
6000 bin_ls(char *name, char **argv, Options ops, UNUSED(int func)) |
|
6001 { |
|
6002 char** bck_up=argv; |
|
6003 int count=1; //hold the argument count... |
|
6004 int cur_idx=0; // consider - (hyphen) |
|
6005 char arg_buf[8+1]; |
|
6006 int err=-1; |
|
6007 |
|
6008 arg_buf[cur_idx]='-'; |
|
6009 cur_idx++; |
|
6010 |
|
6011 if(OPT_ISSET(ops,'1')) |
|
6012 { |
|
6013 arg_buf[cur_idx]='1'; |
|
6014 cur_idx++; |
|
6015 } |
|
6016 if(OPT_ISSET(ops,'A')) |
|
6017 { |
|
6018 arg_buf[cur_idx]='A'; |
|
6019 cur_idx++; |
|
6020 } |
|
6021 if(OPT_ISSET(ops,'C')) |
|
6022 { |
|
6023 arg_buf[cur_idx]='C'; |
|
6024 cur_idx++; |
|
6025 } |
|
6026 if(OPT_ISSET(ops,'F')) |
|
6027 { |
|
6028 arg_buf[cur_idx]='F'; |
|
6029 cur_idx++; |
|
6030 } |
|
6031 if(OPT_ISSET(ops,'L')) |
|
6032 { |
|
6033 arg_buf[cur_idx]='L'; |
|
6034 cur_idx++; |
|
6035 } |
|
6036 if(OPT_ISSET(ops,'R')) |
|
6037 { |
|
6038 arg_buf[cur_idx]='R'; |
|
6039 cur_idx++; |
|
6040 } |
|
6041 if(OPT_ISSET(ops,'S')) |
|
6042 { |
|
6043 arg_buf[cur_idx]='S'; |
|
6044 cur_idx++; |
|
6045 } |
|
6046 if(OPT_ISSET(ops,'T')) |
|
6047 { |
|
6048 arg_buf[cur_idx]='T'; |
|
6049 cur_idx++; |
|
6050 } |
|
6051 if(OPT_ISSET(ops,'W')) |
|
6052 { |
|
6053 arg_buf[cur_idx]='W'; |
|
6054 cur_idx++; |
|
6055 } |
|
6056 if(OPT_ISSET(ops,'a')) |
|
6057 { |
|
6058 arg_buf[cur_idx]='a'; |
|
6059 cur_idx++; |
|
6060 } |
|
6061 if(OPT_ISSET(ops,'c')) |
|
6062 { |
|
6063 arg_buf[cur_idx]='c'; |
|
6064 cur_idx++; |
|
6065 } |
|
6066 if(OPT_ISSET(ops,'d')) |
|
6067 { |
|
6068 arg_buf[cur_idx]='d'; |
|
6069 cur_idx++; |
|
6070 } |
|
6071 if(OPT_ISSET(ops,'f')) |
|
6072 { |
|
6073 arg_buf[cur_idx]='f'; |
|
6074 cur_idx++; |
|
6075 } |
|
6076 if(OPT_ISSET(ops,'g')) |
|
6077 { |
|
6078 arg_buf[cur_idx]='g'; |
|
6079 cur_idx++; |
|
6080 } |
|
6081 if(OPT_ISSET(ops,'i')) |
|
6082 { |
|
6083 arg_buf[cur_idx]='i'; |
|
6084 cur_idx++; |
|
6085 } |
|
6086 if(OPT_ISSET(ops,'k')) |
|
6087 { |
|
6088 arg_buf[cur_idx]='k'; |
|
6089 cur_idx++; |
|
6090 } |
|
6091 if(OPT_ISSET(ops,'l')) |
|
6092 { |
|
6093 arg_buf[cur_idx]='l'; |
|
6094 cur_idx++; |
|
6095 } |
|
6096 if(OPT_ISSET(ops,'m')) |
|
6097 { |
|
6098 arg_buf[cur_idx]='m'; |
|
6099 cur_idx++; |
|
6100 } |
|
6101 if(OPT_ISSET(ops,'n')) |
|
6102 { |
|
6103 arg_buf[cur_idx]='n'; |
|
6104 cur_idx++; |
|
6105 } |
|
6106 if(OPT_ISSET(ops,'o')) |
|
6107 { |
|
6108 arg_buf[cur_idx]='o'; |
|
6109 cur_idx++; |
|
6110 } |
|
6111 if(OPT_ISSET(ops,'p')) |
|
6112 { |
|
6113 arg_buf[cur_idx]='p'; |
|
6114 cur_idx++; |
|
6115 } |
|
6116 if(OPT_ISSET(ops,'q')) |
|
6117 { |
|
6118 arg_buf[cur_idx]='q'; |
|
6119 cur_idx++; |
|
6120 } |
|
6121 if(OPT_ISSET(ops,'r')) |
|
6122 { |
|
6123 arg_buf[cur_idx]='r'; |
|
6124 cur_idx++; |
|
6125 } |
|
6126 if(OPT_ISSET(ops,'s')) |
|
6127 { |
|
6128 arg_buf[cur_idx]='s'; |
|
6129 cur_idx++; |
|
6130 } |
|
6131 if(OPT_ISSET(ops,'t')) |
|
6132 { |
|
6133 arg_buf[cur_idx]='t'; |
|
6134 cur_idx++; |
|
6135 } |
|
6136 if(OPT_ISSET(ops,'u')) |
|
6137 { |
|
6138 arg_buf[cur_idx]='u'; |
|
6139 cur_idx++; |
|
6140 } |
|
6141 if(OPT_ISSET(ops,'x')) |
|
6142 { |
|
6143 arg_buf[cur_idx]='x'; |
|
6144 cur_idx++; |
|
6145 } |
|
6146 |
|
6147 if(cur_idx>1) //consider hyphen |
|
6148 { |
|
6149 arg_buf[cur_idx]='\0'; |
|
6150 count++; |
|
6151 } |
|
6152 else |
|
6153 { |
|
6154 arg_buf[0]='\0'; |
|
6155 cur_idx--; |
|
6156 } |
|
6157 |
|
6158 while(argv && *argv) |
|
6159 { |
|
6160 count++; |
|
6161 argv++; |
|
6162 } |
|
6163 |
|
6164 bck_up=make_arg("ls", &arg_buf[0], bck_up, (cur_idx>0?count-2:count-1)); |
|
6165 if(bck_up) |
|
6166 { |
|
6167 err=ls_internal(count, bck_up); |
|
6168 clear_arg(bck_up, count); |
|
6169 } |
|
6170 return err; |
|
6171 |
|
6172 } |
|
6173 |
|
6174 int |
|
6175 bin_cat(char *name, char **argv, Options ops, UNUSED(int func)) |
|
6176 { |
|
6177 char** bck_up=argv; |
|
6178 int count=1; //hold the argument count... |
|
6179 int cur_idx=0; // consider - (hyphen) |
|
6180 char arg_buf[8+1]; |
|
6181 int err=-1; |
|
6182 |
|
6183 arg_buf[cur_idx]='-'; |
|
6184 cur_idx++; |
|
6185 |
|
6186 if(OPT_ISSET(ops,'b')) |
|
6187 { |
|
6188 arg_buf[cur_idx]='b'; |
|
6189 cur_idx++; |
|
6190 } |
|
6191 if(OPT_ISSET(ops,'e')) |
|
6192 { |
|
6193 arg_buf[cur_idx]='e'; |
|
6194 cur_idx++; |
|
6195 } |
|
6196 if(OPT_ISSET(ops,'n')) |
|
6197 { |
|
6198 arg_buf[cur_idx]='n'; |
|
6199 cur_idx++; |
|
6200 } |
|
6201 if(OPT_ISSET(ops,'s')) |
|
6202 { |
|
6203 arg_buf[cur_idx]='s'; |
|
6204 cur_idx++; |
|
6205 } |
|
6206 if(OPT_ISSET(ops,'t')) |
|
6207 { |
|
6208 arg_buf[cur_idx]='t'; |
|
6209 cur_idx++; |
|
6210 } |
|
6211 if(OPT_ISSET(ops,'u')) |
|
6212 { |
|
6213 arg_buf[cur_idx]='u'; |
|
6214 cur_idx++; |
|
6215 } |
|
6216 if(OPT_ISSET(ops,'v')) |
|
6217 { |
|
6218 arg_buf[cur_idx]='v'; |
|
6219 cur_idx++; |
|
6220 } |
|
6221 |
|
6222 if(cur_idx>1) //consider hyphen |
|
6223 { |
|
6224 arg_buf[cur_idx]='\0'; |
|
6225 count++; |
|
6226 } |
|
6227 else |
|
6228 { |
|
6229 arg_buf[0]='\0'; |
|
6230 cur_idx--; |
|
6231 } |
|
6232 |
|
6233 while(argv && *argv) |
|
6234 { |
|
6235 count++; |
|
6236 argv++; |
|
6237 } |
|
6238 |
|
6239 bck_up=make_arg("ls", &arg_buf[0], bck_up, (cur_idx>0?count-2:count-1)); |
|
6240 if(bck_up) |
|
6241 { |
|
6242 err=cat_internal(count, bck_up); |
|
6243 clear_arg(bck_up, count); |
|
6244 } |
|
6245 |
|
6246 return err; |
|
6247 } |
|
6248 |
|
6249 int |
|
6250 bin_cp(char *name, char **argv, Options ops, UNUSED(int func)) |
|
6251 { |
|
6252 char** bck_up=argv; |
|
6253 int count=1; //hold the argument count... |
|
6254 int cur_idx=0; // consider - (hyphen) |
|
6255 char arg_buf[9+1]; |
|
6256 int err=-1; |
|
6257 |
|
6258 arg_buf[cur_idx]='-'; |
|
6259 cur_idx++; |
|
6260 |
|
6261 if(OPT_ISSET(ops,'H')) |
|
6262 { |
|
6263 arg_buf[cur_idx]='H'; |
|
6264 cur_idx++; |
|
6265 } |
|
6266 if(OPT_ISSET(ops,'L')) |
|
6267 { |
|
6268 arg_buf[cur_idx]='L'; |
|
6269 cur_idx++; |
|
6270 } |
|
6271 if(OPT_ISSET(ops,'P')) |
|
6272 { |
|
6273 arg_buf[cur_idx]='P'; |
|
6274 cur_idx++; |
|
6275 } |
|
6276 if(OPT_ISSET(ops,'R')) |
|
6277 { |
|
6278 arg_buf[cur_idx]='R'; |
|
6279 cur_idx++; |
|
6280 } |
|
6281 if(OPT_ISSET(ops,'f')) |
|
6282 { |
|
6283 arg_buf[cur_idx]='f'; |
|
6284 cur_idx++; |
|
6285 } |
|
6286 if(OPT_ISSET(ops,'i')) |
|
6287 { |
|
6288 arg_buf[cur_idx]='i'; |
|
6289 cur_idx++; |
|
6290 } |
|
6291 if(OPT_ISSET(ops,'p')) |
|
6292 { |
|
6293 arg_buf[cur_idx]='p'; |
|
6294 cur_idx++; |
|
6295 } |
|
6296 if(OPT_ISSET(ops,'r')) |
|
6297 { |
|
6298 arg_buf[cur_idx]='r'; |
|
6299 cur_idx++; |
|
6300 } |
|
6301 |
|
6302 if(cur_idx>1) //consider hyphen |
|
6303 { |
|
6304 arg_buf[cur_idx]='\0'; |
|
6305 count++; |
|
6306 } |
|
6307 else |
|
6308 { |
|
6309 arg_buf[0]='\0'; |
|
6310 cur_idx--; |
|
6311 } |
|
6312 |
|
6313 while(argv && *argv) |
|
6314 { |
|
6315 count++; |
|
6316 argv++; |
|
6317 } |
|
6318 |
|
6319 bck_up=make_arg("ls", &arg_buf[0], bck_up, (cur_idx>0?count-2:count-1)); |
|
6320 if(bck_up) |
|
6321 { |
|
6322 err=cp_internal(count, bck_up); |
|
6323 clear_arg(bck_up, count); |
|
6324 } |
|
6325 |
|
6326 return err; |
|
6327 } |
|
6328 |
|
6329 int |
|
6330 bin_touch(char *name, char **argv, Options ops, UNUSED(int func)) |
|
6331 { |
|
6332 char** bck_up=argv; |
|
6333 int count=1; //hold the argument count... |
|
6334 int cur_idx=0; // consider - (hyphen) |
|
6335 char arg_buf[7+1]; |
|
6336 int err=-1; |
|
6337 |
|
6338 arg_buf[cur_idx]='-'; |
|
6339 cur_idx++; |
|
6340 |
|
6341 if(OPT_ISSET(ops,'a')) |
|
6342 { |
|
6343 arg_buf[cur_idx]='a'; |
|
6344 cur_idx++; |
|
6345 } |
|
6346 if(OPT_ISSET(ops,'c')) |
|
6347 { |
|
6348 arg_buf[cur_idx]='c'; |
|
6349 cur_idx++; |
|
6350 } |
|
6351 if(OPT_ISSET(ops,'f')) |
|
6352 { |
|
6353 arg_buf[cur_idx]='f'; |
|
6354 cur_idx++; |
|
6355 } |
|
6356 if(OPT_ISSET(ops,'m')) |
|
6357 { |
|
6358 arg_buf[cur_idx]='m'; |
|
6359 cur_idx++; |
|
6360 } |
|
6361 if(OPT_ISSET(ops,'r')) |
|
6362 { |
|
6363 arg_buf[cur_idx]='r'; |
|
6364 cur_idx++; |
|
6365 } |
|
6366 if(OPT_ISSET(ops,'t')) |
|
6367 { |
|
6368 arg_buf[cur_idx]='t'; |
|
6369 cur_idx++; |
|
6370 } |
|
6371 |
|
6372 if(cur_idx>1) //consider hyphen |
|
6373 { |
|
6374 arg_buf[cur_idx]='\0'; |
|
6375 count++; |
|
6376 } |
|
6377 else |
|
6378 { |
|
6379 arg_buf[0]='\0'; |
|
6380 cur_idx--; |
|
6381 } |
|
6382 |
|
6383 while(argv && *argv) |
|
6384 { |
|
6385 count++; |
|
6386 argv++; |
|
6387 } |
|
6388 |
|
6389 bck_up=make_arg("ls", &arg_buf[0], bck_up, (cur_idx>0?count-2:count-1)); |
|
6390 if(bck_up) |
|
6391 { |
|
6392 err=touch_internal(count, bck_up); |
|
6393 clear_arg(bck_up, count); |
|
6394 } |
|
6395 |
|
6396 return err; |
|
6397 } |
|
6398 |
|
6399 int |
|
6400 bin_more(char *name, char **argv, Options ops, UNUSED(int func)) |
|
6401 { |
|
6402 char data[512]; |
|
6403 int read_cnt; |
|
6404 |
|
6405 if(pipeUsed==0) |
|
6406 { |
|
6407 printf("more: Usage: Supported with pipes only\n"); |
|
6408 return 1; |
|
6409 } |
|
6410 if(argv && *argv) |
|
6411 { |
|
6412 printf("more: No options are supported\n"); |
|
6413 return 1; |
|
6414 } |
|
6415 for(;;) |
|
6416 { |
|
6417 memset(&data[0], 0, 512); |
|
6418 read_cnt=read(0, &data[0], 512); |
|
6419 |
|
6420 /* Comparing with -1 in case of any error other than KErrNotReady */ |
|
6421 if((read_cnt==-1) || (read_cnt==0)) |
|
6422 break; |
|
6423 |
|
6424 write(1, &data[0], read_cnt); |
|
6425 fflush(stdout); |
|
6426 } |
|
6427 |
|
6428 |
|
6429 return 0; |
|
6430 } |
|
6431 |
|
6432 #endif //__SYMBIAN32__ |
|
6433 |
|
6434 /* Generic builtin for facilities not available on this OS */ |
|
6435 |
|
6436 /**/ |
|
6437 mod_export int |
|
6438 bin_notavail(char *nam, UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func)) |
|
6439 { |
|
6440 zwarnnam(nam, "not available on this system", NULL, 0); |
|
6441 return 1; |
|
6442 } |