int path_absolute(const char* path, stralloc* sa) { int ret = 0; stralloc_zero(sa); if(!path_isabs(path)) { path_getcwd(sa); stralloc_catc(sa, PATHSEP_C); stralloc_cats(sa, path); return 1; } stralloc_copys(sa, path); return 0; }
int parse_subst(struct parser *p) { char c; if(source_next(&c) <= 0) return -1; if(c == '(') { return parse_bquoted(p); } else if(parse_isparam(c) || c == '{') { return parse_param(p); } stralloc_catc(&p->sa, '$'); return 0; }
/* set a variable value * ----------------------------------------------------------------------- */ const char *var_setvint(const char *v, int i, int flags) { struct var *var; var = var_create(v, flags); var->flags |= flags; if(var->sa.a == 0) var->sa.s = NULL; stralloc_copyb(&var->sa, v, var->len); stralloc_catc(&var->sa, '='); stralloc_catlong(&var->sa, i); stralloc_nul(&var->sa); var->offset = var->len + 1; return var->sa.s; }
int list_dir_internal(stralloc* dir, char type) { size_t l; struct dir_s d; stralloc pre; int dtype; int is_dir, is_symlink; size_t len; #if !WINDOWS_NATIVE struct stat st; static dev_t root_dev; #endif char *name, *s; (void)type; while(dir->len > 1 && IS_DIRSEP(dir->s[dir->len - 1])) dir->len--; stralloc_nul(dir); #if !WINDOWS_NATIVE if(root_dev == 0) { if(stat(dir->s, &st) != -1) { root_dev = st.st_dev; } } #endif if(dir_open(&d, dir->s) != 0) { buffer_puts(buffer_2, "ERROR: Opening directory "); buffer_putsa(buffer_2, dir); buffer_puts(buffer_2, " failed!\n"); buffer_flush(buffer_2); goto end; } if(dir->s[dir->len - 1] != DIRSEP_C) stralloc_cats(dir, DIRSEP_S); l = dir->len; while((name = dir_read(&d))) { unsigned int mode = 0, nlink = 0, uid = 0, gid = 0; uint64 size = 0, mtime = 0; dtype = dir_type(&d); dir->len = l; if(str_equal(name, "") || str_equal(name, ".") || str_equal(name, "..")) { continue; } stralloc_readyplus(dir, str_len(name) + 1); str_copy(dir->s + dir->len, name); dir->len += str_len(name); is_symlink = !!(dtype & D_SYMLINK); #if !WINDOWS_NATIVE if(!opt_deref && lstat(dir->s, &st) != -1) { if(root_dev && st.st_dev) { if(st.st_dev != root_dev) { continue; } } } #endif #if !WINDOWS_NATIVE if(S_ISLNK(st.st_mode)) { stat(dir->s, &st); } mode = st.st_mode; #endif if(dtype) { is_dir = !!(dtype & D_DIRECTORY); } else { #if WINDOWS_NATIVE is_dir = 0; #else is_dir = !!S_ISDIR(mode); #endif } if(dtype & D_SYMLINK) is_symlink = 1; #if !WINDOWS_NATIVE nlink = st.st_nlink; uid = st.st_uid; gid = st.st_gid; size = st.st_size; mtime = st.st_mtime; #else mode = (is_dir ? 0040000 : 0100000) | (is_symlink ? 0120000 : 0); #if USE_READDIR if(!is_dir) { size = dir_size(&d); /* dir_INTERNAL(&d)->dir_entry->d_name); */ mtime = dir_time(&d); } else { mtime = 0; size = 0; } #else size = dir_size(&d); mtime = dir_time(&d, D_TIME_MODIFICATION); #endif #endif if(opt_list && size >= opt_minsize) { stralloc_init(&pre); /* Mode string */ mode_str(&pre, mode); stralloc_catb(&pre, " ", 1); /* num links */ make_num(&pre, nlink, 3); stralloc_catb(&pre, " ", 1); /* uid */ make_num(&pre, uid, 0); stralloc_catb(&pre, " ", 1); /* gid */ make_num(&pre, gid, 0); stralloc_catb(&pre, " ", 1); /* size */ make_num(&pre, size, 6); stralloc_catb(&pre, " ", 1); /* time */ make_num(&pre, mtime, 0); /* make_time(&pre, mtime, 10); */ stralloc_catb(&pre, " ", 1); } /* fprintf(stderr, "%d %08x\n", is_dir, dir_ATTRS(&d)); */ if(is_dir) stralloc_catc(dir, opt_separator); if(dir->len > MAX_PATH) { buffer_puts(buffer_2, "ERROR: Directory "); buffer_putsa(buffer_2, dir); buffer_puts(buffer_2, " longer than MAX_PATH (" STRINGIFY(MAX_PATH) ")!\n"); /*buffer_putulong(buffer_2, MAX_PATH); buffer_puts(buffer_2, ")!\n");*/ buffer_flush(buffer_2); goto end; } s = dir->s; len = dir->len; if(len >= 2 && s[0] == '.' && IS_DIRSEP(s[1])) { len -= 2; s += 2; } if(opt_list && size >= opt_minsize) buffer_putsa(buffer_1, &pre); if(opt_relative_to) { size_t sz = str_len(opt_relative_to); if(str_diffn(s, opt_relative_to, sz) == 0) { s += sz; len -= sz; while(*s == '\\' || *s == '/') { s++; len--; } } } if(size >= opt_minsize) { buffer_put(buffer_1, s, len); buffer_put(buffer_1, "\n", 1); buffer_flush(buffer_1); } if(is_dir && (opt_deref || !is_symlink)) { dir->len--; list_dir_internal(dir, 0); } } end: dir_close(&d); return 0; }
union node* expand_param(struct nargparam* param, union node** nptr, struct vartab* varstack, char* argv[], int exitcode, int flags) { union node* n = *nptr; stralloc value; char* str = NULL; const char *v = NULL; unsigned long argc, vlen = 0; for(argc = 0; argv[argc]; ++argc) ; stralloc_init(&value); /* treat special arguments */ if(param->flag & S_SPECIAL) { switch(param->flag & S_SPECIAL) { /* $# substitution */ case S_ARGC: { stralloc_catulong0(&value, argc, 0); break; } /* $* substitution */ case S_ARGV: { char** s; for(s = argv; *s;) { stralloc_cats(&n->narg.stra, *s); if(*++s) stralloc_catc(&n->narg.stra, ' '); } break; } /* $@ substitution */ case S_ARGVS: { unsigned int i = 0; while(i < argc) { param->flag &= ~S_SPECIAL; param->flag |= S_ARG; param->numb = 1 + i; n = expand_param(param, nptr, varstack, argv, exitcode,flags); if(++i < argc) nptr = &n->list.next; } return n; } /* $? substitution */ case S_EXITCODE: { stralloc_catulong0(&value, exitcode, 0); break; } /* $- substitution */ case S_FLAGS: break; /* $! substitution */ case S_BGEXCODE: break; /* $[0-9] arg subst */ case S_ARG: { if(param->numb == 0) { /* stralloc_cats(&value, sh_argv0); */ } else if(param->numb - 1 < argc) { stralloc_cats(&value, argv[param->numb - 1]); } break; } /* $$ arg subst */ case S_PID: { stralloc_catulong0(&value, getpid(), 0); break; } } /* special parameters are always set */ if(value.len) { stralloc_nul(&value); v = value.s; } vlen = value.len; } /* ..and variable substitutions */ else { size_t offset; /* look for the variable. if the S_NULL flag is set and we have a var which is null set v to NULL */ if((v = var_get(varstack, param->name, &offset))) { if(v[offset] == '\0' && (param->flag & S_NULL)) { v = NULL; vlen = 0; } else { v = &v[offset]; vlen = str_len(v); } } } /* check for S_STRLEN substitution */ if(param->flag & S_STRLEN) { char lstr[FMT_ULONG]; n = expand_cat(lstr, fmt_ulong(lstr, vlen), nptr, varstack, flags); stralloc_free(&value); return n; } str = str_ndup(v, vlen); /* otherwise expand the apropriate variable/word subst */ switch(param->flag & S_VAR) { /* return word if parameter unset (or null) */ case S_DEFAULT: { if(v) n = expand_cat(v, vlen, nptr, varstack, flags); /* unset, substitute */ else n = expand_arg(¶m->word->narg, nptr, varstack, argv, exitcode, flags); break; } /* if parameter unset (or null) then expand word to it and substitute paramter */ case S_ASGNDEF: { if(v) n = expand_cat(v, vlen, nptr, varstack, flags); else { n = expand_arg(¶m->word->narg, nptr, varstack, argv, exitcode, flags | X_NOSPLIT); var_setvsa(param->name, /* BUG */ &n->narg.stra, V_DEFAULT); } break; } /* indicate error if null or unset */ case S_ERRNULL: { if(v) n = expand_cat(v, vlen, nptr, varstack, flags); else { union node* tmpnode = NULL; n = expand_arg(¶m->word->narg, &tmpnode, varstack, argv, exitcode, flags); errmsg_warn((n && n->narg.stra.s) ? n->narg.stra.s : "parameter null or not set", 0); if(tmpnode) tree_free(tmpnode); } break; } /* if parameter unset (or null) then substitute null, otherwise substitute word */ case S_ALTERNAT: { if(v) n = expand_arg(¶m->word->narg, nptr, varstack, argv, exitcode, flags); break; /* remove smallest matching suffix */ case S_RSSFX: { int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = vlen - 1; i >= 0; i--) if(fnmatch(sa.s, str + i, FNM_PERIOD) == 0) break; n = expand_cat(v, (i < 0 ? vlen : i), nptr, varstack, flags); } break; } } /* remove largest matching suffix */ case S_RLSFX: { unsigned int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = 0; i <= vlen; i++) if(fnmatch(sa.s, str + i, FNM_PERIOD) == 0) break; n = expand_cat(v, (i > vlen ? vlen : i), nptr, varstack, flags); } break; } /* remove smallest matching prefix */ case S_RSPFX: { unsigned int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = 1; i <= vlen; i++) { str_copyn(str, v, i); if(fnmatch(sa.s, (char*)v, FNM_PERIOD) == 0) break; } if(i > vlen) i = 0; n = expand_cat(v + i, vlen - i, nptr, varstack, flags); str_copy(str, v); } break; } /* remove largest matching prefix */ case S_RLPFX: { unsigned int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = vlen; i > 0; i--) { str_copyn(str, v, i); if(fnmatch(sa.s, (char*)v, FNM_PERIOD) == 0) break; } if(i == 0) i = vlen; n = expand_cat(v + i, vlen - i, nptr, varstack, flags); str_copy(str, v); } break; } } free(str); stralloc_free(&value); return n; }
/* main loop, parse lines into trees and execute them * ----------------------------------------------------------------------- */ void sh_loop(void) { struct parser p; union node *list; stralloc cmd; /* if we're in interactive mode some additional stuff is to be initialized */ if(source->mode & SOURCE_IACTIVE) history_load(); stralloc_init(&cmd); parse_init(&p, P_DEFAULT); while(!(parse_gettok(&p, P_DEFAULT) & T_EOF)) { p.pushback++; parse_lineno = source->line; var_setvint("LINENO", parse_lineno, V_DEFAULT); /* launch the parser to get a complete command */ if((list = parse_list(&p))) { struct eval e; if(source->mode & SOURCE_IACTIVE) { tree_printlist(list, &cmd, NULL); stralloc_catc(&cmd, '\n'); stralloc_nul(&cmd); history_set(cmd.s); cmd.s = NULL; history_advance(); } #ifdef DEBUG /* debug_list(list, 0); buffer_putnlflush(fd_err->w);*/ #endif /* DEBUG */ eval_push(&e, E_JCTL); eval_tree(&e, list, E_ROOT|E_LIST); sh->exitcode = eval_pop(&e); stralloc_zero(&cmd); tree_free(list); } else if(!(p.tok & (T_NL | T_SEMI | T_BGND))) { /* we have a parse error */ if(p.tok != T_EOF) parse_error(&p, 0); /* exit if not interactive */ if(!(source->mode & SOURCE_IACTIVE)) sh_exit(1); /* ..otherwise discard the input buffer */ source_flush(); p.pushback = 0; } if(p.tok & (T_NL|T_SEMI|T_BGND)) p.pushback = 0; /* reset prompt */ prompt_number = 0; } }