openenvutils/commandshell/shell/src/builtin.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     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 }