From d88866ccf74d2a0686e42bb24c462a022697256f Mon Sep 17 00:00:00 2001 From: slama Date: Sat, 24 Mar 2018 17:34:58 +0900 Subject: [PATCH] deleted no longer necessary codes due to removing process expansion. --- src/expand.cpp | 390 +------------------------------------------------ 1 file changed, 1 insertion(+), 389 deletions(-) diff --git a/src/expand.cpp b/src/expand.cpp index bf57451ff..38309345c 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -54,33 +54,9 @@ #include "tokenizer.h" #endif -/// Description for child process. -#define COMPLETE_CHILD_PROCESS_DESC _(L"Child process") - -/// Description for non-child process. -#define COMPLETE_PROCESS_DESC _(L"Process") - -/// Description for long job. -#define COMPLETE_JOB_DESC _(L"Job") - -/// Description for short job. The job command is concatenated. -#define COMPLETE_JOB_DESC_VAL _(L"Job: %ls") - -/// Description for the shells own pid. -#define COMPLETE_SELF_DESC _(L"Shell process") - -/// Description for the shells own pid. -#define COMPLETE_LAST_DESC _(L"Last background job") - -/// String in process expansion denoting ourself. -#define SELF_STR L"self" - -/// String in process expansion denoting last background job. -#define LAST_STR L"last" - /// Characters which make a string unclean if they are the first character of the string. See \c /// expand_is_clean(). -#define UNCLEAN_FIRST L"~%" +#define UNCLEAN_FIRST L"~" /// Unclean characters. See \c expand_is_clean(). #define UNCLEAN L"$*?\\\"'({})" @@ -201,370 +177,6 @@ wcstring expand_escape_variable(const env_var_t &var) { return buff; } -/// Tests if all characters in the wide string are numeric. -static int iswnumeric(const wchar_t *n) { - for (; *n; n++) { - if (*n < L'0' || *n > L'9') { - return 0; - } - } - return 1; -} - -/// See if the process described by \c proc matches the commandline \c cmd. -static bool match_pid(const wcstring &cmd, const wchar_t *proc, size_t *offset) { - // Test for a direct match. If the proc string is empty (e.g. the user tries to complete against - // %), then return an offset pointing at the base command. That ensures that you don't see a - // bunch of dumb paths when completing against all processes. - if (proc[0] != L'\0' && wcsncmp(cmd.c_str(), proc, wcslen(proc)) == 0) { - if (offset) *offset = 0; - return true; - } - - // Get the command to match against. We're only interested in the last path component. - const wcstring base_cmd = wbasename(cmd); - - bool result = string_prefixes_string(proc, base_cmd); - // It's a match. Return the offset within the full command. - if (result && offset) *offset = cmd.size() - base_cmd.size(); - return result; -} - -/// Helper class for iterating over processes. The names returned have been unescaped (e.g. may -/// include spaces). -#ifdef KERN_PROCARGS2 - -// BSD / OS X process completions. - -class process_iterator_t { - std::vector pids; - size_t idx; - - wcstring name_for_pid(pid_t pid); - - public: - process_iterator_t(); - bool next_process(wcstring *str, pid_t *pid); -}; - -wcstring process_iterator_t::name_for_pid(pid_t pid) { - wcstring result; - int mib[4], maxarg = 0, numArgs = 0; - size_t size = 0; - char *args = NULL, *stringPtr = NULL; - - mib[0] = CTL_KERN; - mib[1] = KERN_ARGMAX; - - size = sizeof(maxarg); - if (sysctl(mib, 2, &maxarg, &size, NULL, 0) == -1) { - return result; - } - - args = (char *)malloc(maxarg); - if (!args) return result; - - mib[0] = CTL_KERN; - mib[1] = KERN_PROCARGS2; - mib[2] = pid; - - size = (size_t)maxarg; - if (sysctl(mib, 3, args, &size, NULL, 0) == -1) { - free(args); - return result; - } - - memcpy(&numArgs, args, sizeof(numArgs)); - stringPtr = args + sizeof(numArgs); - result = str2wcstring(stringPtr); - free(args); - return result; -} - -bool process_iterator_t::next_process(wcstring *out_str, pid_t *out_pid) { - wcstring name; - pid_t pid = 0; - bool result = false; - while (idx < pids.size()) { - pid = pids.at(idx++); - name = name_for_pid(pid); - if (!name.empty()) { - result = true; - break; - } - } - if (result) { - *out_str = name; - *out_pid = pid; - } - return result; -} - -process_iterator_t::process_iterator_t() : idx(0) { - int err; - struct kinfo_proc *result; - bool done; - static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; - // Declaring name as const requires us to cast it when passing it to sysctl because the - // prototype doesn't include the const modifier. - size_t length; - - // We start by calling sysctl with result == NULL and length == 0. That will succeed, and set - // length to the appropriate length. We then allocate a buffer of that size and call sysctl - // again with that buffer. If that succeeds, we're done. If that fails with ENOMEM, we have to - // throw away our buffer and loop. Note that the loop causes use to call sysctl with NULL - // again; this is necessary because the ENOMEM failure case sets length to the amount of data - // returned, not the amount of data that could have been returned. - result = NULL; - done = false; - do { - assert(result == NULL); - - // Call sysctl with a NULL buffer. - length = 0; - err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0); - if (err == -1) { - err = errno; - } - - // Allocate an appropriately sized buffer based on the results from the previous call. - if (err == 0) { - result = (struct kinfo_proc *)malloc(length); - if (result == NULL) { - err = ENOMEM; - } - } - - // Call sysctl again with the new buffer. If we get an ENOMEM error, toss away our buffer - // and start again. - if (err == 0) { - err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, result, &length, NULL, 0); - if (err == -1) { - err = errno; - } - if (err == 0) { - done = true; - } else if (err == ENOMEM) { - assert(result != NULL); - free(result); - result = NULL; - err = 0; - } - } - } while (err == 0 && !done); - - // Clean up and establish post conditions. - if (err == 0 && result != NULL) { - for (size_t idx = 0; idx < length / sizeof(struct kinfo_proc); idx++) - pids.push_back(result[idx].kp_proc.p_pid); - } - - if (result) free(result); -} - -#else - -/// /proc style process completions. -class process_iterator_t { - DIR *dir; - - public: - process_iterator_t(); - ~process_iterator_t(); - - bool next_process(wcstring *out_str, pid_t *out_pid); -}; - -process_iterator_t::process_iterator_t() { dir = opendir("/proc"); } - -process_iterator_t::~process_iterator_t() { - if (dir) closedir(dir); -} - -bool process_iterator_t::next_process(wcstring *out_str, pid_t *out_pid) { - wcstring cmd; - pid_t pid = 0; - while (cmd.empty()) { - wcstring name; - if (!dir || !wreaddir(dir, name)) break; - if (!iswnumeric(name.c_str())) continue; - - wcstring path = wcstring(L"/proc/") + name; - struct stat buf; - if (wstat(path, &buf)) continue; - - if (buf.st_uid != getuid()) continue; - - // Remember the pid. - pid = fish_wcstoi(name.c_str()); - if (errno || pid < 0) { - debug(1, _(L"Unexpected failure to convert pid '%ls' to integer\n"), name.c_str()); - } - - // The 'cmdline' file exists, it should contain the commandline. - FILE *cmdfile; - if ((cmdfile = wfopen(path + L"/cmdline", "r"))) { - wcstring full_command_line; - fgetws2(&full_command_line, cmdfile); - - // The command line needs to be escaped. - cmd = tok_first(full_command_line); - } -#ifdef SunOS - else if ((cmdfile = wfopen(path + L"/psinfo", "r"))) { - psinfo_t info; - if (fread(&info, sizeof(info), 1, cmdfile)) { - // The filename is unescaped. - cmd = str2wcstring(info.pr_fname); - } - } -#endif - if (cmdfile) fclose(cmdfile); - } - - bool result = !cmd.empty(); - if (result) { - *out_str = cmd; - *out_pid = pid; - } - return result; -} - -#endif - -/// The following function is invoked on the main thread, because the job list is not thread safe. -/// It should search the job list for something matching the given proc, and then return true to -/// stop the search, false to continue it. -static bool find_job(const wchar_t *proc, expand_flags_t flags, - std::vector *completions) { - ASSERT_IS_MAIN_THREAD(); - - bool found = false; - // If we are not doing tab completion, we first check for the single '%' character, because an - // empty string will pass the numeric check below. But if we are doing tab completion, we want - // all of the job IDs as completion options, not just the last job backgrounded, so we pass this - // first block in favor of the second. - if (wcslen(proc) == 0 && !(flags & EXPAND_FOR_COMPLETIONS)) { - // This is an empty job expansion: '%'. It expands to the last job backgrounded. - job_iterator_t jobs; - while (const job_t *j = jobs.next()) { - if (!j->command_is_empty()) { - append_completion(completions, to_string(j->pgid)); - break; - } - } - // You don't *really* want to flip a coin between killing the last process backgrounded and - // all processes, do you? Let's not try other match methods with the solo '%' syntax. - found = true; - } else if (iswnumeric(proc)) { - // This is a numeric job string, like '%2'. - if (flags & EXPAND_FOR_COMPLETIONS) { - job_iterator_t jobs; - while (const job_t *j = jobs.next()) { - wchar_t jid[16]; - if (j->command_is_empty()) continue; - - swprintf(jid, 16, L"%d", j->job_id); - - if (wcsncmp(proc, jid, wcslen(proc)) == 0) { - wcstring desc_buff = format_string(COMPLETE_JOB_DESC_VAL, j->command_wcstr()); - append_completion(completions, jid + wcslen(proc), desc_buff, 0); - } - } - } else { - int jid = fish_wcstoi(proc); - if (!errno && jid > 0) { - const job_t *j = job_get(jid); - if (j && !j->command_is_empty()) { - append_completion(completions, to_string(j->pgid)); - } - } - } - // Stop here so you can't match a random process name when you're just trying to use job - // control. - found = true; - } - - if (found) { - return found; - } - - job_iterator_t jobs; - while (const job_t *j = jobs.next()) { - if (j->command_is_empty()) continue; - - size_t offset = 0; - if (match_pid(j->command(), proc, &offset)) { - if (flags & EXPAND_FOR_COMPLETIONS) { - append_completion(completions, j->command_wcstr() + offset + wcslen(proc), - COMPLETE_JOB_DESC, 0); - } else { - append_completion(completions, to_string(j->pgid)); - found = 1; - } - } - } - - if (found) { - return found; - } - - jobs.reset(); - while (const job_t *j = jobs.next()) { - if (j->command_is_empty()) continue; - for (const process_ptr_t &p : j->processes) { - if (p->actual_cmd.empty()) continue; - - size_t offset = 0; - if (match_pid(p->actual_cmd, proc, &offset)) { - if (flags & EXPAND_FOR_COMPLETIONS) { - append_completion(completions, wcstring(p->actual_cmd, offset + wcslen(proc)), - COMPLETE_CHILD_PROCESS_DESC, 0); - } else { - append_completion(completions, to_string(p->pid), L"", 0); - found = 1; - } - } - } - } - - return found; -} - -/// Searches for a job with the specified job id, or a job or process which has the string \c proc -/// as a prefix of its commandline. Appends the name of the process as a completion in 'out'. -/// -/// Otherwise, any job matching the specified string is matched, and the job pgid is returned. If no -/// job matches, all child processes are searched. If no child processes match, and fish -/// can understand the contents of the /proc filesystem, all the users processes are searched for -/// matches. -static void find_process(const wchar_t *proc, expand_flags_t flags, - std::vector *out) { - if (!(flags & EXPAND_SKIP_JOBS)) { - bool found = false; - iothread_perform_on_main([&]() { found = find_job(proc, flags, out); }); - if (found) { - return; - } - } - - // Iterate over all processes. - wcstring process_name; - pid_t process_pid; - process_iterator_t iterator; - while (iterator.next_process(&process_name, &process_pid)) { - size_t offset = 0; - if (match_pid(process_name, proc, &offset)) { - if (flags & EXPAND_FOR_COMPLETIONS) { - append_completion(out, process_name.c_str() + offset + wcslen(proc), - COMPLETE_PROCESS_DESC, 0); - } else { - append_completion(out, to_string(process_pid)); - } - } - } -} - /// Parse an array slicing specification Returns 0 on success. If a parse error occurs, returns the /// index of the bad token. Note that 0 can never be a bad index because the string always starts /// with [.