From 36389fb0dac5c1aed0fe0f6ccbd676ad364c1a9b Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Tue, 23 Mar 2021 15:04:54 +1100 Subject: [PATCH] Abstract htop main function to allow for a platform binary One review request relating to the PCP platform is to have a clearly separate binary from the regular htop so that we have no confusion as to what is being requested to run, to aid debugging, and a bunch of other good reasons. This commit renames htop.c to CommandLine.c and provides a minimal htop main function for 'native' platforms to use. The PCP version of this will setup libpcp.so and then call the same CommandLine_run function as regular htop. Related to https://github.com/htop-dev/htop/pull/536 --- CommandLine.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++ CommandLine.h | 14 ++ Makefile.am | 14 +- htop.c | 358 +----------------------------------------------- 4 files changed, 399 insertions(+), 359 deletions(-) create mode 100644 CommandLine.c create mode 100644 CommandLine.h diff --git a/CommandLine.c b/CommandLine.c new file mode 100644 index 00000000..bd17c696 --- /dev/null +++ b/CommandLine.c @@ -0,0 +1,372 @@ +/* +htop - CommandLine.c +(C) 2004-2011 Hisham H. Muhammad +(C) 2020-2021 htop dev team +Released under the GNU GPLv2, see the COPYING file +in the source distribution for its full text. +*/ + +#include "config.h" // IWYU pragma: keep + +#include "CommandLine.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Action.h" +#include "CRT.h" +#include "Hashtable.h" +#include "Header.h" +#include "IncSet.h" +#include "MainPanel.h" +#include "MetersPanel.h" +#include "Panel.h" +#include "Platform.h" +#include "Process.h" +#include "ProcessList.h" +#include "ProvideCurses.h" +#include "ScreenManager.h" +#include "Settings.h" +#include "UsersTable.h" +#include "XUtils.h" + + +static void printVersionFlag(const char* name) { + printf("%s " VERSION "\n", name); +} + +static void printHelpFlag(const char* name) { + printf("%s " VERSION "\n" + COPYRIGHT "\n" + "Released under the GNU GPLv2.\n\n" + "-C --no-color Use a monochrome color scheme\n" + "-d --delay=DELAY Set the delay between updates, in tenths of seconds\n" + "-F --filter=FILTER Show only the commands matching the given filter\n" + "-h --help Print this help screen\n" + "-H --highlight-changes[=DELAY] Highlight new and old processes\n" + "-M --no-mouse Disable the mouse\n" + "-p --pid=PID[,PID,PID...] Show only the given PIDs\n" + "-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n" + "-t --tree Show the tree view (can be combined with -s)\n" + "-u --user[=USERNAME] Show only processes for a given user (or $USER)\n" + "-U --no-unicode Do not use unicode but plain ASCII\n" + "-V --version Print version info\n", name); + Platform_longOptionsUsage(name); + printf("\n" + "Long options may be passed with a single dash.\n\n" + "Press F1 inside %s for online help.\n" + "See 'man %s' for more information.\n", name, name); +} + +// ---------------------------------------- + +typedef struct CommandLineSettings_ { + Hashtable* pidMatchList; + char* commFilter; + uid_t userId; + int sortKey; + int delay; + bool useColors; + bool enableMouse; + bool treeView; + bool allowUnicode; + bool highlightChanges; + int highlightDelaySecs; +} CommandLineSettings; + +static CommandLineSettings parseArguments(const char* program, int argc, char** argv) { + + CommandLineSettings flags = { + .pidMatchList = NULL, + .commFilter = NULL, + .userId = (uid_t)-1, // -1 is guaranteed to be an invalid uid_t (see setreuid(2)) + .sortKey = 0, + .delay = -1, + .useColors = true, + .enableMouse = true, + .treeView = false, + .allowUnicode = true, + .highlightChanges = false, + .highlightDelaySecs = -1, + }; + + const struct option long_opts[] = + { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"delay", required_argument, 0, 'd'}, + {"sort-key", required_argument, 0, 's'}, + {"user", optional_argument, 0, 'u'}, + {"no-color", no_argument, 0, 'C'}, + {"no-colour", no_argument, 0, 'C'}, + {"no-mouse", no_argument, 0, 'M'}, + {"no-unicode", no_argument, 0, 'U'}, + {"tree", no_argument, 0, 't'}, + {"pid", required_argument, 0, 'p'}, + {"filter", required_argument, 0, 'F'}, + {"highlight-changes", optional_argument, 0, 'H'}, + PLATFORM_LONG_OPTIONS + {0,0,0,0} + }; + + int opt, opti=0; + /* Parse arguments */ + while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:H::", long_opts, &opti))) { + if (opt == EOF) break; + switch (opt) { + case 'h': + printHelpFlag(program); + exit(0); + case 'V': + printVersionFlag(program); + exit(0); + case 's': + assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */ + if (String_eq(optarg, "help")) { + for (int j = 1; j < LAST_PROCESSFIELD; j++) { + const char* name = Process_fields[j].name; + const char* description = Process_fields[j].description; + if (name) printf("%19s %s\n", name, description); + } + exit(0); + } + flags.sortKey = 0; + for (int j = 1; j < LAST_PROCESSFIELD; j++) { + if (Process_fields[j].name == NULL) + continue; + if (String_eq(optarg, Process_fields[j].name)) { + flags.sortKey = j; + break; + } + } + if (flags.sortKey == 0) { + fprintf(stderr, "Error: invalid column \"%s\".\n", optarg); + exit(1); + } + break; + case 'd': + if (sscanf(optarg, "%16d", &(flags.delay)) == 1) { + if (flags.delay < 1) flags.delay = 1; + if (flags.delay > 100) flags.delay = 100; + } else { + fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg); + exit(1); + } + break; + case 'u': + { + const char *username = optarg; + if (!username && optind < argc && argv[optind] != NULL && + (argv[optind][0] != '\0' && argv[optind][0] != '-')) { + username = argv[optind++]; + } + + if (!username) { + flags.userId = geteuid(); + } else if (!Action_setUserOnly(username, &(flags.userId))) { + fprintf(stderr, "Error: invalid user \"%s\".\n", username); + exit(1); + } + break; + } + case 'C': + flags.useColors = false; + break; + case 'M': + flags.enableMouse = false; + break; + case 'U': + flags.allowUnicode = false; + break; + case 't': + flags.treeView = true; + break; + case 'p': { + assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */ + char* argCopy = xStrdup(optarg); + char* saveptr; + const char* pid = strtok_r(argCopy, ",", &saveptr); + + if (!flags.pidMatchList) { + flags.pidMatchList = Hashtable_new(8, false); + } + + while(pid) { + unsigned int num_pid = atoi(pid); + // deepcode ignore CastIntegerToAddress: we just want a non-NUll pointer here + Hashtable_put(flags.pidMatchList, num_pid, (void *) 1); + pid = strtok_r(NULL, ",", &saveptr); + } + free(argCopy); + + break; + } + case 'F': { + assert(optarg); + free_and_xStrdup(&flags.commFilter, optarg); + break; + } + case 'H': { + const char *delay = optarg; + if (!delay && optind < argc && argv[optind] != NULL && + (argv[optind][0] != '\0' && argv[optind][0] != '-')) { + delay = argv[optind++]; + } + if (delay) { + if (sscanf(delay, "%16d", &(flags.highlightDelaySecs)) == 1) { + if (flags.highlightDelaySecs < 1) + flags.highlightDelaySecs = 1; + } else { + fprintf(stderr, "Error: invalid highlight delay value \"%s\".\n", delay); + exit(1); + } + } + flags.highlightChanges = true; + break; + } + + default: + if (Platform_getLongOption(opt, argc, argv) == false) + exit(1); + break; + } + } + return flags; +} + +static void millisleep(unsigned long millisec) { + struct timespec req = { + .tv_sec = 0, + .tv_nsec = millisec * 1000000L + }; + while(nanosleep(&req,&req)==-1) { + continue; + } +} + +static void setCommFilter(State* state, char** commFilter) { + ProcessList* pl = state->pl; + IncSet* inc = state->mainPanel->inc; + + IncSet_setFilter(inc, *commFilter); + pl->incFilter = IncSet_filter(inc); + + free(*commFilter); + *commFilter = NULL; +} + +int CommandLine_run(const char* name, int argc, char** argv) { + + /* initialize locale */ + const char* lc_ctype; + if ((lc_ctype = getenv("LC_CTYPE")) || (lc_ctype = getenv("LC_ALL"))) + setlocale(LC_CTYPE, lc_ctype); + else + setlocale(LC_CTYPE, ""); + + CommandLineSettings flags = parseArguments(name, argc, argv); + + Platform_init(); + + Process_setupColumnWidths(); + + UsersTable* ut = UsersTable_new(); + ProcessList* pl = ProcessList_new(ut, flags.pidMatchList, flags.userId); + + Settings* settings = Settings_new(pl->cpuCount); + pl->settings = settings; + + Header* header = Header_new(pl, settings, 2); + + Header_populateFromSettings(header); + + if (flags.delay != -1) + settings->delay = flags.delay; + if (!flags.useColors) + settings->colorScheme = COLORSCHEME_MONOCHROME; + if (!flags.enableMouse) + settings->enableMouse = false; + if (flags.treeView) + settings->treeView = true; + if (flags.highlightChanges) + settings->highlightChanges = true; + if (flags.highlightDelaySecs != -1) + settings->highlightDelaySecs = flags.highlightDelaySecs; + if (flags.sortKey > 0) { + // -t -s means "tree sorted by key" + // -s means "list sorted by key" (previous existing behavior) + if (!flags.treeView) { + settings->treeView = false; + } + Settings_setSortKey(settings, flags.sortKey); + } + + CRT_init(settings, flags.allowUnicode); + + MainPanel* panel = MainPanel_new(); + ProcessList_setPanel(pl, (Panel*) panel); + + MainPanel_updateTreeFunctions(panel, settings->treeView); + + State state = { + .settings = settings, + .ut = ut, + .pl = pl, + .mainPanel = panel, + .header = header, + .pauseProcessUpdate = false, + .hideProcessSelection = false, + }; + + MainPanel_setState(panel, &state); + if (flags.commFilter) + setCommFilter(&state, &(flags.commFilter)); + + ScreenManager* scr = ScreenManager_new(header, settings, &state, true); + ScreenManager_add(scr, (Panel*) panel, -1); + + ProcessList_scan(pl, false); + millisleep(75); + ProcessList_scan(pl, false); + + if (settings->allBranchesCollapsed) + ProcessList_collapseAllBranches(pl); + + ScreenManager_run(scr, NULL, NULL); + + attron(CRT_colors[RESET_COLOR]); + mvhline(LINES-1, 0, ' ', COLS); + attroff(CRT_colors[RESET_COLOR]); + refresh(); + + Platform_done(); + + CRT_done(); + + if (settings->changed) { + int r = Settings_write(settings); + if (r < 0) + fprintf(stderr, "Can not save configuration to %s: %s\n", settings->filename, strerror(-r)); + } + + Header_delete(header); + ProcessList_delete(pl); + + ScreenManager_delete(scr); + MetersPanel_cleanup(); + + UsersTable_delete(ut); + Settings_delete(settings); + + if (flags.pidMatchList) + Hashtable_delete(flags.pidMatchList); + + return 0; +} diff --git a/CommandLine.h b/CommandLine.h new file mode 100644 index 00000000..b1f157ea --- /dev/null +++ b/CommandLine.h @@ -0,0 +1,14 @@ +#ifndef HEADER_CommandLine +#define HEADER_CommandLine +/* +htop - CommandLine.h +(C) 2004-2011 Hisham H. Muhammad +(C) 2020-2021 htop dev team +Released under the GNU GPLv2, see the COPYING file +in the source distribution for its full text. +*/ + + +int CommandLine_run(const char* name, int argc, char** argv); + +#endif diff --git a/Makefile.am b/Makefile.am index e894457b..f587eeb0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,3 @@ -bin_PROGRAMS = htop - dist_man_MANS = htop.1 EXTRA_DIST = \ $(dist_man_MANS) \ @@ -32,6 +30,7 @@ myhtopsources = \ ClockMeter.c \ ColorsPanel.c \ ColumnsPanel.c \ + CommandLine.c \ CommandScreen.c \ Compat.c \ CPUMeter.c \ @@ -88,6 +87,7 @@ myhtopheaders = \ ClockMeter.h \ ColorsPanel.h \ ColumnsPanel.h \ + CommandLine.h \ CommandScreen.h \ Compat.h \ DateMeter.h \ @@ -171,6 +171,7 @@ linux_platform_sources = \ if HTOP_LINUX AM_LDFLAGS += -rdynamic +myhtopplatprogram = htop myhtopplatheaders = $(linux_platform_headers) myhtopplatsources = $(linux_platform_sources) endif @@ -201,6 +202,7 @@ freebsd_platform_sources = \ zfs/ZfsCompressedArcMeter.c if HTOP_FREEBSD +myhtopplatprogram = htop myhtopplatheaders = $(freebsd_platform_headers) myhtopplatsources = $(freebsd_platform_sources) endif @@ -224,6 +226,7 @@ dragonflybsd_platform_sources = \ generic/uname.c if HTOP_DRAGONFLYBSD +myhtopplatprogram = htop myhtopplatheaders = $(dragonflybsd_platform_headers) myhtopplatsources = $(dragonflybsd_platform_sources) endif @@ -247,6 +250,7 @@ openbsd_platform_sources = \ openbsd/Platform.c if HTOP_OPENBSD +myhtopplatprogram = htop myhtopplatheaders = $(openbsd_platform_headers) myhtopplatsources = $(openbsd_platform_sources) endif @@ -278,6 +282,7 @@ darwin_platform_sources = \ if HTOP_DARWIN AM_LDFLAGS += -framework IOKit -framework CoreFoundation +myhtopplatprogram = htop myhtopplatheaders = $(darwin_platform_headers) myhtopplatsources = $(darwin_platform_sources) endif @@ -306,6 +311,7 @@ solaris_platform_sources = \ zfs/ZfsCompressedArcMeter.c if HTOP_SOLARIS +myhtopplatprogram = htop myhtopplatheaders = $(solaris_platform_headers) myhtopplatsources = $(solaris_platform_sources) endif @@ -325,13 +331,15 @@ unsupported_platform_sources = \ unsupported/UnsupportedProcessList.c if HTOP_UNSUPPORTED +myhtopplatprogram = htop myhtopplatsources = $(unsupported_platform_sources) myhtopplatheaders = $(unsupported_platform_headers) endif # ---- -htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) +bin_PROGRAMS = $(myhtopplatprogram) +htop_SOURCES = $(myhtopheaders) $(myhtopplatheaders) $(myhtopsources) $(myhtopplatsources) nodist_htop_SOURCES = config.h target: diff --git a/htop.c b/htop.c index 656aa086..426b59af 100644 --- a/htop.c +++ b/htop.c @@ -8,363 +8,9 @@ in the source distribution for its full text. #include "config.h" // IWYU pragma: keep -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "CommandLine.h" -#include "Action.h" -#include "CRT.h" -#include "Hashtable.h" -#include "Header.h" -#include "IncSet.h" -#include "MainPanel.h" -#include "MetersPanel.h" -#include "Panel.h" -#include "Platform.h" -#include "Process.h" -#include "ProcessList.h" -#include "ProvideCurses.h" -#include "ScreenManager.h" -#include "Settings.h" -#include "UsersTable.h" -#include "XUtils.h" - - -static void printVersionFlag(const char* name) { - printf("%s " VERSION "\n", name); -} - -static void printHelpFlag(const char* name) { - printf("%s " VERSION "\n" - COPYRIGHT "\n" - "Released under the GNU GPLv2.\n\n" - "-C --no-color Use a monochrome color scheme\n" - "-d --delay=DELAY Set the delay between updates, in tenths of seconds\n" - "-F --filter=FILTER Show only the commands matching the given filter\n" - "-h --help Print this help screen\n" - "-H --highlight-changes[=DELAY] Highlight new and old processes\n" - "-M --no-mouse Disable the mouse\n" - "-p --pid=PID[,PID,PID...] Show only the given PIDs\n" - "-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n" - "-t --tree Show the tree view (can be combined with -s)\n" - "-u --user[=USERNAME] Show only processes for a given user (or $USER)\n" - "-U --no-unicode Do not use unicode but plain ASCII\n" - "-V --version Print version info\n", name); - Platform_longOptionsUsage(name); - printf("\n" - "Long options may be passed with a single dash.\n\n" - "Press F1 inside %s for online help.\n" - "See 'man %s' for more information.\n", name, name); -} - -// ---------------------------------------- - -typedef struct CommandLineSettings_ { - Hashtable* pidMatchList; - char* commFilter; - uid_t userId; - int sortKey; - int delay; - bool useColors; - bool enableMouse; - bool treeView; - bool allowUnicode; - bool highlightChanges; - int highlightDelaySecs; -} CommandLineSettings; - -static CommandLineSettings parseArguments(const char* program, int argc, char** argv) { - - CommandLineSettings flags = { - .pidMatchList = NULL, - .commFilter = NULL, - .userId = (uid_t)-1, // -1 is guaranteed to be an invalid uid_t (see setreuid(2)) - .sortKey = 0, - .delay = -1, - .useColors = true, - .enableMouse = true, - .treeView = false, - .allowUnicode = true, - .highlightChanges = false, - .highlightDelaySecs = -1, - }; - - const struct option long_opts[] = - { - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"delay", required_argument, 0, 'd'}, - {"sort-key", required_argument, 0, 's'}, - {"user", optional_argument, 0, 'u'}, - {"no-color", no_argument, 0, 'C'}, - {"no-colour", no_argument, 0, 'C'}, - {"no-mouse", no_argument, 0, 'M'}, - {"no-unicode", no_argument, 0, 'U'}, - {"tree", no_argument, 0, 't'}, - {"pid", required_argument, 0, 'p'}, - {"filter", required_argument, 0, 'F'}, - {"highlight-changes", optional_argument, 0, 'H'}, - PLATFORM_LONG_OPTIONS - {0,0,0,0} - }; - - int opt, opti=0; - /* Parse arguments */ - while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:H::", long_opts, &opti))) { - if (opt == EOF) break; - switch (opt) { - case 'h': - printHelpFlag(program); - exit(0); - case 'V': - printVersionFlag(program); - exit(0); - case 's': - assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */ - if (String_eq(optarg, "help")) { - for (int j = 1; j < LAST_PROCESSFIELD; j++) { - const char* name = Process_fields[j].name; - const char* description = Process_fields[j].description; - if (name) printf("%19s %s\n", name, description); - } - exit(0); - } - flags.sortKey = 0; - for (int j = 1; j < LAST_PROCESSFIELD; j++) { - if (Process_fields[j].name == NULL) - continue; - if (String_eq(optarg, Process_fields[j].name)) { - flags.sortKey = j; - break; - } - } - if (flags.sortKey == 0) { - fprintf(stderr, "Error: invalid column \"%s\".\n", optarg); - exit(1); - } - break; - case 'd': - if (sscanf(optarg, "%16d", &(flags.delay)) == 1) { - if (flags.delay < 1) flags.delay = 1; - if (flags.delay > 100) flags.delay = 100; - } else { - fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg); - exit(1); - } - break; - case 'u': - { - const char *username = optarg; - if (!username && optind < argc && argv[optind] != NULL && - (argv[optind][0] != '\0' && argv[optind][0] != '-')) { - username = argv[optind++]; - } - - if (!username) { - flags.userId = geteuid(); - } else if (!Action_setUserOnly(username, &(flags.userId))) { - fprintf(stderr, "Error: invalid user \"%s\".\n", username); - exit(1); - } - break; - } - case 'C': - flags.useColors = false; - break; - case 'M': - flags.enableMouse = false; - break; - case 'U': - flags.allowUnicode = false; - break; - case 't': - flags.treeView = true; - break; - case 'p': { - assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */ - char* argCopy = xStrdup(optarg); - char* saveptr; - const char* pid = strtok_r(argCopy, ",", &saveptr); - - if (!flags.pidMatchList) { - flags.pidMatchList = Hashtable_new(8, false); - } - - while(pid) { - unsigned int num_pid = atoi(pid); - // deepcode ignore CastIntegerToAddress: we just want a non-NUll pointer here - Hashtable_put(flags.pidMatchList, num_pid, (void *) 1); - pid = strtok_r(NULL, ",", &saveptr); - } - free(argCopy); - - break; - } - case 'F': { - assert(optarg); - free_and_xStrdup(&flags.commFilter, optarg); - break; - } - case 'H': { - const char *delay = optarg; - if (!delay && optind < argc && argv[optind] != NULL && - (argv[optind][0] != '\0' && argv[optind][0] != '-')) { - delay = argv[optind++]; - } - if (delay) { - if (sscanf(delay, "%16d", &(flags.highlightDelaySecs)) == 1) { - if (flags.highlightDelaySecs < 1) - flags.highlightDelaySecs = 1; - } else { - fprintf(stderr, "Error: invalid highlight delay value \"%s\".\n", delay); - exit(1); - } - } - flags.highlightChanges = true; - break; - } - - default: - if (Platform_getLongOption(opt, argc, argv) == false) - exit(1); - break; - } - } - return flags; -} - -static void millisleep(unsigned long millisec) { - struct timespec req = { - .tv_sec = 0, - .tv_nsec = millisec * 1000000L - }; - while(nanosleep(&req,&req)==-1) { - continue; - } -} - -static void setCommFilter(State* state, char** commFilter) { - ProcessList* pl = state->pl; - IncSet* inc = state->mainPanel->inc; - - IncSet_setFilter(inc, *commFilter); - pl->incFilter = IncSet_filter(inc); - - free(*commFilter); - *commFilter = NULL; -} int main(int argc, char** argv) { - - /* initialize locale */ - const char* lc_ctype; - if ((lc_ctype = getenv("LC_CTYPE")) || (lc_ctype = getenv("LC_ALL"))) - setlocale(LC_CTYPE, lc_ctype); - else - setlocale(LC_CTYPE, ""); - - CommandLineSettings flags = parseArguments(PACKAGE, argc, argv); - - Platform_init(); - - Process_setupColumnWidths(); - - UsersTable* ut = UsersTable_new(); - ProcessList* pl = ProcessList_new(ut, flags.pidMatchList, flags.userId); - - Settings* settings = Settings_new(pl->cpuCount); - pl->settings = settings; - - Header* header = Header_new(pl, settings, 2); - - Header_populateFromSettings(header); - - if (flags.delay != -1) - settings->delay = flags.delay; - if (!flags.useColors) - settings->colorScheme = COLORSCHEME_MONOCHROME; - if (!flags.enableMouse) - settings->enableMouse = false; - if (flags.treeView) - settings->treeView = true; - if (flags.highlightChanges) - settings->highlightChanges = true; - if (flags.highlightDelaySecs != -1) - settings->highlightDelaySecs = flags.highlightDelaySecs; - if (flags.sortKey > 0) { - // -t -s means "tree sorted by key" - // -s means "list sorted by key" (previous existing behavior) - if (!flags.treeView) { - settings->treeView = false; - } - Settings_setSortKey(settings, flags.sortKey); - } - - CRT_init(settings, flags.allowUnicode); - - MainPanel* panel = MainPanel_new(); - ProcessList_setPanel(pl, (Panel*) panel); - - MainPanel_updateTreeFunctions(panel, settings->treeView); - - State state = { - .settings = settings, - .ut = ut, - .pl = pl, - .mainPanel = panel, - .header = header, - .pauseProcessUpdate = false, - .hideProcessSelection = false, - }; - - MainPanel_setState(panel, &state); - if (flags.commFilter) - setCommFilter(&state, &(flags.commFilter)); - - ScreenManager* scr = ScreenManager_new(header, settings, &state, true); - ScreenManager_add(scr, (Panel*) panel, -1); - - ProcessList_scan(pl, false); - millisleep(75); - ProcessList_scan(pl, false); - - if (settings->allBranchesCollapsed) - ProcessList_collapseAllBranches(pl); - - ScreenManager_run(scr, NULL, NULL); - - attron(CRT_colors[RESET_COLOR]); - mvhline(LINES-1, 0, ' ', COLS); - attroff(CRT_colors[RESET_COLOR]); - refresh(); - - Platform_done(); - - CRT_done(); - - if (settings->changed) { - int r = Settings_write(settings); - if (r < 0) - fprintf(stderr, "Can not save configuration to %s: %s\n", settings->filename, strerror(-r)); - } - - Header_delete(header); - ProcessList_delete(pl); - - ScreenManager_delete(scr); - MetersPanel_cleanup(); - - UsersTable_delete(ut); - Settings_delete(settings); - - if (flags.pidMatchList) - Hashtable_delete(flags.pidMatchList); - - return 0; + return CommandLine_run(PACKAGE, argc, argv); }