restyle fish modules to match project style

Reduces lint errors from 60 to 60 (-0%). Line count from 5599 to 4925 (-12%).

Another step in resolving issue #2902.
This commit is contained in:
Kurtis Rader 2016-04-30 18:37:19 -07:00
parent aa8840b423
commit 075811e588
5 changed files with 1935 additions and 2609 deletions

View file

@ -1,3 +1,4 @@
// The main loop of the fish program.
/*
Copyright (C) 2005-2008 Axel Liljencrantz
@ -14,85 +15,79 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/** \file fish.c
The main loop of <tt>fish</tt>.
*/
#include "config.h"
#include <assert.h>
#include <getopt.h>
#include <limits.h>
#include <stdint.h>
#include <sys/stat.h>
#include <string>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h> // IWYU pragma: keep
#include <sys/un.h>
#include <pwd.h>
#include <getopt.h>
#include <limits.h>
#include <locale.h>
#include <memory>
#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h> // IWYU pragma: keep
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include <wchar.h>
#include <memory>
#include <string>
#include <vector>
#include "fallback.h" // IWYU pragma: keep
#include "common.h"
#include "reader.h"
#include "builtin.h"
#include "function.h"
#include "wutil.h" // IWYU pragma: keep
#include "common.h"
#include "env.h"
#include "proc.h"
#include "parser.h"
#include "expand.h"
#include "event.h"
#include "history.h"
#include "path.h"
#include "input.h"
#include "io.h"
#include "expand.h"
#include "fallback.h" // IWYU pragma: keep
#include "fish_version.h"
#include "function.h"
#include "history.h"
#include "input.h"
#include "input_common.h"
#include "io.h"
#include "parser.h"
#include "path.h"
#include "proc.h"
#include "reader.h"
#include "wildcard.h"
#include "wutil.h" // IWYU pragma: keep
// PATH_MAX may not exist.
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
/* If we are doing profiling, the filename to output to */
/// If we are doing profiling, the filename to output to.
static const char *s_profiling_output_filename = NULL;
static bool has_suffix(const std::string &path, const char *suffix, bool ignore_case)
{
static bool has_suffix(const std::string &path, const char *suffix, bool ignore_case) {
size_t pathlen = path.size(), suffixlen = strlen(suffix);
return pathlen >= suffixlen && !(ignore_case ? strcasecmp : strcmp)(path.c_str() + pathlen - suffixlen, suffix);
return pathlen >= suffixlen &&
!(ignore_case ? strcasecmp : strcmp)(path.c_str() + pathlen - suffixlen, suffix);
}
/* Modifies the given path by calling realpath. Returns true if realpath succeeded, false otherwise */
static bool get_realpath(std::string &path)
{
/// Modifies the given path by calling realpath. Returns true if realpath succeeded, false
/// otherwise.
static bool get_realpath(std::string &path) {
char buff[PATH_MAX], *ptr;
if ((ptr = realpath(path.c_str(), buff)))
{
if ((ptr = realpath(path.c_str(), buff))) {
path = ptr;
}
return ptr != NULL;
}
/* OS X function for getting the executable path */
// OS X function for getting the executable path.
extern "C" {
int _NSGetExecutablePath(char* buf, uint32_t* bufsize);
int _NSGetExecutablePath(char *buf, uint32_t *bufsize);
}
// Return the path to the current executable. This needs to be realpath'd.
static std::string get_executable_path(const char *argv0)
{
/// Return the path to the current executable. This needs to be realpath'd.
static std::string get_executable_path(const char *argv0) {
char buff[PATH_MAX];
#if __APPLE__
@ -121,35 +116,32 @@ static std::string get_executable_path(const char *argv0)
return std::string(argv0 ? argv0 : "");
}
static struct config_paths_t determine_config_directory_paths(const char *argv0)
{
static struct config_paths_t determine_config_directory_paths(const char *argv0) {
struct config_paths_t paths;
bool done = false;
std::string exec_path = get_executable_path(argv0);
if (get_realpath(exec_path))
{
if (get_realpath(exec_path)) {
#if __APPLE__
/* On OS X, maybe we're an app bundle, and should use the bundle's files. Since we don't link CF, use this lame approach to test it: see if the resolved path ends with /Contents/MacOS/fish, case insensitive since HFS+ usually is.
*/
if (! done)
{
// On OS X, maybe we're an app bundle, and should use the bundle's files. Since we don't
// link CF, use this lame approach to test it: see if the resolved path ends with
// /Contents/MacOS/fish, case insensitive since HFS+ usually is.
if (!done) {
const char *suffix = "/Contents/MacOS/fish";
const size_t suffixlen = strlen(suffix);
if (has_suffix(exec_path, suffix, true))
{
/* Looks like we're a bundle. Cut the string at the / prefixing /Contents... and then the rest */
if (has_suffix(exec_path, suffix, true)) {
// Looks like we're a bundle. Cut the string at the / prefixing /Contents... and
// then the rest.
wcstring wide_resolved_path = str2wcstring(exec_path);
wide_resolved_path.resize(exec_path.size() - suffixlen);
wide_resolved_path.append(L"/Contents/Resources/");
/* Append share, etc, doc */
// Append share, etc, doc.
paths.data = wide_resolved_path + L"share/fish";
paths.sysconf = wide_resolved_path + L"etc/fish";
paths.doc = wide_resolved_path + L"doc/fish";
/* But the bin_dir is the resolved_path, minus fish (aka the MacOS directory) */
// But the bin_dir is the resolved_path, minus fish (aka the MacOS directory).
paths.bin = str2wcstring(exec_path);
paths.bin.resize(paths.bin.size() - strlen("/fish"));
@ -158,18 +150,13 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
}
#endif
if (! done)
{
/* The next check is that we are in a reloctable directory tree like this:
bin/fish
etc/fish
share/fish
Check it!
*/
if (!done) {
// The next check is that we are in a reloctable directory tree like this:
// bin/fish
// etc/fish
// share/fish
const char *suffix = "/bin/fish";
if (has_suffix(exec_path, suffix, false))
{
if (has_suffix(exec_path, suffix, false)) {
wcstring base_path = str2wcstring(exec_path);
base_path.resize(base_path.size() - strlen(suffix));
@ -178,13 +165,12 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
paths.doc = base_path + L"/share/doc/fish";
paths.bin = base_path + L"/bin";
/* Check only that the data and sysconf directories exist. Handle the doc directories separately */
// Check only that the data and sysconf directories exist. Handle the doc
// directories separately.
struct stat buf;
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf))
{
/* The docs dir may not exist; in that case fall back to the compiled in path */
if (0 != wstat(paths.doc, &buf))
{
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf)) {
// The docs dir may not exist; in that case fall back to the compiled in path.
if (0 != wstat(paths.doc, &buf)) {
paths.doc = L"" DOCDIR;
}
done = true;
@ -193,9 +179,8 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
}
}
if (! done)
{
/* Fall back to what got compiled in. */
if (!done) {
// Fall back to what got compiled in.
paths.data = L"" DATADIR "/fish";
paths.sysconf = L"" SYSCONFDIR "/fish";
paths.doc = L"" DOCDIR;
@ -208,21 +193,19 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
}
// Source the file config.fish in the given directory.
static void source_config_in_directory(const wcstring &dir)
{
// If the config.fish file doesn't exist or isn't readable silently return.
// Fish versions up thru 2.2.0 would instead try to source the file with
// stderr redirected to /dev/null to deal with that possibility.
static void source_config_in_directory(const wcstring &dir) {
// If the config.fish file doesn't exist or isn't readable silently return. Fish versions up
// thru 2.2.0 would instead try to source the file with stderr redirected to /dev/null to deal
// with that possibility.
//
// This introduces a race condition since the readability of the file can
// change between this test and the execution of the 'source' command.
// However, that is not a security problem in this context so we ignore it.
// This introduces a race condition since the readability of the file can change between this
// test and the execution of the 'source' command. However, that is not a security problem in
// this context so we ignore it.
const wcstring config_pathname = dir + L"/config.fish";
const wcstring escaped_dir = escape_string(dir, ESCAPE_ALL);
const wcstring escaped_pathname = escaped_dir + L"/config.fish";
if (waccess(config_pathname, R_OK) != 0) {
debug(2, L"not sourcing %ls (not readable or does not exist)",
escaped_pathname.c_str());
debug(2, L"not sourcing %ls (not readable or does not exist)", escaped_pathname.c_str());
return;
}
debug(2, L"sourcing %ls", escaped_pathname.c_str());
@ -234,21 +217,14 @@ static void source_config_in_directory(const wcstring &dir)
parser.set_is_within_fish_initialization(false);
}
static int try_connect_socket(std::string &name)
{
static int try_connect_socket(std::string &name) {
int s, r, ret = -1;
/** Connect to a DGRAM socket rather than the expected STREAM.
This avoids any notification to a remote socket that we have connected,
preventing any surprising behaviour.
If the connection fails with EPROTOTYPE, the connection is probably a
STREAM; if it succeeds or fails any other way, there is no cause for
alarm.
With thanks to Andrew Lutomirski <github.com/amluto>
*/
if ((s = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
{
/// Connect to a DGRAM socket rather than the expected STREAM. This avoids any notification to a
/// remote socket that we have connected, preventing any surprising behaviour. If the connection
/// fails with EPROTOTYPE, the connection is probably a STREAM; if it succeeds or fails any
/// other way, there is no cause for alarm. With thanks to Andrew Lutomirski <github.com/amluto>
if ((s = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
wperror(L"socket");
return -1;
}
@ -261,8 +237,7 @@ static int try_connect_socket(std::string &name)
r = connect(s, (struct sockaddr *)&local, sizeof local);
if (r == -1 && errno == EPROTOTYPE)
{
if (r == -1 && errno == EPROTOTYPE) {
ret = 0;
}
@ -270,24 +245,19 @@ static int try_connect_socket(std::string &name)
return ret;
}
/**
Check for a running fishd from old versions and warn about not being able
to share variables.
https://github.com/fish-shell/fish-shell/issues/1730
*/
static void check_running_fishd()
{
/* There are two paths to check:
$FISHD_SOCKET_DIR/fishd.socket.$USER or /tmp/fishd.socket.$USER
- referred to as the "old socket"
$XDG_RUNTIME_DIR/fishd.socket or /tmp/fish.$USER/fishd.socket
- referred to as the "new socket"
All existing versions of fish attempt to create the old socket, but
failure in newer versions is not treated as critical, so both need
to be checked. */
/// Check for a running fishd from old versions and warn about not being able to share variables.
/// https://github.com/fish-shell/fish-shell/issues/1730
static void check_running_fishd() {
// There are two paths to check:
// $FISHD_SOCKET_DIR/fishd.socket.$USER or /tmp/fishd.socket.$USER
// - referred to as the "old socket"
// $XDG_RUNTIME_DIR/fishd.socket or /tmp/fish.$USER/fishd.socket
// - referred to as the "new socket"
// All existing versions of fish attempt to create the old socket, but
// failure in newer versions is not treated as critical, so both need
// to be checked.
const char *uname = getenv("USER");
if (uname == NULL)
{
if (uname == NULL) {
const struct passwd *pw = getpwuid(getuid());
uname = pw->pw_name;
}
@ -295,12 +265,9 @@ static void check_running_fishd()
const char *dir_old_socket = getenv("FISHD_SOCKET_DIR");
std::string path_old_socket;
if (dir_old_socket == NULL)
{
if (dir_old_socket == NULL) {
path_old_socket = "/tmp/";
}
else
{
} else {
path_old_socket.append(dir_old_socket);
}
@ -309,146 +276,107 @@ static void check_running_fishd()
const char *dir_new_socket = getenv("XDG_RUNTIME_DIR");
std::string path_new_socket;
if (dir_new_socket == NULL)
{
if (dir_new_socket == NULL) {
path_new_socket = "/tmp/fish.";
path_new_socket.append(uname);
path_new_socket.push_back('/');
}
else
{
} else {
path_new_socket.append(dir_new_socket);
}
path_new_socket.append("fishd.socket");
if (try_connect_socket(path_old_socket) == 0 || try_connect_socket(path_new_socket) == 0)
{
debug(1, _(L"Old versions of fish appear to be running. You will not be able to share variable values between old and new fish sessions. For best results, restart all running instances of fish."));
if (try_connect_socket(path_old_socket) == 0 || try_connect_socket(path_new_socket) == 0) {
debug(1, _(L"Old versions of fish appear to be running. You will not be able to share "
L"variable values between old and new fish sessions. For best results, restart "
L"all running instances of fish."));
}
}
/**
Parse init files. exec_path is the path of fish executable as determined by argv[0].
*/
static int read_init(const struct config_paths_t &paths)
{
/// Parse init files. exec_path is the path of fish executable as determined by argv[0].
static int read_init(const struct config_paths_t &paths) {
source_config_in_directory(paths.data);
source_config_in_directory(paths.sysconf);
/* We need to get the configuration directory before we can source the user configuration file. If path_get_config returns false then we have no configuration directory and no custom config to load. */
// We need to get the configuration directory before we can source the user configuration file.
// If path_get_config returns false then we have no configuration directory and no custom config
// to load.
wcstring config_dir;
if (path_get_config(config_dir))
{
if (path_get_config(config_dir)) {
source_config_in_directory(config_dir);
}
return 1;
}
/**
Parse the argument list, return the index of the first non-switch
arguments.
*/
static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
{
/// Parse the argument list, return the index of the first non-switch arguments.
static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds) {
const char *short_opts = "+hilnvc:p:d:";
const struct option long_opts[] =
{
{ "command", required_argument, NULL, 'c' },
{ "debug-level", required_argument, NULL, 'd' },
{ "interactive", no_argument, NULL, 'i' } ,
{ "login", no_argument, NULL, 'l' },
{ "no-execute", no_argument, NULL, 'n' },
{ "profile", required_argument, NULL, 'p' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
const struct option long_opts[] = {{"command", required_argument, NULL, 'c'},
{"debug-level", required_argument, NULL, 'd'},
{"interactive", no_argument, NULL, 'i'},
{"login", no_argument, NULL, 'l'},
{"no-execute", no_argument, NULL, 'n'},
{"profile", required_argument, NULL, 'p'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0}};
int opt;
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1)
{
switch (opt)
{
case 0:
{
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (opt) {
case 0: {
fwprintf(stderr, _(L"getopt_long() unexpectedly returned zero\n"));
exit(127);
}
case 'c':
{
case 'c': {
cmds->push_back(optarg);
break;
}
case 'd':
{
case 'd': {
char *end;
long tmp;
errno = 0;
tmp = strtol(optarg, &end, 10);
if (tmp >= 0 && tmp <=10 && !*end && !errno)
{
if (tmp >= 0 && tmp <= 10 && !*end && !errno) {
debug_level = (int)tmp;
}
else
{
fwprintf(stderr, _(L"Invalid value '%s' for debug level switch"),
optarg);
} else {
fwprintf(stderr, _(L"Invalid value '%s' for debug level switch"), optarg);
exit(1);
}
break;
}
case 'h':
{
case 'h': {
cmds->push_back("__fish_print_help fish");
break;
}
case 'i':
{
case 'i': {
is_interactive_session = 1;
break;
}
case 'l':
{
case 'l': {
is_login = 1;
break;
}
case 'n':
{
case 'n': {
no_exec = 1;
break;
}
case 'p':
{
case 'p': {
s_profiling_output_filename = optarg;
g_profiling_active = true;
break;
}
case 'v':
{
fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME,
get_fish_version());
case 'v': {
fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version());
exit(0);
}
default:
{
default: {
// We assume getopt_long() has already emitted a diagnostic msg.
exit(1);
}
}
}
@ -458,51 +386,43 @@ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds)
// We are an interactive session if we have not been given an explicit
// command or file to execute and stdin is a tty. Note that the -i or
// --interactive options also force interactive mode.
if (cmds->size() == 0 && optind == argc && isatty(STDIN_FILENO))
{
if (cmds->size() == 0 && optind == argc && isatty(STDIN_FILENO)) {
is_interactive_session = 1;
}
return optind;
}
int main(int argc, char **argv)
{
int res=1;
int my_optind=0;
int main(int argc, char **argv) {
int res = 1;
int my_optind = 0;
// We can't do this at compile time due to the use of enum symbols.
assert(EXPAND_SENTINAL >= EXPAND_RESERVED_BASE &&
EXPAND_SENTINAL <= EXPAND_RESERVED_END);
assert(ANY_SENTINAL >= WILDCARD_RESERVED_BASE &&
ANY_SENTINAL <= WILDCARD_RESERVED_END);
assert(R_SENTINAL >= INPUT_COMMON_BASE &&
R_SENTINAL <= INPUT_COMMON_END);
assert(EXPAND_SENTINAL >= EXPAND_RESERVED_BASE && EXPAND_SENTINAL <= EXPAND_RESERVED_END);
assert(ANY_SENTINAL >= WILDCARD_RESERVED_BASE && ANY_SENTINAL <= WILDCARD_RESERVED_END);
assert(R_SENTINAL >= INPUT_COMMON_BASE && R_SENTINAL <= INPUT_COMMON_END);
set_main_thread();
setup_fork_guards();
wsetlocale(LC_ALL, L"");
program_name=L"fish";
program_name = L"fish";
//struct stat tmp;
//stat("----------FISH_HIT_MAIN----------", &tmp);
// struct stat tmp;
// stat("----------FISH_HIT_MAIN----------", &tmp);
std::vector<std::string> cmds;
my_optind = fish_parse_opt(argc, argv, &cmds);
/*
No-exec is prohibited when in interactive mode
*/
if (is_interactive_session && no_exec)
{
// No-exec is prohibited when in interactive mode.
if (is_interactive_session && no_exec) {
debug(1, _(L"Can not use the no-execute mode when running an interactive session"));
no_exec = 0;
}
/* Only save (and therefore restore) the fg process group if we are interactive. See #197, #1002 */
if (is_interactive_session)
{
// Only save (and therefore restore) the fg process group if we are interactive. See issues
// #197 and #1002.
if (is_interactive_session) {
save_term_foreground_process_group();
}
@ -515,63 +435,48 @@ int main(int argc, char **argv)
env_init(&paths);
reader_init();
history_init();
/* For setcolor to support term256 in config.fish (#1022) */
// For set_color to support term256 in config.fish (issue #1022).
update_fish_color_support();
parser_t &parser = parser_t::principal_parser();
if (g_log_forks)
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
const io_chain_t empty_ios;
if (read_init(paths))
{
/* Stomp the exit status of any initialization commands (#635) */
if (read_init(paths)) {
// Stomp the exit status of any initialization commands (issue #635).
proc_set_last_status(STATUS_BUILTIN_OK);
/* Run the commands specified as arguments, if any */
if (! cmds.empty())
{
/* Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. */
if (is_login)
{
// Run the commands specified as arguments, if any.
if (!cmds.empty()) {
// Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds.
if (is_login) {
fish_xdm_login_hack_hack_hack_hack(&cmds, argc - my_optind, argv + my_optind);
}
for (size_t i=0; i < cmds.size(); i++)
{
for (size_t i = 0; i < cmds.size(); i++) {
const wcstring cmd_wcs = str2wcstring(cmds.at(i));
res = parser.eval(cmd_wcs, empty_ios, TOP);
}
reader_exit(0, 0);
}
else if (my_optind == argc)
{
} else if (my_optind == argc) {
// Interactive mode
check_running_fishd();
res = reader_read(STDIN_FILENO, empty_ios);
}
else
{
char *file = *(argv+(my_optind++));
} else {
char *file = *(argv + (my_optind++));
int fd = open(file, O_RDONLY);
if (fd == -1)
{
if (fd == -1) {
perror(file);
}
else
{
// OK to not do this atomically since we cannot have gone multithreaded yet
} else {
// OK to not do this atomically since we cannot have gone multithreaded yet.
set_cloexec(fd);
if (*(argv+my_optind))
{
if (*(argv + my_optind)) {
wcstring sb;
char **ptr;
int i;
for (i=1,ptr = argv+my_optind; *ptr; i++, ptr++)
{
if (i != 1)
sb.append(ARRAY_SEP_STR);
for (i = 1, ptr = argv + my_optind; *ptr; i++, ptr++) {
if (i != 1) sb.append(ARRAY_SEP_STR);
sb.append(str2wcstring(*ptr));
}
@ -584,11 +489,10 @@ int main(int argc, char **argv)
res = reader_read(fd, empty_ios);
if (res)
{
debug(1,
_(L"Error while reading file %ls\n"),
reader_current_filename()?reader_current_filename(): _(L"Standard input"));
if (res) {
debug(1, _(L"Error while reading file %ls\n"), reader_current_filename()
? reader_current_filename()
: _(L"Standard input"));
}
reader_pop_current_filename();
}
@ -602,8 +506,7 @@ int main(int argc, char **argv)
restore_term_mode();
restore_term_foreground_process_group();
if (g_profiling_active)
{
if (g_profiling_active) {
parser.emit_profiling(s_profiling_output_filename);
}
@ -613,9 +516,8 @@ int main(int argc, char **argv)
reader_destroy();
event_destroy();
if (g_log_forks)
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
exit_without_destructors(exit_status);
return EXIT_FAILURE; //above line should always exit
return EXIT_FAILURE; // above line should always exit
}

View file

@ -15,30 +15,30 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <vector>
#include <assert.h>
#include <getopt.h>
#include <locale.h>
#include <stddef.h>
#include <string>
#include <memory>
#include <wctype.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <memory>
#include <string>
#include <vector>
#include "color.h"
#include "highlight.h"
#include "parse_constants.h"
#include "wutil.h" // IWYU pragma: keep
#include "common.h"
#include "output.h"
#include "env.h"
#include "fish_version.h"
#include "highlight.h"
#include "input.h"
#include "output.h"
#include "parse_constants.h"
#include "parse_tree.h"
#include "print_help.h"
#include "fish_version.h"
#include "wutil.h" // IWYU pragma: keep
#define SPACES_PER_INDENT 4
@ -47,16 +47,12 @@ typedef unsigned int indent_t;
static bool dump_parse_tree = false;
// Read the entire contents of a file into the specified string.
static wcstring read_file(FILE *f)
{
static wcstring read_file(FILE *f) {
wcstring result;
while (1)
{
while (1) {
wint_t c = fgetwc(f);
if (c == WEOF)
{
if (ferror(f))
{
if (c == WEOF) {
if (ferror(f)) {
wperror(L"fgetwc");
exit(1);
}
@ -70,64 +66,56 @@ static wcstring read_file(FILE *f)
// Append whitespace as necessary. If we have a newline, append the appropriate indent. Otherwise,
// append a space.
static void append_whitespace(indent_t node_indent, bool do_indent, bool has_new_line,
wcstring *out_result)
{
if (!has_new_line)
{
wcstring *out_result) {
if (!has_new_line) {
out_result->push_back(L' ');
}
else if (do_indent)
{
} else if (do_indent) {
out_result->append(node_indent * SPACES_PER_INDENT, L' ');
}
}
// Dump a parse tree node in a form helpful to someone debugging the behavior of this program.
static void dump_node(indent_t node_indent, const parse_node_t &node, const wcstring &source)
{
static void dump_node(indent_t node_indent, const parse_node_t &node, const wcstring &source) {
int nextc_idx = node.source_start + node.source_length;
wchar_t prevc = node.source_start > 0 ? source[node.source_start - 1] : L' ';
wchar_t nextc = nextc_idx < source.size() ? source[nextc_idx] : L' ';
wchar_t prevc_str[4] = {prevc, 0, 0, 0};
wchar_t nextc_str[4] = {nextc, 0, 0, 0};
if (prevc < L' ')
{
if (prevc < L' ') {
prevc_str[0] = L'\\';
prevc_str[1] = L'c';
prevc_str[2] = prevc + '@';
}
if (nextc < L' ')
{
if (nextc < L' ') {
nextc_str[0] = L'\\';
nextc_str[1] = L'c';
nextc_str[2] = nextc + '@';
}
fwprintf(stderr, L"{off %4d, len %4d, indent %2u, kw %ls, %ls} [%ls|%ls|%ls]\n",
node.source_start, node.source_length, node_indent,
keyword_description(node.keyword), token_type_description(node.type),
prevc_str, source.substr(node.source_start, node.source_length).c_str(), nextc_str);
node.source_start, node.source_length, node_indent, keyword_description(node.keyword),
token_type_description(node.type), prevc_str,
source.substr(node.source_start, node.source_length).c_str(), nextc_str);
}
static void prettify_node_recursive(const wcstring &source, const parse_node_tree_t &tree,
node_offset_t node_idx, indent_t node_indent, parse_token_type_t parent_type,
bool *has_new_line, wcstring *out_result, bool do_indent)
{
node_offset_t node_idx, indent_t node_indent,
parse_token_type_t parent_type, bool *has_new_line,
wcstring *out_result, bool do_indent) {
const parse_node_t &node = tree.at(node_idx);
const parse_token_type_t node_type = node.type;
const parse_token_type_t prev_node_type = node_idx > 0 ?
tree.at(node_idx - 1).type : token_type_invalid;
const parse_token_type_t prev_node_type =
node_idx > 0 ? tree.at(node_idx - 1).type : token_type_invalid;
// Increment the indent if we are either a root job_list, or root case_item_list, or in an if or
// while header (#1665).
const bool is_root_job_list = node_type == symbol_job_list && parent_type != symbol_job_list;
const bool is_root_case_list = node_type == symbol_case_item_list &&
parent_type != symbol_case_item_list;
const bool is_if_while_header = \
(node_type == symbol_job || node_type == symbol_andor_job_list) &&
(parent_type == symbol_if_clause || parent_type == symbol_while_header);
const bool is_root_case_list =
node_type == symbol_case_item_list && parent_type != symbol_case_item_list;
const bool is_if_while_header =
(node_type == symbol_job || node_type == symbol_andor_job_list) &&
(parent_type == symbol_if_clause || parent_type == symbol_while_header);
if (is_root_job_list || is_root_case_list || is_if_while_header)
{
if (is_root_job_list || is_root_case_list || is_if_while_header) {
node_indent += 1;
}
@ -135,35 +123,27 @@ static void prettify_node_recursive(const wcstring &source, const parse_node_tre
if (node.has_comments()) // handle comments, which come before the text
{
const parse_node_tree_t::parse_node_list_t comment_nodes = (
tree.comment_nodes_for_node(node));
for (size_t i = 0; i < comment_nodes.size(); i++)
{
const parse_node_tree_t::parse_node_list_t comment_nodes =
(tree.comment_nodes_for_node(node));
for (size_t i = 0; i < comment_nodes.size(); i++) {
const parse_node_t &comment_node = *comment_nodes.at(i);
append_whitespace(node_indent, do_indent, *has_new_line, out_result);
out_result->append(source, comment_node.source_start, comment_node.source_length);
}
}
if (node_type == parse_token_type_end)
{
if (node_type == parse_token_type_end) {
out_result->push_back(L'\n');
*has_new_line = true;
}
else if ((node_type >= FIRST_PARSE_TOKEN_TYPE && node_type <= LAST_PARSE_TOKEN_TYPE) ||
node_type == parse_special_type_parse_error)
{
if (node.keyword != parse_keyword_none)
{
} else if ((node_type >= FIRST_PARSE_TOKEN_TYPE && node_type <= LAST_PARSE_TOKEN_TYPE) ||
node_type == parse_special_type_parse_error) {
if (node.keyword != parse_keyword_none) {
append_whitespace(node_indent, do_indent, *has_new_line, out_result);
out_result->append(keyword_description(node.keyword));
*has_new_line = false;
}
else if (node.has_source())
{
} else if (node.has_source()) {
// Some type representing a particular token.
if (prev_node_type != parse_token_type_redirection)
{
if (prev_node_type != parse_token_type_redirection) {
append_whitespace(node_indent, do_indent, *has_new_line, out_result);
}
out_result->append(source, node.source_start, node.source_length);
@ -172,51 +152,50 @@ static void prettify_node_recursive(const wcstring &source, const parse_node_tre
}
// Recurse to all our children.
for (node_offset_t idx = 0; idx < node.child_count; idx++)
{
for (node_offset_t idx = 0; idx < node.child_count; idx++) {
// Note we pass our type to our child, which becomes its parent node type.
prettify_node_recursive(source, tree, node.child_start + idx, node_indent, node_type,
has_new_line, out_result, do_indent);
has_new_line, out_result, do_indent);
}
}
/* Entry point for prettification. */
static wcstring prettify(const wcstring &src, bool do_indent)
{
// Entry point for prettification.
static wcstring prettify(const wcstring &src, bool do_indent) {
parse_node_tree_t tree;
if (! parse_tree_from_string(src, parse_flag_continue_after_error | parse_flag_include_comments | parse_flag_leave_unterminated | parse_flag_show_blank_lines, &tree, NULL /* errors */))
{
/* We return the initial string on failure */
if (!parse_tree_from_string(src,
parse_flag_continue_after_error | parse_flag_include_comments |
parse_flag_leave_unterminated | parse_flag_show_blank_lines,
&tree, NULL /* errors */)) {
// We return the initial string on failure.
return src;
}
/* We may have a forest of disconnected trees on a parse failure. We have to handle all nodes that have no parent, and all parse errors. */
// We may have a forest of disconnected trees on a parse failure. We have to handle all nodes
// that have no parent, and all parse errors.
bool has_new_line = true;
wcstring result;
for (node_offset_t i=0; i < tree.size(); i++)
{
for (node_offset_t i = 0; i < tree.size(); i++) {
const parse_node_t &node = tree.at(i);
if (node.parent == NODE_OFFSET_INVALID || node.type == parse_special_type_parse_error)
{
/* A root node */
prettify_node_recursive(src, tree, i, 0, symbol_job_list, &has_new_line, &result, do_indent);
if (node.parent == NODE_OFFSET_INVALID || node.type == parse_special_type_parse_error) {
// A root node.
prettify_node_recursive(src, tree, i, 0, symbol_job_list, &has_new_line, &result,
do_indent);
}
}
return result;
}
// Helper for output_set_writer
static std::string output_receiver;
static int write_to_output_receiver(char c)
{
static int write_to_output_receiver(char c) {
output_receiver.push_back(c);
return 0;
}
/* Given a string and list of colors of the same size, return the string with ANSI escape sequences representing the colors. */
static std::string ansi_colorize(const wcstring &text, const std::vector<highlight_spec_t> &colors)
{
/// Given a string and list of colors of the same size, return the string with ANSI escape sequences
/// representing the colors.
static std::string ansi_colorize(const wcstring &text,
const std::vector<highlight_spec_t> &colors) {
assert(colors.size() == text.size());
assert(output_receiver.empty());
@ -224,11 +203,9 @@ static std::string ansi_colorize(const wcstring &text, const std::vector<highlig
output_set_writer(write_to_output_receiver);
highlight_spec_t last_color = highlight_spec_normal;
for (size_t i=0; i < text.size(); i++)
{
for (size_t i = 0; i < text.size(); i++) {
highlight_spec_t color = colors.at(i);
if (color != last_color)
{
if (color != last_color) {
set_color(highlight_get_color(color, false), rgb_color_t::normal());
last_color = color;
}
@ -241,102 +218,124 @@ static std::string ansi_colorize(const wcstring &text, const std::vector<highlig
return result;
}
/* Given a string and list of colors of the same size, return the string with HTML span elements for the various colors. */
static const wchar_t *html_class_name_for_color(highlight_spec_t spec)
{
#define P(x) L"fish_color_" #x
switch (spec & HIGHLIGHT_SPEC_PRIMARY_MASK)
{
case highlight_spec_normal: return P(normal);
case highlight_spec_error: return P(error);
case highlight_spec_command: return P(command);
case highlight_spec_statement_terminator: return P(statement_terminator);
case highlight_spec_param: return P(param);
case highlight_spec_comment: return P(comment);
case highlight_spec_match: return P(match);
case highlight_spec_search_match: return P(search_match);
case highlight_spec_operator: return P(operator);
case highlight_spec_escape: return P(escape);
case highlight_spec_quote: return P(quote);
case highlight_spec_redirection: return P(redirection);
case highlight_spec_autosuggestion: return P(autosuggestion);
case highlight_spec_selection: return P(selection);
default: return P(other);
/// Given a string and list of colors of the same size, return the string with HTML span elements
/// for the various colors.
static const wchar_t *html_class_name_for_color(highlight_spec_t spec) {
#define P(x) L"fish_color_" #x
switch (spec & HIGHLIGHT_SPEC_PRIMARY_MASK) {
case highlight_spec_normal: {
return P(normal);
}
case highlight_spec_error: {
return P(error);
}
case highlight_spec_command: {
return P(command);
}
case highlight_spec_statement_terminator: {
return P(statement_terminator);
}
case highlight_spec_param: {
return P(param);
}
case highlight_spec_comment: {
return P(comment);
}
case highlight_spec_match: {
return P(match);
}
case highlight_spec_search_match: {
return P(search_match);
}
case highlight_spec_operator: {
return P(operator);
}
case highlight_spec_escape: {
return P(escape);
}
case highlight_spec_quote: {
return P(quote);
}
case highlight_spec_redirection: {
return P(redirection);
}
case highlight_spec_autosuggestion: {
return P(autosuggestion);
}
case highlight_spec_selection: {
return P(selection);
}
default: { return P(other); }
}
}
static std::string html_colorize(const wcstring &text, const std::vector<highlight_spec_t> &colors)
{
if (text.empty())
{
static std::string html_colorize(const wcstring &text,
const std::vector<highlight_spec_t> &colors) {
if (text.empty()) {
return "";
}
assert(colors.size() == text.size());
wcstring html = L"<pre><code>";
highlight_spec_t last_color = highlight_spec_normal;
for (size_t i=0; i < text.size(); i++)
{
/* Handle colors */
for (size_t i = 0; i < text.size(); i++) {
// Handle colors.
highlight_spec_t color = colors.at(i);
if (i > 0 && color != last_color)
{
if (i > 0 && color != last_color) {
html.append(L"</span>");
}
if (i == 0 || color != last_color)
{
if (i == 0 || color != last_color) {
append_format(html, L"<span class=\"%ls\">", html_class_name_for_color(color));
}
last_color = color;
/* Handle text */
// Handle text.
wchar_t wc = text.at(i);
switch (wc)
{
case L'&':
switch (wc) {
case L'&': {
html.append(L"&amp;");
break;
case L'\'':
}
case L'\'': {
html.append(L"&apos;");
break;
case L'"':
}
case L'"': {
html.append(L"&quot;");
break;
case L'<':
}
case L'<': {
html.append(L"&lt;");
break;
case L'>':
}
case L'>': {
html.append(L"&gt;");
break;
default:
}
default: {
html.push_back(wc);
break;
}
}
}
html.append(L"</span></code></pre>");
return wcs2string(html);
}
static std::string no_colorize(const wcstring &text)
{
return wcs2string(text);
}
static std::string no_colorize(const wcstring &text) { return wcs2string(text); }
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
set_main_thread();
setup_fork_guards();
wsetlocale(LC_ALL, L"");
program_name=L"fish_indent";
program_name = L"fish_indent";
env_init();
input_init();
/* Types of output we support */
enum
{
// Types of output we support.
enum {
output_type_plain_text,
output_type_ansi,
output_type_html
@ -344,68 +343,48 @@ int main(int argc, char *argv[])
bool do_indent = true;
const char *short_opts = "+dhvi";
const struct option long_opts[] =
{
{ "dump", no_argument, NULL, 'd' },
{ "no-indent", no_argument, NULL, 'i' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "html", no_argument, NULL, 1 },
{ "ansi", no_argument, NULL, 2 },
{ NULL, 0, NULL, 0 }
};
const struct option long_opts[] = {{"dump", no_argument, NULL, 'd'},
{"no-indent", no_argument, NULL, 'i'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{"html", no_argument, NULL, 1},
{"ansi", no_argument, NULL, 2},
{NULL, 0, NULL, 0}};
int opt;
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1)
{
switch (opt)
{
case 0:
{
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (opt) {
case 0: {
fwprintf(stderr, _(L"getopt_long() unexpectedly returned zero\n"));
exit_without_destructors(127);
}
case 'd':
{
case 'd': {
dump_parse_tree = true;
break;
}
case 'h':
{
case 'h': {
print_help("fish_indent", 1);
exit_without_destructors(0);
}
case 'v':
{
case 'v': {
fwprintf(stderr, _(L"%ls, version %s\n"), program_name, get_fish_version());
exit(0);
assert(0 && "Unreachable code reached");
break;
}
case 'i':
{
case 'i': {
do_indent = false;
break;
}
case 1:
{
case 1: {
output_type = output_type_html;
break;
}
case 2:
{
case 2: {
output_type = output_type_ansi;
break;
}
default:
{
default: {
// We assume getopt_long() has already emitted a diagnostic msg.
exit_without_destructors(1);
}
@ -415,27 +394,27 @@ int main(int argc, char *argv[])
const wcstring src = read_file(stdin);
const wcstring output_wtext = prettify(src, do_indent);
/* Maybe colorize */
// Maybe colorize.
std::vector<highlight_spec_t> colors;
if (output_type != output_type_plain_text)
{
highlight_shell_no_io(output_wtext, colors, output_wtext.size(), NULL, env_vars_snapshot_t::current());
if (output_type != output_type_plain_text) {
highlight_shell_no_io(output_wtext, colors, output_wtext.size(), NULL,
env_vars_snapshot_t::current());
}
std::string colored_output;
switch (output_type)
{
case output_type_plain_text:
switch (output_type) {
case output_type_plain_text: {
colored_output = no_colorize(output_wtext);
break;
case output_type_ansi:
}
case output_type_ansi: {
colored_output = ansi_colorize(output_wtext, colors);
break;
case output_type_html:
}
case output_type_html: {
colored_output = html_colorize(output_wtext, colors);
break;
}
}
fputs(colored_output.c_str(), stdout);

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,12 @@
/** \file fish_version.c Fish version receiver.
This file has a specific purpose of shortening compilation times when
the only change is different `git describe` version.
*/
// Fish version receiver.
//
// This file has a specific purpose of shortening compilation times when
// the only change is different `git describe` version.
#include "fish_version.h"
#ifndef FISH_BUILD_VERSION
#include "fish-build-version.h"
#endif
/**
* Return fish shell version.
*/
const char *get_fish_version() {
return FISH_BUILD_VERSION;
}
/// Return fish shell version.
const char *get_fish_version() { return FISH_BUILD_VERSION; }

View file

@ -1,5 +1,2 @@
/** \file fish_version.h
Prototype for version receiver.
*/
// Prototype for version receiver.
const char *get_fish_version();